diff --git a/.eslintrc.json b/.eslintrc.json index 76ce0a75b88690..1851d68bd2bb89 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -41,7 +41,8 @@ "CodeMirror": "readonly", "esprima": "readonly", "jsonlint": "readonly", - "VideoFrame": "readonly" + "VideoFrame": "readonly", + "VideoDecoder": "readonly" }, "rules": { "no-throw-literal": [ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef55565e7a67c1..a4c7ddce188e9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,7 +89,7 @@ jobs: - name: === E2E testing === run: npm run test-e2e - name: Upload output screenshots - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 if: always() with: name: Output screenshots-${{ matrix.os }}-${{ matrix.CI }} diff --git a/.github/workflows/codeql-code-scanning.yml b/.github/workflows/codeql-code-scanning.yml index 2bd9b9be355c9c..13923c8d4fc962 100644 --- a/.github/workflows/codeql-code-scanning.yml +++ b/.github/workflows/codeql-code-scanning.yml @@ -30,16 +30,16 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3 + uses: github/codeql-action/init@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3 with: languages: ${{ matrix.language }} config-file: ./.github/codeql-config.yml queries: security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3 + uses: github/codeql-action/autobuild@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3 + uses: github/codeql-action/analyze@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/read-size.yml b/.github/workflows/read-size.yml index 1280688714ebcd..b527fc134ffd70 100644 --- a/.github/workflows/read-size.yml +++ b/.github/workflows/read-size.yml @@ -61,7 +61,7 @@ jobs: # write the output in a json file to upload it as artifact node -pe "JSON.stringify({ filesize: $WEBGL_FILESIZE, gzip: $WEBGL_FILESIZE_GZIP, treeshaken: $WEBGL_TREESHAKEN, treeshakenGzip: $WEBGL_TREESHAKEN_GZIP, filesize2: $WEBGPU_FILESIZE, gzip2: $WEBGPU_FILESIZE_GZIP, treeshaken2: $WEBGPU_TREESHAKEN, treeshakenGzip2: $WEBGPU_TREESHAKEN_GZIP, filesize3: $WEBGPU_NODES_FILESIZE, gzip3: $WEBGPU_NODES_FILESIZE_GZIP, treeshaken3: $WEBGPU_NODES_TREESHAKEN, treeshakenGzip3: $WEBGPU_NODES_TREESHAKEN_GZIP, pr: $PR })" > sizes.json - name: Upload artifact - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 with: name: sizes path: sizes.json diff --git a/LICENSE b/LICENSE index d33709fbf00f10..cf781430404b0a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright © 2010-2024 three.js authors +Copyright © 2010-2025 three.js authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 0027148a242f94..8fc47bf453fb99 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ #### JavaScript 3D library -The aim of the project is to create an easy-to-use, lightweight, cross-browser, general-purpose 3D library. The current builds only include a WebGL renderer but WebGPU (experimental), SVG and CSS3D renderers are also available as addons. +The aim of the project is to create an easy-to-use, lightweight, cross-browser, general-purpose 3D library. The current builds only include WebGL and WebGPU renderers but SVG and CSS3D renderers are also available as addons. [Examples](https://threejs.org/examples/) — [Docs](https://threejs.org/docs/) — diff --git a/build/three.cjs b/build/three.cjs index 014846da7b4adf..9bbf9599e84b2e 100644 --- a/build/three.cjs +++ b/build/three.cjs @@ -1,11 +1,11 @@ /** * @license - * Copyright 2010-2024 Three.js Authors + * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */ 'use strict'; -const REVISION = '172dev'; +const REVISION = '173dev'; 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 }; @@ -3276,9 +3276,9 @@ 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. + // Users can still set in Data3DTexture directly. // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); + // const texture = new THREE.Data3DTexture( data, width, height, depth ); // texture.anisotropy = 16; // // See #14839 @@ -10002,6 +10002,8 @@ const DataUtils = { const _vector$9 = /*@__PURE__*/ new Vector3(); const _vector2$1 = /*@__PURE__*/ new Vector2(); +let _id$3 = 0; + class BufferAttribute { constructor( array, itemSize, normalized = false ) { @@ -10014,6 +10016,8 @@ class BufferAttribute { this.isBufferAttribute = true; + Object.defineProperty( this, 'id', { value: _id$3 ++ } ); + this.name = ''; this.array = array; @@ -12750,8 +12754,8 @@ class PerspectiveCamera extends Camera { * Sets minTarget and maxTarget to the coordinates of the lower-left and upper-right corners of the view rectangle. * * @param {number} distance - * @param {number} minTarget - * @param {number} maxTarget + * @param {Vector2} minTarget + * @param {Vector2} maxTarget */ getViewBounds( distance, minTarget, maxTarget ) { @@ -16214,7 +16218,7 @@ class BatchedMesh extends Mesh { const instanceInfo = this._instanceInfo; for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) { - if ( instanceInfo[ i ].geometryIndex === geometryId ) { + if ( instanceInfo[ i ].active && instanceInfo[ i ].geometryIndex === geometryId ) { this.deleteInstance( i ); @@ -17523,6 +17527,36 @@ class VideoTexture extends Texture { } +class VideoFrameTexture extends VideoTexture { + + constructor( mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + super( {}, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + } + + update() { + + // overwrites `VideoTexture.update()` with an empty method since + // this type of texture is updated via `setFrame()`. + + } + + clone() { + + return new this.constructor().copy( this ); // restoring Texture.clone() + + } + + setFrame( frame ) { + + this.image = frame; + this.needsUpdate = true; + + } + +} + class FramebufferTexture extends Texture { constructor( width, height ) { @@ -21412,7 +21446,7 @@ function pointInTriangle( ax, ay, bx, by, cx, cy, px, 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 + return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // doesn'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( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case @@ -34381,6 +34415,42 @@ class AnimationMixer extends EventDispatcher { } +class RenderTarget3D extends RenderTarget { + + constructor( width = 1, height = 1, depth = 1, options = {} ) { + + super( width, height, options ); + + this.isRenderTarget3D = true; + + this.depth = depth; + + this.texture = new Data3DTexture( null, width, height, depth ); + + this.texture.isRenderTargetTexture = true; + + } + +} + +class RenderTargetArray extends RenderTarget { + + constructor( width = 1, height = 1, depth = 1, options = {} ) { + + super( width, height, options ); + + this.isRenderTargetArray = true; + + this.depth = depth; + + this.texture = new DataArrayTexture( null, width, height, depth ); + + this.texture.isRenderTargetTexture = true; + + } + +} + class Uniform { constructor( value ) { @@ -36020,17 +36090,19 @@ class CameraHelper extends LineSegments { _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); - // center / target + // Adjust z values based on coordinate system + const nearZ = this.camera.coordinateSystem === WebGLCoordinateSystem ? - 1 : 0; - setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); + // center / target + setPoint( 'c', pointMap, geometry, _camera, 0, 0, nearZ ); setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); // near - setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); - setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); - setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); - setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); + setPoint( 'n1', pointMap, geometry, _camera, - w, - h, nearZ ); + setPoint( 'n2', pointMap, geometry, _camera, w, - h, nearZ ); + setPoint( 'n3', pointMap, geometry, _camera, - w, h, nearZ ); + setPoint( 'n4', pointMap, geometry, _camera, w, h, nearZ ); // far @@ -36041,9 +36113,9 @@ class CameraHelper extends LineSegments { // up - setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); + setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, nearZ ); + setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, nearZ ); + setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, nearZ ); // cross @@ -36052,10 +36124,10 @@ class CameraHelper extends LineSegments { setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); - setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); - setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); - setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); - setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); + setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, nearZ ); + setPoint( 'cn2', pointMap, geometry, _camera, w, 0, nearZ ); + setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, nearZ ); + setPoint( 'cn4', pointMap, geometry, _camera, 0, h, nearZ ); geometry.getAttribute( 'position' ).needsUpdate = true; @@ -37497,7 +37569,7 @@ var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( var 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"; -var 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"; +var 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\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\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#else\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#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"; var 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"; @@ -38539,6 +38611,8 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, boxMesh.geometry.dispose(); boxMesh.material.dispose(); + boxMesh = undefined; + } if ( planeMesh !== undefined ) { @@ -38546,6 +38620,8 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, planeMesh.geometry.dispose(); planeMesh.material.dispose(); + planeMesh = undefined; + } } @@ -50189,7 +50265,11 @@ class WebXRManager extends EventDispatcher { currentPixelRatio = renderer.getPixelRatio(); renderer.getSize( currentSize ); - if ( session.renderState.layers === undefined ) { + // Check that the browser implements the necessary APIs to use an + // XRProjectionLayer rather than an XRWebGLLayer + const useLayers = typeof XRWebGLBinding !== 'undefined' && 'createProjectionLayer' in XRWebGLBinding.prototype; + + if ( ! useLayers ) { const layerInit = { antialias: attributes.antialias, @@ -50696,8 +50776,11 @@ class WebXRManager extends EventDispatcher { // const enabledFeatures = session.enabledFeatures; + const gpuDepthSensingEnabled = enabledFeatures && + enabledFeatures.includes( 'depth-sensing' ) && + session.depthUsage == 'gpu-optimized'; - if ( enabledFeatures && enabledFeatures.includes( 'depth-sensing' ) ) { + if ( gpuDepthSensingEnabled && glBinding ) { const depthData = glBinding.getDepthInformation( views[ 0 ] ); @@ -52946,7 +53029,7 @@ class WebGLRenderer { // - if ( _currentRenderTarget !== null ) { + if ( _currentRenderTarget !== null && _currentActiveMipmapLevel === 0 ) { // resolve multisample renderbuffers to a single-sample texture if necessary @@ -53941,6 +54024,7 @@ class WebGLRenderer { }; + const _scratchFrameBuffer = _gl.createFramebuffer(); this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { _currentRenderTarget = renderTarget; @@ -54049,6 +54133,14 @@ class WebGLRenderer { } + // Use a scratch frame buffer if rendering to a mip level to avoid depth buffers + // being bound that are different sizes. + if ( activeMipmapLevel !== 0 ) { + + framebuffer = _scratchFrameBuffer; + + } + const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); if ( framebufferBound && useDefaultFramebuffer ) { @@ -54069,8 +54161,15 @@ class WebGLRenderer { } else if ( isRenderTarget3D ) { const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); + const layer = activeCubeFace; + _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel, layer ); + + } else if ( renderTarget !== null && activeMipmapLevel !== 0 ) { + + // Only bind the frame buffer if we are using a scratch frame buffer to render to a mipmap. + // If we rebind the texture when using a multi sample buffer then an error about inconsistent samples will be thrown. + const textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, textureProperties.__webglTexture, activeMipmapLevel ); } @@ -54929,6 +55028,8 @@ exports.RedFormat = RedFormat; exports.RedIntegerFormat = RedIntegerFormat; exports.ReinhardToneMapping = ReinhardToneMapping; exports.RenderTarget = RenderTarget; +exports.RenderTarget3D = RenderTarget3D; +exports.RenderTargetArray = RenderTargetArray; exports.RepeatWrapping = RepeatWrapping; exports.ReplaceStencilOp = ReplaceStencilOp; exports.ReverseSubtractEquation = ReverseSubtractEquation; @@ -55007,6 +55108,7 @@ exports.Vector2 = Vector2; exports.Vector3 = Vector3; exports.Vector4 = Vector4; exports.VectorKeyframeTrack = VectorKeyframeTrack; +exports.VideoFrameTexture = VideoFrameTexture; exports.VideoTexture = VideoTexture; exports.WebGL3DRenderTarget = WebGL3DRenderTarget; exports.WebGLArrayRenderTarget = WebGLArrayRenderTarget; diff --git a/build/three.core.js b/build/three.core.js index 237da1bce0e460..d53f8f7e86bca9 100644 --- a/build/three.core.js +++ b/build/three.core.js @@ -1,9 +1,9 @@ /** * @license - * Copyright 2010-2024 Three.js Authors + * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */ -const REVISION = '172dev'; +const REVISION = '173dev'; 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 }; @@ -3274,9 +3274,9 @@ 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. + // Users can still set in Data3DTexture directly. // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); + // const texture = new THREE.Data3DTexture( data, width, height, depth ); // texture.anisotropy = 16; // // See #14839 @@ -10000,6 +10000,8 @@ const DataUtils = { const _vector$9 = /*@__PURE__*/ new Vector3(); const _vector2$1 = /*@__PURE__*/ new Vector2(); +let _id$2 = 0; + class BufferAttribute { constructor( array, itemSize, normalized = false ) { @@ -10012,6 +10014,8 @@ class BufferAttribute { this.isBufferAttribute = true; + Object.defineProperty( this, 'id', { value: _id$2 ++ } ); + this.name = ''; this.array = array; @@ -12748,8 +12752,8 @@ class PerspectiveCamera extends Camera { * Sets minTarget and maxTarget to the coordinates of the lower-left and upper-right corners of the view rectangle. * * @param {number} distance - * @param {number} minTarget - * @param {number} maxTarget + * @param {Vector2} minTarget + * @param {Vector2} maxTarget */ getViewBounds( distance, minTarget, maxTarget ) { @@ -16212,7 +16216,7 @@ class BatchedMesh extends Mesh { const instanceInfo = this._instanceInfo; for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) { - if ( instanceInfo[ i ].geometryIndex === geometryId ) { + if ( instanceInfo[ i ].active && instanceInfo[ i ].geometryIndex === geometryId ) { this.deleteInstance( i ); @@ -17521,6 +17525,36 @@ class VideoTexture extends Texture { } +class VideoFrameTexture extends VideoTexture { + + constructor( mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + super( {}, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + } + + update() { + + // overwrites `VideoTexture.update()` with an empty method since + // this type of texture is updated via `setFrame()`. + + } + + clone() { + + return new this.constructor().copy( this ); // restoring Texture.clone() + + } + + setFrame( frame ) { + + this.image = frame; + this.needsUpdate = true; + + } + +} + class FramebufferTexture extends Texture { constructor( width, height ) { @@ -21410,7 +21444,7 @@ function pointInTriangle( ax, ay, bx, by, cx, cy, px, 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 + return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // doesn'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( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case @@ -34379,6 +34413,42 @@ class AnimationMixer extends EventDispatcher { } +class RenderTarget3D extends RenderTarget { + + constructor( width = 1, height = 1, depth = 1, options = {} ) { + + super( width, height, options ); + + this.isRenderTarget3D = true; + + this.depth = depth; + + this.texture = new Data3DTexture( null, width, height, depth ); + + this.texture.isRenderTargetTexture = true; + + } + +} + +class RenderTargetArray extends RenderTarget { + + constructor( width = 1, height = 1, depth = 1, options = {} ) { + + super( width, height, options ); + + this.isRenderTargetArray = true; + + this.depth = depth; + + this.texture = new DataArrayTexture( null, width, height, depth ); + + this.texture.isRenderTargetTexture = true; + + } + +} + class Uniform { constructor( value ) { @@ -36018,17 +36088,19 @@ class CameraHelper extends LineSegments { _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); - // center / target + // Adjust z values based on coordinate system + const nearZ = this.camera.coordinateSystem === WebGLCoordinateSystem ? - 1 : 0; - setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); + // center / target + setPoint( 'c', pointMap, geometry, _camera, 0, 0, nearZ ); setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); // near - setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); - setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); - setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); - setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); + setPoint( 'n1', pointMap, geometry, _camera, - w, - h, nearZ ); + setPoint( 'n2', pointMap, geometry, _camera, w, - h, nearZ ); + setPoint( 'n3', pointMap, geometry, _camera, - w, h, nearZ ); + setPoint( 'n4', pointMap, geometry, _camera, w, h, nearZ ); // far @@ -36039,9 +36111,9 @@ class CameraHelper extends LineSegments { // up - setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); + setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, nearZ ); + setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, nearZ ); + setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, nearZ ); // cross @@ -36050,10 +36122,10 @@ class CameraHelper extends LineSegments { setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); - setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); - setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); - setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); - setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); + setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, nearZ ); + setPoint( 'cn2', pointMap, geometry, _camera, w, 0, nearZ ); + setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, nearZ ); + setPoint( 'cn4', pointMap, geometry, _camera, 0, h, nearZ ); geometry.getAttribute( 'position' ).needsUpdate = true; @@ -37008,4 +37080,4 @@ if ( typeof window !== 'undefined' ) { } -export { ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BackSide, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometry, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, Color, ColorKeyframeTrack, ColorManagement, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, ConstantAlphaFactor, ConstantColorFactor, Controls, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, FloatType, Fog, FogExp2, FramebufferTexture, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, MOUSE, Material, MaterialLoader, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, PCFShadowMap, PCFSoftShadowMap, Path, PerspectiveCamera, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RAD2DEG, 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, 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, RawShaderMaterial, Ray, Raycaster, RectAreaLight, RedFormat, RedIntegerFormat, ReinhardToneMapping, RenderTarget, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RingGeometry, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TOUCH, TangentSpaceNormalMap, TetrahedronGeometry, Texture, TextureLoader, TextureUtils, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, UniformsUtils, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, VectorKeyframeTrack, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLRenderTarget, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, arrayNeedsUint32, cloneUniforms, createCanvasElement, createElementNS, getByteLength, getUnlitUniformColorSpace, mergeUniforms, probeAsync, toNormalizedProjectionMatrix, toReversedProjectionMatrix, warnOnce }; +export { ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BackSide, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometry, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, Color, ColorKeyframeTrack, ColorManagement, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, ConstantAlphaFactor, ConstantColorFactor, Controls, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, FloatType, Fog, FogExp2, FramebufferTexture, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, MOUSE, Material, MaterialLoader, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, PCFShadowMap, PCFSoftShadowMap, Path, PerspectiveCamera, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RAD2DEG, 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, 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, RawShaderMaterial, Ray, Raycaster, RectAreaLight, RedFormat, RedIntegerFormat, ReinhardToneMapping, RenderTarget, RenderTarget3D, RenderTargetArray, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RingGeometry, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TOUCH, TangentSpaceNormalMap, TetrahedronGeometry, Texture, TextureLoader, TextureUtils, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, UniformsUtils, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLRenderTarget, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, arrayNeedsUint32, cloneUniforms, createCanvasElement, createElementNS, getByteLength, getUnlitUniformColorSpace, mergeUniforms, probeAsync, toNormalizedProjectionMatrix, toReversedProjectionMatrix, warnOnce }; diff --git a/build/three.core.min.js b/build/three.core.min.js index 5aa9aa1c5f49e9..e4fd213bd3898e 100644 --- a/build/three.core.min.js +++ b/build/three.core.min.js @@ -1,6 +1,6 @@ /** * @license - * Copyright 2010-2024 Three.js Authors + * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */ -const t="172dev",e={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,c=3,u=0,d=1,p=2,m=0,y=1,f=2,g=3,x=4,b=5,v=100,w=101,M=102,S=103,_=104,A=200,T=201,z=202,C=203,I=204,B=205,k=206,E=207,P=208,R=209,O=210,F=211,N=212,L=213,V=214,W=0,j=1,U=2,D=3,H=4,q=5,J=6,X=7,Y=0,Z=1,G=2,$=0,Q=1,K=2,tt=3,et=4,st=5,it=6,rt=7,nt="attached",ot="detached",at=300,ht=301,lt=302,ct=303,ut=304,dt=306,pt=1e3,mt=1001,yt=1002,ft=1003,gt=1004,xt=1004,bt=1005,vt=1005,wt=1006,Mt=1007,St=1007,_t=1008,At=1008,Tt=1009,zt=1010,Ct=1011,It=1012,Bt=1013,kt=1014,Et=1015,Pt=1016,Rt=1017,Ot=1018,Ft=1020,Nt=35902,Lt=1021,Vt=1022,Wt=1023,jt=1024,Ut=1025,Dt=1026,Ht=1027,qt=1028,Jt=1029,Xt=1030,Yt=1031,Zt=1032,Gt=1033,$t=33776,Qt=33777,Kt=33778,te=33779,ee=35840,se=35841,ie=35842,re=35843,ne=36196,oe=37492,ae=37496,he=37808,le=37809,ce=37810,ue=37811,de=37812,pe=37813,me=37814,ye=37815,fe=37816,ge=37817,xe=37818,be=37819,ve=37820,we=37821,Me=36492,Se=36494,_e=36495,Ae=36283,Te=36284,ze=36285,Ce=36286,Ie=2200,Be=2201,ke=2202,Ee=2300,Pe=2301,Re=2302,Oe=2400,Fe=2401,Ne=2402,Le=2500,Ve=2501,We=0,je=1,Ue=2,De=3200,He=3201,qe=3202,Je=3203,Xe=0,Ye=1,Ze="",Ge="srgb",$e="srgb-linear",Qe="linear",Ke="srgb",ts=0,es=7680,ss=7681,is=7682,rs=7683,ns=34055,os=34056,as=5386,hs=512,ls=513,cs=514,us=515,ds=516,ps=517,ms=518,ys=519,fs=512,gs=513,xs=514,bs=515,vs=516,ws=517,Ms=518,Ss=519,_s=35044,As=35048,Ts=35040,zs=35045,Cs=35049,Is=35041,Bs=35046,ks=35050,Es=35042,Ps="100",Rs="300 es",Os=2e3,Fs=2001;class Ns{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const s=this._listeners;void 0===s[t]&&(s[t]=[]),-1===s[t].indexOf(e)&&s[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const s=this._listeners;return void 0!==s[t]&&-1!==s[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const s=this._listeners[t];if(void 0!==s){const t=s.indexOf(e);-1!==t&&s.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 s=e.slice(0);for(let e=0,i=s.length;e>8&255]+Ls[t>>16&255]+Ls[t>>24&255]+"-"+Ls[255&e]+Ls[e>>8&255]+"-"+Ls[e>>16&15|64]+Ls[e>>24&255]+"-"+Ls[63&s|128]+Ls[s>>8&255]+"-"+Ls[s>>16&255]+Ls[s>>24&255]+Ls[255&i]+Ls[i>>8&255]+Ls[i>>16&255]+Ls[i>>24&255]).toLowerCase()}function Ds(t,e,s){return Math.max(e,Math.min(s,t))}function Hs(t,e){return(t%e+e)%e}function qs(t,e,s){return(1-s)*t+s*e}function Js(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 Xs(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 Ys={DEG2RAD:Ws,RAD2DEG:js,generateUUID:Us,clamp:Ds,euclideanModulo:Hs,mapLinear:function(t,e,s,i,r){return i+(t-e)*(r-i)/(s-e)},inverseLerp:function(t,e,s){return t!==e?(s-t)/(e-t):0},lerp:qs,damp:function(t,e,s,i){return qs(t,e,1-Math.exp(-s*i))},pingpong:function(t,e=1){return e-Math.abs(Hs(t,2*e)-e)},smoothstep:function(t,e,s){return t<=e?0:t>=s?1:(t=(t-e)/(s-e))*t*(3-2*t)},smootherstep:function(t,e,s){return t<=e?0:t>=s?1:(t=(t-e)/(s-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&&(Vs=t);let e=Vs+=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*Ws},radToDeg:function(t){return t*js},isPowerOfTwo:function(t){return!(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,s,i,r){const n=Math.cos,o=Math.sin,a=n(s/2),h=o(s/2),l=n((e+i)/2),c=o((e+i)/2),u=n((e-i)/2),d=o((e-i)/2),p=n((i-e)/2),m=o((i-e)/2);switch(r){case"XYX":t.set(a*c,h*u,h*d,a*l);break;case"YZY":t.set(h*d,a*c,h*u,a*l);break;case"ZXZ":t.set(h*u,h*d,a*c,a*l);break;case"XZX":t.set(a*c,h*m,h*p,a*l);break;case"YXY":t.set(h*p,a*c,h*m,a*l);break;case"ZYZ":t.set(h*m,h*p,a*c,a*l);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:Xs,denormalize:Js};class Zs{constructor(t=0,e=0){Zs.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,s=this.y,i=t.elements;return this.x=i[0]*e+i[3]*s+i[6],this.y=i[1]*e+i[4]*s+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=Ds(this.x,t.x,e.x),this.y=Ds(this.y,t.y,e.y),this}clampScalar(t,e){return this.x=Ds(this.x,t,e),this.y=Ds(this.y,t,e),this}clampLength(t,e){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Ds(s,t,e))}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 s=this.dot(t)/e;return Math.acos(Ds(s,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,s=this.y-t.y;return e*e+s*s}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,s){return this.x=t.x+(e.x-t.x)*s,this.y=t.y+(e.y-t.y)*s,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 s=Math.cos(e),i=Math.sin(e),r=this.x-t.x,n=this.y-t.y;return this.x=r*s-n*i+t.x,this.y=r*i+n*s+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class Gs{constructor(t,e,s,i,r,n,o,a,h){Gs.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],void 0!==t&&this.set(t,e,s,i,r,n,o,a,h)}set(t,e,s,i,r,n,o,a,h){const l=this.elements;return l[0]=t,l[1]=i,l[2]=o,l[3]=e,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(t){const e=this.elements,s=t.elements;return e[0]=s[0],e[1]=s[1],e[2]=s[2],e[3]=s[3],e[4]=s[4],e[5]=s[5],e[6]=s[6],e[7]=s[7],e[8]=s[8],this}extractBasis(t,e,s){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),s.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 s=t.elements,i=e.elements,r=this.elements,n=s[0],o=s[3],a=s[6],h=s[1],l=s[4],c=s[7],u=s[2],d=s[5],p=s[8],m=i[0],y=i[3],f=i[6],g=i[1],x=i[4],b=i[7],v=i[2],w=i[5],M=i[8];return r[0]=n*m+o*g+a*v,r[3]=n*y+o*x+a*w,r[6]=n*f+o*b+a*M,r[1]=h*m+l*g+c*v,r[4]=h*y+l*x+c*w,r[7]=h*f+l*b+c*M,r[2]=u*m+d*g+p*v,r[5]=u*y+d*x+p*w,r[8]=u*f+d*b+p*M,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],s=t[1],i=t[2],r=t[3],n=t[4],o=t[5],a=t[6],h=t[7],l=t[8];return e*n*l-e*o*h-s*r*l+s*o*a+i*r*h-i*n*a}invert(){const t=this.elements,e=t[0],s=t[1],i=t[2],r=t[3],n=t[4],o=t[5],a=t[6],h=t[7],l=t[8],c=l*n-o*h,u=o*a-l*r,d=h*r-n*a,p=e*c+s*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]=c*m,t[1]=(i*h-l*s)*m,t[2]=(o*s-i*n)*m,t[3]=u*m,t[4]=(l*e-i*a)*m,t[5]=(i*r-o*e)*m,t[6]=d*m,t[7]=(s*a-h*e)*m,t[8]=(n*e-s*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,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+t,-i*h,i*a,-i*(-h*n+a*o)+o+e,0,0,1),this}scale(t,e){return this.premultiply($s.makeScale(t,e)),this}rotate(t){return this.premultiply($s.makeRotation(-t)),this}translate(t,e){return this.premultiply($s.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),s=Math.sin(t);return this.set(e,-s,0,s,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,s=t.elements;for(let t=0;t<9;t++)if(e[t]!==s[t])return!1;return!0}fromArray(t,e=0){for(let s=0;s<9;s++)this.elements[s]=t[s+e];return this}toArray(t=[],e=0){const s=this.elements;return t[e]=s[0],t[e+1]=s[1],t[e+2]=s[2],t[e+3]=s[3],t[e+4]=s[4],t[e+5]=s[5],t[e+6]=s[6],t[e+7]=s[7],t[e+8]=s[8],t}clone(){return(new this.constructor).fromArray(this.elements)}}const $s=new Gs;function Qs(t){for(let e=t.length-1;e>=0;--e)if(t[e]>=65535)return!0;return!1}const Ks={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function ti(t,e){return new Ks[t](e)}function ei(t){return document.createElementNS("http://www.w3.org/1999/xhtml",t)}function si(){const t=ei("canvas");return t.style.display="block",t}const ii={};function ri(t){t in ii||(ii[t]=!0,console.warn(t))}function ni(t,e,s){return new Promise((function(i,r){setTimeout((function n(){switch(t.clientWaitSync(e,t.SYNC_FLUSH_COMMANDS_BIT,0)){case t.WAIT_FAILED:r();break;case t.TIMEOUT_EXPIRED:setTimeout(n,s);break;default:i()}}),s)}))}function oi(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]}function ai(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])}const hi=(new Gs).set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),li=(new Gs).set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);function ci(){const t={enabled:!0,workingColorSpace:$e,spaces:{},convert:function(t,e,s){return!1!==this.enabled&&e!==s&&e&&s?(this.spaces[e].transfer===Ke&&(t.r=di(t.r),t.g=di(t.g),t.b=di(t.b)),this.spaces[e].primaries!==this.spaces[s].primaries&&(t.applyMatrix3(this.spaces[e].toXYZ),t.applyMatrix3(this.spaces[s].fromXYZ)),this.spaces[s].transfer===Ke&&(t.r=pi(t.r),t.g=pi(t.g),t.b=pi(t.b)),t):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 this.spaces[t].primaries},getTransfer:function(t){return""===t?Qe:this.spaces[t].transfer},getLuminanceCoefficients:function(t,e=this.workingColorSpace){return t.fromArray(this.spaces[e].luminanceCoefficients)},define:function(t){Object.assign(this.spaces,t)},_getMatrix:function(t,e,s){return t.copy(this.spaces[e].toXYZ).multiply(this.spaces[s].fromXYZ)},_getDrawingBufferColorSpace:function(t){return this.spaces[t].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(t=this.workingColorSpace){return this.spaces[t].workingColorSpaceConfig.unpackColorSpace}},e=[.64,.33,.3,.6,.15,.06],s=[.2126,.7152,.0722],i=[.3127,.329];return t.define({[$e]:{primaries:e,whitePoint:i,transfer:Qe,toXYZ:hi,fromXYZ:li,luminanceCoefficients:s,workingColorSpaceConfig:{unpackColorSpace:Ge},outputColorSpaceConfig:{drawingBufferColorSpace:Ge}},[Ge]:{primaries:e,whitePoint:i,transfer:Ke,toXYZ:hi,fromXYZ:li,luminanceCoefficients:s,outputColorSpaceConfig:{drawingBufferColorSpace:Ge}}}),t}const ui=ci();function di(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function pi(t){return t<.0031308?12.92*t:1.055*Math.pow(t,.41666)-.055}let mi;class yi{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===mi&&(mi=ei("canvas")),mi.width=t.width,mi.height=t.height;const s=mi.getContext("2d");t instanceof ImageData?s.putImageData(t,0,0):s.drawImage(t,0,0,t.width,t.height),e=mi}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=ei("canvas");e.width=t.width,e.height=t.height;const s=e.getContext("2d");s.drawImage(t,0,0,t.width,t.height);const i=s.getImageData(0,0,t.width,t.height),r=i.data;for(let t=0;t0&&(s.userData=this.userData),e||(t.textures[this.uuid]=s),s}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(t){if(this.mapping!==at)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 yt: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 yt: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++}}vi.DEFAULT_IMAGE=null,vi.DEFAULT_MAPPING=at,vi.DEFAULT_ANISOTROPY=1;class wi{constructor(t=0,e=0,s=0,i=1){wi.prototype.isVector4=!0,this.x=t,this.y=e,this.z=s,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,s,i){return this.x=t,this.y=e,this.z=s,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,s=this.y,i=this.z,r=this.w,n=t.elements;return this.x=n[0]*e+n[4]*s+n[8]*i+n[12]*r,this.y=n[1]*e+n[5]*s+n[9]*i+n[13]*r,this.z=n[2]*e+n[6]*s+n[10]*i+n[14]*r,this.w=n[3]*e+n[7]*s+n[11]*i+n[15]*r,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this.w/=t.w,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,s,i,r;const n=.01,o=.1,a=t.elements,h=a[0],l=a[4],c=a[8],u=a[1],d=a[5],p=a[9],m=a[2],y=a[6],f=a[10];if(Math.abs(l-u)a&&t>g?tg?a=0?1:-1,i=1-e*e;if(i>Number.EPSILON){const r=Math.sqrt(i),n=Math.atan2(r,e*s);t=Math.sin(t*n)/r,o=Math.sin(o*n)/r}const r=o*s;if(a=a*t+u*r,h=h*t+d*r,l=l*t+p*r,c=c*t+m*r,t===1-o){const t=1/Math.sqrt(a*a+h*h+l*l+c*c);a*=t,h*=t,l*=t,c*=t}}t[e]=a,t[e+1]=h,t[e+2]=l,t[e+3]=c}static multiplyQuaternionsFlat(t,e,s,i,r,n){const o=s[i],a=s[i+1],h=s[i+2],l=s[i+3],c=r[n],u=r[n+1],d=r[n+2],p=r[n+3];return t[e]=o*p+l*c+a*d-h*u,t[e+1]=a*p+l*u+h*c-o*d,t[e+2]=h*p+l*d+o*u-a*c,t[e+3]=l*p-o*c-a*u-h*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,s,i){return this._x=t,this._y=e,this._z=s,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 s=t._x,i=t._y,r=t._z,n=t._order,o=Math.cos,a=Math.sin,h=o(s/2),l=o(i/2),c=o(r/2),u=a(s/2),d=a(i/2),p=a(r/2);switch(n){case"XYZ":this._x=u*l*c+h*d*p,this._y=h*d*c-u*l*p,this._z=h*l*p+u*d*c,this._w=h*l*c-u*d*p;break;case"YXZ":this._x=u*l*c+h*d*p,this._y=h*d*c-u*l*p,this._z=h*l*p-u*d*c,this._w=h*l*c+u*d*p;break;case"ZXY":this._x=u*l*c-h*d*p,this._y=h*d*c+u*l*p,this._z=h*l*p+u*d*c,this._w=h*l*c-u*d*p;break;case"ZYX":this._x=u*l*c-h*d*p,this._y=h*d*c+u*l*p,this._z=h*l*p-u*d*c,this._w=h*l*c+u*d*p;break;case"YZX":this._x=u*l*c+h*d*p,this._y=h*d*c+u*l*p,this._z=h*l*p-u*d*c,this._w=h*l*c-u*d*p;break;case"XZY":this._x=u*l*c-h*d*p,this._y=h*d*c-u*l*p,this._z=h*l*p+u*d*c,this._w=h*l*c+u*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+n)}return!0===e&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const s=e/2,i=Math.sin(s);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(s),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,s=e[0],i=e[4],r=e[8],n=e[1],o=e[5],a=e[9],h=e[2],l=e[6],c=e[10],u=s+o+c;if(u>0){const t=.5/Math.sqrt(u+1);this._w=.25/t,this._x=(l-a)*t,this._y=(r-h)*t,this._z=(n-i)*t}else if(s>o&&s>c){const t=2*Math.sqrt(1+s-o-c);this._w=(l-a)/t,this._x=.25*t,this._y=(i+n)/t,this._z=(r+h)/t}else if(o>c){const t=2*Math.sqrt(1+o-s-c);this._w=(r-h)/t,this._x=(i+n)/t,this._y=.25*t,this._z=(a+l)/t}else{const t=2*Math.sqrt(1+c-s-o);this._w=(n-i)/t,this._x=(r+h)/t,this._y=(a+l)/t,this._z=.25*t}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let s=t.dot(e)+1;return sMath.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=s):(this._x=0,this._y=-t.z,this._z=t.y,this._w=s)):(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=s),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs(Ds(this.dot(t),-1,1)))}rotateTowards(t,e){const s=this.angleTo(t);if(0===s)return this;const i=Math.min(1,e/s);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 s=t._x,i=t._y,r=t._z,n=t._w,o=e._x,a=e._y,h=e._z,l=e._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(t,e){if(0===e)return this;if(1===e)return this.copy(t);const s=this._x,i=this._y,r=this._z,n=this._w;let o=n*t._w+s*t._x+i*t._y+r*t._z;if(o<0?(this._w=-t._w,this._x=-t._x,this._y=-t._y,this._z=-t._z,o=-o):this.copy(t),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 t=1-e;return this._w=t*n+e*this._w,this._x=t*s+e*this._x,this._y=t*i+e*this._y,this._z=t*r+e*this._z,this.normalize(),this}const h=Math.sqrt(a),l=Math.atan2(h,o),c=Math.sin((1-e)*l)/h,u=Math.sin(e*l)/h;return this._w=n*c+this._w*u,this._x=s*c+this._x*u,this._y=i*c+this._y*u,this._z=r*c+this._z*u,this._onChangeCallback(),this}slerpQuaternions(t,e,s){return this.copy(t).slerp(e,s)}random(){const t=2*Math.PI*Math.random(),e=2*Math.PI*Math.random(),s=Math.random(),i=Math.sqrt(1-s),r=Math.sqrt(s);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 Ii{constructor(t=0,e=0,s=0){Ii.prototype.isVector3=!0,this.x=t,this.y=e,this.z=s}set(t,e,s){return void 0===s&&(s=this.z),this.x=t,this.y=e,this.z=s,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(ki.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(ki.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,s=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*s+r[6]*i,this.y=r[1]*e+r[4]*s+r[7]*i,this.z=r[2]*e+r[5]*s+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,s=this.y,i=this.z,r=t.elements,n=1/(r[3]*e+r[7]*s+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*s+r[8]*i+r[12])*n,this.y=(r[1]*e+r[5]*s+r[9]*i+r[13])*n,this.z=(r[2]*e+r[6]*s+r[10]*i+r[14])*n,this}applyQuaternion(t){const e=this.x,s=this.y,i=this.z,r=t.x,n=t.y,o=t.z,a=t.w,h=2*(n*i-o*s),l=2*(o*e-r*i),c=2*(r*s-n*e);return this.x=e+a*h+n*c-o*l,this.y=s+a*l+o*h-r*c,this.z=i+a*c+r*l-n*h,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,s=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*s+r[8]*i,this.y=r[1]*e+r[5]*s+r[9]*i,this.z=r[2]*e+r[6]*s+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=Ds(this.x,t.x,e.x),this.y=Ds(this.y,t.y,e.y),this.z=Ds(this.z,t.z,e.z),this}clampScalar(t,e){return this.x=Ds(this.x,t,e),this.y=Ds(this.y,t,e),this.z=Ds(this.z,t,e),this}clampLength(t,e){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Ds(s,t,e))}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,s){return this.x=t.x+(e.x-t.x)*s,this.y=t.y+(e.y-t.y)*s,this.z=t.z+(e.z-t.z)*s,this}cross(t){return this.crossVectors(this,t)}crossVectors(t,e){const s=t.x,i=t.y,r=t.z,n=e.x,o=e.y,a=e.z;return this.x=i*a-r*o,this.y=r*n-s*a,this.z=s*o-i*n,this}projectOnVector(t){const e=t.lengthSq();if(0===e)return this.set(0,0,0);const s=t.dot(this)/e;return this.copy(t).multiplyScalar(s)}projectOnPlane(t){return Bi.copy(this).projectOnVector(t),this.sub(Bi)}reflect(t){return this.sub(Bi.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 s=this.dot(t)/e;return Math.acos(Ds(s,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,s=this.y-t.y,i=this.z-t.z;return e*e+s*s+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,s){const i=Math.sin(e)*t;return this.x=i*Math.sin(s),this.y=Math.cos(e)*t,this.z=i*Math.cos(s),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,s){return this.x=t*Math.sin(e),this.y=s,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(),s=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=s,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,s=Math.sqrt(1-e*e);return this.x=s*Math.cos(t),this.y=e,this.z=s*Math.sin(t),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const Bi=new Ii,ki=new Ci;class Ei{constructor(t=new Ii(1/0,1/0,1/0),e=new Ii(-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,s=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,Ri),Ri.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,s;return t.normal.x>0?(e=t.normal.x*this.min.x,s=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,s=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,s+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,s+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,s+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,s+=t.normal.z*this.min.z),e<=-t.constant&&s>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(Ui),Di.subVectors(this.max,Ui),Fi.subVectors(t.a,Ui),Ni.subVectors(t.b,Ui),Li.subVectors(t.c,Ui),Vi.subVectors(Ni,Fi),Wi.subVectors(Li,Ni),ji.subVectors(Fi,Li);let e=[0,-Vi.z,Vi.y,0,-Wi.z,Wi.y,0,-ji.z,ji.y,Vi.z,0,-Vi.x,Wi.z,0,-Wi.x,ji.z,0,-ji.x,-Vi.y,Vi.x,0,-Wi.y,Wi.x,0,-ji.y,ji.x,0];return!!Ji(e,Fi,Ni,Li,Di)&&(e=[1,0,0,0,1,0,0,0,1],!!Ji(e,Fi,Ni,Li,Di)&&(Hi.crossVectors(Vi,Wi),e=[Hi.x,Hi.y,Hi.z],Ji(e,Fi,Ni,Li,Di)))}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,Ri).distanceTo(t)}getBoundingSphere(t){return this.isEmpty()?t.makeEmpty():(this.getCenter(t.center),t.radius=.5*this.getSize(Ri).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()||(Pi[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),Pi[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),Pi[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),Pi[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),Pi[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),Pi[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),Pi[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),Pi[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(Pi)),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 Pi=[new Ii,new Ii,new Ii,new Ii,new Ii,new Ii,new Ii,new Ii],Ri=new Ii,Oi=new Ei,Fi=new Ii,Ni=new Ii,Li=new Ii,Vi=new Ii,Wi=new Ii,ji=new Ii,Ui=new Ii,Di=new Ii,Hi=new Ii,qi=new Ii;function Ji(t,e,s,i,r){for(let n=0,o=t.length-3;n<=o;n+=3){qi.fromArray(t,n);const o=r.x*Math.abs(qi.x)+r.y*Math.abs(qi.y)+r.z*Math.abs(qi.z),a=e.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 Ei,Yi=new Ii,Zi=new Ii;class Gi{constructor(t=new Ii,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 s=this.center;void 0!==e?s.copy(e):Xi.setFromPoints(t).getCenter(s);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;Yi.subVectors(t,this.center);const e=Yi.lengthSq();if(e>this.radius*this.radius){const t=Math.sqrt(e),s=.5*(t-this.radius);this.center.addScaledVector(Yi,s/t),this.radius+=s}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):(Zi.subVectors(t.center,this.center).setLength(t.radius),this.expandByPoint(Yi.copy(t.center).add(Zi)),this.expandByPoint(Yi.copy(t.center).sub(Zi))),this)}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const $i=new Ii,Qi=new Ii,Ki=new Ii,tr=new Ii,er=new Ii,sr=new Ii,ir=new Ii;class rr{constructor(t=new Ii,e=new Ii(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,$i)),this}closestPointToPoint(t,e){e.subVectors(t,this.origin);const s=e.dot(this.direction);return s<0?e.copy(this.origin):e.copy(this.origin).addScaledVector(this.direction,s)}distanceToPoint(t){return Math.sqrt(this.distanceSqToPoint(t))}distanceSqToPoint(t){const e=$i.subVectors(t,this.origin).dot(this.direction);return e<0?this.origin.distanceToSquared(t):($i.copy(this.origin).addScaledVector(this.direction,e),$i.distanceToSquared(t))}distanceSqToSegment(t,e,s,i){Qi.copy(t).add(e).multiplyScalar(.5),Ki.copy(e).sub(t).normalize(),tr.copy(this.origin).sub(Qi);const r=.5*t.distanceTo(e),n=-this.direction.dot(Ki),o=tr.dot(this.direction),a=-tr.dot(Ki),h=tr.lengthSq(),l=Math.abs(1-n*n);let c,u,d,p;if(l>0)if(c=n*a-o,u=n*o-a,p=r*l,c>=0)if(u>=-p)if(u<=p){const t=1/l;c*=t,u*=t,d=c*(c+n*u+2*o)+u*(n*c+u+2*a)+h}else u=r,c=Math.max(0,-(n*u+o)),d=-c*c+u*(u+2*a)+h;else u=-r,c=Math.max(0,-(n*u+o)),d=-c*c+u*(u+2*a)+h;else u<=-p?(c=Math.max(0,-(-n*r+o)),u=c>0?-r:Math.min(Math.max(-r,-a),r),d=-c*c+u*(u+2*a)+h):u<=p?(c=0,u=Math.min(Math.max(-r,-a),r),d=u*(u+2*a)+h):(c=Math.max(0,-(n*r+o)),u=c>0?r:Math.min(Math.max(-r,-a),r),d=-c*c+u*(u+2*a)+h);else u=n>0?-r:r,c=Math.max(0,-(n*u+o)),d=-c*c+u*(u+2*a)+h;return s&&s.copy(this.origin).addScaledVector(this.direction,c),i&&i.copy(Qi).addScaledVector(Ki,u),d}intersectSphere(t,e){$i.subVectors(t.center,this.origin);const s=$i.dot(this.direction),i=$i.dot($i)-s*s,r=t.radius*t.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,e):this.at(o,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 s=-(this.origin.dot(t.normal)+t.constant)/e;return s>=0?s:null}intersectPlane(t,e){const s=this.distanceToPlane(t);return null===s?null:this.at(s,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 s,i,r,n,o,a;const h=1/this.direction.x,l=1/this.direction.y,c=1/this.direction.z,u=this.origin;return h>=0?(s=(t.min.x-u.x)*h,i=(t.max.x-u.x)*h):(s=(t.max.x-u.x)*h,i=(t.min.x-u.x)*h),l>=0?(r=(t.min.y-u.y)*l,n=(t.max.y-u.y)*l):(r=(t.max.y-u.y)*l,n=(t.min.y-u.y)*l),s>n||r>i?null:((r>s||isNaN(s))&&(s=r),(n=0?(o=(t.min.z-u.z)*c,a=(t.max.z-u.z)*c):(o=(t.max.z-u.z)*c,a=(t.min.z-u.z)*c),s>a||o>i?null:((o>s||s!=s)&&(s=o),(a=0?s:i,e)))}intersectsBox(t){return null!==this.intersectBox(t,$i)}intersectTriangle(t,e,s,i,r){er.subVectors(e,t),sr.subVectors(s,t),ir.crossVectors(er,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}tr.subVectors(this.origin,t);const a=n*this.direction.dot(sr.crossVectors(tr,sr));if(a<0)return null;const h=n*this.direction.dot(er.cross(tr));if(h<0)return null;if(a+h>o)return null;const l=-n*tr.dot(ir);return l<0?null:this.at(l/o,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 nr{constructor(t,e,s,i,r,n,o,a,h,l,c,u,d,p,m,y){nr.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,s,i,r,n,o,a,h,l,c,u,d,p,m,y)}set(t,e,s,i,r,n,o,a,h,l,c,u,d,p,m,y){const f=this.elements;return f[0]=t,f[4]=e,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]=c,f[14]=u,f[3]=d,f[7]=p,f[11]=m,f[15]=y,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(t){const e=this.elements,s=t.elements;return e[0]=s[0],e[1]=s[1],e[2]=s[2],e[3]=s[3],e[4]=s[4],e[5]=s[5],e[6]=s[6],e[7]=s[7],e[8]=s[8],e[9]=s[9],e[10]=s[10],e[11]=s[11],e[12]=s[12],e[13]=s[13],e[14]=s[14],e[15]=s[15],this}copyPosition(t){const e=this.elements,s=t.elements;return e[12]=s[12],e[13]=s[13],e[14]=s[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,s){return t.setFromMatrixColumn(this,0),e.setFromMatrixColumn(this,1),s.setFromMatrixColumn(this,2),this}makeBasis(t,e,s){return this.set(t.x,e.x,s.x,0,t.y,e.y,s.y,0,t.z,e.z,s.z,0,0,0,0,1),this}extractRotation(t){const e=this.elements,s=t.elements,i=1/or.setFromMatrixColumn(t,0).length(),r=1/or.setFromMatrixColumn(t,1).length(),n=1/or.setFromMatrixColumn(t,2).length();return e[0]=s[0]*i,e[1]=s[1]*i,e[2]=s[2]*i,e[3]=0,e[4]=s[4]*r,e[5]=s[5]*r,e[6]=s[6]*r,e[7]=0,e[8]=s[8]*n,e[9]=s[9]*n,e[10]=s[10]*n,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromEuler(t){const e=this.elements,s=t.x,i=t.y,r=t.z,n=Math.cos(s),o=Math.sin(s),a=Math.cos(i),h=Math.sin(i),l=Math.cos(r),c=Math.sin(r);if("XYZ"===t.order){const t=n*l,s=n*c,i=o*l,r=o*c;e[0]=a*l,e[4]=-a*c,e[8]=h,e[1]=s+i*h,e[5]=t-r*h,e[9]=-o*a,e[2]=r-t*h,e[6]=i+s*h,e[10]=n*a}else if("YXZ"===t.order){const t=a*l,s=a*c,i=h*l,r=h*c;e[0]=t+r*o,e[4]=i*o-s,e[8]=n*h,e[1]=n*c,e[5]=n*l,e[9]=-o,e[2]=s*o-i,e[6]=r+t*o,e[10]=n*a}else if("ZXY"===t.order){const t=a*l,s=a*c,i=h*l,r=h*c;e[0]=t-r*o,e[4]=-n*c,e[8]=i+s*o,e[1]=s+i*o,e[5]=n*l,e[9]=r-t*o,e[2]=-n*h,e[6]=o,e[10]=n*a}else if("ZYX"===t.order){const t=n*l,s=n*c,i=o*l,r=o*c;e[0]=a*l,e[4]=i*h-s,e[8]=t*h+r,e[1]=a*c,e[5]=r*h+t,e[9]=s*h-i,e[2]=-h,e[6]=o*a,e[10]=n*a}else if("YZX"===t.order){const t=n*a,s=n*h,i=o*a,r=o*h;e[0]=a*l,e[4]=r-t*c,e[8]=i*c+s,e[1]=c,e[5]=n*l,e[9]=-o*l,e[2]=-h*l,e[6]=s*c+i,e[10]=t-r*c}else if("XZY"===t.order){const t=n*a,s=n*h,i=o*a,r=o*h;e[0]=a*l,e[4]=-c,e[8]=h*l,e[1]=t*c+r,e[5]=n*l,e[9]=s*c-i,e[2]=i*c-s,e[6]=o*l,e[10]=r*c+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(hr,t,lr)}lookAt(t,e,s){const i=this.elements;return dr.subVectors(t,e),0===dr.lengthSq()&&(dr.z=1),dr.normalize(),cr.crossVectors(s,dr),0===cr.lengthSq()&&(1===Math.abs(s.z)?dr.x+=1e-4:dr.z+=1e-4,dr.normalize(),cr.crossVectors(s,dr)),cr.normalize(),ur.crossVectors(dr,cr),i[0]=cr.x,i[4]=ur.x,i[8]=dr.x,i[1]=cr.y,i[5]=ur.y,i[9]=dr.y,i[2]=cr.z,i[6]=ur.z,i[10]=dr.z,this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const s=t.elements,i=e.elements,r=this.elements,n=s[0],o=s[4],a=s[8],h=s[12],l=s[1],c=s[5],u=s[9],d=s[13],p=s[2],m=s[6],y=s[10],f=s[14],g=s[3],x=s[7],b=s[11],v=s[15],w=i[0],M=i[4],S=i[8],_=i[12],A=i[1],T=i[5],z=i[9],C=i[13],I=i[2],B=i[6],k=i[10],E=i[14],P=i[3],R=i[7],O=i[11],F=i[15];return r[0]=n*w+o*A+a*I+h*P,r[4]=n*M+o*T+a*B+h*R,r[8]=n*S+o*z+a*k+h*O,r[12]=n*_+o*C+a*E+h*F,r[1]=l*w+c*A+u*I+d*P,r[5]=l*M+c*T+u*B+d*R,r[9]=l*S+c*z+u*k+d*O,r[13]=l*_+c*C+u*E+d*F,r[2]=p*w+m*A+y*I+f*P,r[6]=p*M+m*T+y*B+f*R,r[10]=p*S+m*z+y*k+f*O,r[14]=p*_+m*C+y*E+f*F,r[3]=g*w+x*A+b*I+v*P,r[7]=g*M+x*T+b*B+v*R,r[11]=g*S+x*z+b*k+v*O,r[15]=g*_+x*C+b*E+v*F,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],s=t[4],i=t[8],r=t[12],n=t[1],o=t[5],a=t[9],h=t[13],l=t[2],c=t[6],u=t[10],d=t[14];return t[3]*(+r*a*c-i*h*c-r*o*u+s*h*u+i*o*d-s*a*d)+t[7]*(+e*a*d-e*h*u+r*n*u-i*n*d+i*h*l-r*a*l)+t[11]*(+e*h*c-e*o*d-r*n*c+s*n*d+r*o*l-s*h*l)+t[15]*(-i*o*l-e*a*c+e*o*u+i*n*c-s*n*u+s*a*l)}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,s){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]=s),this}invert(){const t=this.elements,e=t[0],s=t[1],i=t[2],r=t[3],n=t[4],o=t[5],a=t[6],h=t[7],l=t[8],c=t[9],u=t[10],d=t[11],p=t[12],m=t[13],y=t[14],f=t[15],g=c*y*h-m*u*h+m*a*d-o*y*d-c*a*f+o*u*f,x=p*u*h-l*y*h-p*a*d+n*y*d+l*a*f-n*u*f,b=l*m*h-p*c*h+p*o*d-n*m*d-l*o*f+n*c*f,v=p*c*a-l*m*a-p*o*u+n*m*u+l*o*y-n*c*y,w=e*g+s*x+i*b+r*v;if(0===w)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const M=1/w;return t[0]=g*M,t[1]=(m*u*r-c*y*r-m*i*d+s*y*d+c*i*f-s*u*f)*M,t[2]=(o*y*r-m*a*r+m*i*h-s*y*h-o*i*f+s*a*f)*M,t[3]=(c*a*r-o*u*r-c*i*h+s*u*h+o*i*d-s*a*d)*M,t[4]=x*M,t[5]=(l*y*r-p*u*r+p*i*d-e*y*d-l*i*f+e*u*f)*M,t[6]=(p*a*r-n*y*r-p*i*h+e*y*h+n*i*f-e*a*f)*M,t[7]=(n*u*r-l*a*r+l*i*h-e*u*h-n*i*d+e*a*d)*M,t[8]=b*M,t[9]=(p*c*r-l*m*r-p*s*d+e*m*d+l*s*f-e*c*f)*M,t[10]=(n*m*r-p*o*r+p*s*h-e*m*h-n*s*f+e*o*f)*M,t[11]=(l*o*r-n*c*r-l*s*h+e*c*h+n*s*d-e*o*d)*M,t[12]=v*M,t[13]=(l*m*i-p*c*i+p*s*u-e*m*u-l*s*y+e*c*y)*M,t[14]=(p*o*i-n*m*i-p*s*a+e*m*a+n*s*y-e*o*y)*M,t[15]=(n*c*i-l*o*i+l*s*a-e*c*a-n*s*u+e*o*u)*M,this}scale(t){const e=this.elements,s=t.x,i=t.y,r=t.z;return e[0]*=s,e[4]*=i,e[8]*=r,e[1]*=s,e[5]*=i,e[9]*=r,e[2]*=s,e[6]*=i,e[10]*=r,e[3]*=s,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],s=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,s,i))}makeTranslation(t,e,s){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,s,0,0,0,1),this}makeRotationX(t){const e=Math.cos(t),s=Math.sin(t);return this.set(1,0,0,0,0,e,-s,0,0,s,e,0,0,0,0,1),this}makeRotationY(t){const e=Math.cos(t),s=Math.sin(t);return this.set(e,0,s,0,0,1,0,0,-s,0,e,0,0,0,0,1),this}makeRotationZ(t){const e=Math.cos(t),s=Math.sin(t);return this.set(e,-s,0,0,s,e,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(t,e){const s=Math.cos(e),i=Math.sin(e),r=1-s,n=t.x,o=t.y,a=t.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(t,e,s){return this.set(t,0,0,0,0,e,0,0,0,0,s,0,0,0,0,1),this}makeShear(t,e,s,i,r,n){return this.set(1,s,r,0,t,1,n,0,e,i,1,0,0,0,0,1),this}compose(t,e,s){const i=this.elements,r=e._x,n=e._y,o=e._z,a=e._w,h=r+r,l=n+n,c=o+o,u=r*h,d=r*l,p=r*c,m=n*l,y=n*c,f=o*c,g=a*h,x=a*l,b=a*c,v=s.x,w=s.y,M=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)*w,i[5]=(1-(u+f))*w,i[6]=(y+g)*w,i[7]=0,i[8]=(p+x)*M,i[9]=(y-g)*M,i[10]=(1-(u+m))*M,i[11]=0,i[12]=t.x,i[13]=t.y,i[14]=t.z,i[15]=1,this}decompose(t,e,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),t.x=i[12],t.y=i[13],t.z=i[14],ar.copy(this);const a=1/r,h=1/n,l=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]*=l,ar.elements[9]*=l,ar.elements[10]*=l,e.setFromRotationMatrix(ar),s.x=r,s.y=n,s.z=o,this}makePerspective(t,e,s,i,r,n,o=2e3){const a=this.elements,h=2*r/(e-t),l=2*r/(s-i),c=(e+t)/(e-t),u=(s+i)/(s-i);let d,p;if(o===Os)d=-(n+r)/(n-r),p=-2*n*r/(n-r);else{if(o!==Fs)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]=c,a[12]=0,a[1]=0,a[5]=l,a[9]=u,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(t,e,s,i,r,n,o=2e3){const a=this.elements,h=1/(e-t),l=1/(s-i),c=1/(n-r),u=(e+t)*h,d=(s+i)*l;let p,m;if(o===Os)p=(n+r)*c,m=-2*c;else{if(o!==Fs)throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+o);p=r*c,m=-1*c}return a[0]=2*h,a[4]=0,a[8]=0,a[12]=-u,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(t){const e=this.elements,s=t.elements;for(let t=0;t<16;t++)if(e[t]!==s[t])return!1;return!0}fromArray(t,e=0){for(let s=0;s<16;s++)this.elements[s]=t[s+e];return this}toArray(t=[],e=0){const s=this.elements;return t[e]=s[0],t[e+1]=s[1],t[e+2]=s[2],t[e+3]=s[3],t[e+4]=s[4],t[e+5]=s[5],t[e+6]=s[6],t[e+7]=s[7],t[e+8]=s[8],t[e+9]=s[9],t[e+10]=s[10],t[e+11]=s[11],t[e+12]=s[12],t[e+13]=s[13],t[e+14]=s[14],t[e+15]=s[15],t}}const or=new Ii,ar=new nr,hr=new Ii(0,0,0),lr=new Ii(1,1,1),cr=new Ii,ur=new Ii,dr=new Ii,pr=new nr,mr=new Ci;class yr{constructor(t=0,e=0,s=0,i=yr.DEFAULT_ORDER){this.isEuler=!0,this._x=t,this._y=e,this._z=s,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,s,i=this._order){return this._x=t,this._y=e,this._z=s,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,s=!0){const i=t.elements,r=i[0],n=i[4],o=i[8],a=i[1],h=i[5],l=i[9],c=i[2],u=i[6],d=i[10];switch(e){case"XYZ":this._y=Math.asin(Ds(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-l,d),this._z=Math.atan2(-n,r)):(this._x=Math.atan2(u,h),this._z=0);break;case"YXZ":this._x=Math.asin(-Ds(l,-1,1)),Math.abs(l)<.9999999?(this._y=Math.atan2(o,d),this._z=Math.atan2(a,h)):(this._y=Math.atan2(-c,r),this._z=0);break;case"ZXY":this._x=Math.asin(Ds(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(-c,d),this._z=Math.atan2(-n,h)):(this._y=0,this._z=Math.atan2(a,r));break;case"ZYX":this._y=Math.asin(-Ds(c,-1,1)),Math.abs(c)<.9999999?(this._x=Math.atan2(u,d),this._z=Math.atan2(a,r)):(this._x=0,this._z=Math.atan2(-n,h));break;case"YZX":this._z=Math.asin(Ds(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-l,h),this._y=Math.atan2(-c,r)):(this._x=0,this._y=Math.atan2(o,d));break;case"XZY":this._z=Math.asin(-Ds(n,-1,1)),Math.abs(n)<.9999999?(this._x=Math.atan2(u,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: "+e)}return this._order=e,!0===s&&this._onChangeCallback(),this}setFromQuaternion(t,e,s){return pr.makeRotationFromQuaternion(t),this.setFromRotationMatrix(pr,e,s)}setFromVector3(t,e=this._order){return this.set(t.x,t.y,t.z,e)}reorder(t){return mr.setFromEuler(this),this.setFromQuaternion(mr,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}}yr.DEFAULT_ORDER="XYZ";class fr{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 s=e.shapes;if(Array.isArray(s))for(let e=0,i=s.length;e0){i.children=[];for(let e=0;e0){i.animations=[];for(let e=0;e0&&(s.geometries=e),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),c.length>0&&(s.nodes=c)}return s.object=i,s;function n(t){const e=[];for(const s in t){const i=t[s];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,s,i,r){Pr.subVectors(i,e),Rr.subVectors(s,e),Or.subVectors(t,e);const n=Pr.dot(Pr),o=Pr.dot(Rr),a=Pr.dot(Or),h=Rr.dot(Rr),l=Rr.dot(Or),c=n*h-o*o;if(0===c)return r.set(0,0,0),null;const u=1/c,d=(h*a-o*l)*u,p=(n*l-o*a)*u;return r.set(1-d-p,p,d)}static containsPoint(t,e,s,i){return null!==this.getBarycoord(t,e,s,i,Fr)&&(Fr.x>=0&&Fr.y>=0&&Fr.x+Fr.y<=1)}static getInterpolation(t,e,s,i,r,n,o,a){return null===this.getBarycoord(t,e,s,i,Fr)?(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,Fr.x),a.addScaledVector(n,Fr.y),a.addScaledVector(o,Fr.z),a)}static getInterpolatedAttribute(t,e,s,i,r,n){return Dr.setScalar(0),Hr.setScalar(0),qr.setScalar(0),Dr.fromBufferAttribute(t,e),Hr.fromBufferAttribute(t,s),qr.fromBufferAttribute(t,i),n.setScalar(0),n.addScaledVector(Dr,r.x),n.addScaledVector(Hr,r.y),n.addScaledVector(qr,r.z),n}static isFrontFacing(t,e,s,i){return Pr.subVectors(s,e),Rr.subVectors(t,e),Pr.cross(Rr).dot(i)<0}set(t,e,s){return this.a.copy(t),this.b.copy(e),this.c.copy(s),this}setFromPointsAndIndices(t,e,s,i){return this.a.copy(t[e]),this.b.copy(t[s]),this.c.copy(t[i]),this}setFromAttributeAndIndices(t,e,s,i){return this.a.fromBufferAttribute(t,e),this.b.fromBufferAttribute(t,s),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 Pr.subVectors(this.c,this.b),Rr.subVectors(this.a,this.b),.5*Pr.cross(Rr).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,s,i,r){return Jr.getInterpolation(t,this.a,this.b,this.c,e,s,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 s=this.a,i=this.b,r=this.c;let n,o;Nr.subVectors(i,s),Lr.subVectors(r,s),Wr.subVectors(t,s);const a=Nr.dot(Wr),h=Lr.dot(Wr);if(a<=0&&h<=0)return e.copy(s);jr.subVectors(t,i);const l=Nr.dot(jr),c=Lr.dot(jr);if(l>=0&&c<=l)return e.copy(i);const u=a*c-l*h;if(u<=0&&a>=0&&l<=0)return n=a/(a-l),e.copy(s).addScaledVector(Nr,n);Ur.subVectors(t,r);const d=Nr.dot(Ur),p=Lr.dot(Ur);if(p>=0&&d<=p)return e.copy(r);const m=d*h-a*p;if(m<=0&&h>=0&&p<=0)return o=h/(h-p),e.copy(s).addScaledVector(Lr,o);const y=l*p-d*c;if(y<=0&&c-l>=0&&d-p>=0)return Vr.subVectors(r,i),o=(c-l)/(c-l+(d-p)),e.copy(i).addScaledVector(Vr,o);const f=1/(y+m+u);return n=m*f,o=u*f,e.copy(s).addScaledVector(Nr,n).addScaledVector(Lr,o)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}const Xr={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 Gr(t,e,s){return s<0&&(s+=1),s>1&&(s-=1),s<1/6?t+6*(e-t)*s:s<.5?e:s<2/3?t+6*(e-t)*(2/3-s):t}class $r{constructor(t,e,s){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(t,e,s)}set(t,e,s){if(void 0===e&&void 0===s){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,s);return this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t,e=Ge){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(255&t)/255,ui.toWorkingColorSpace(this,e),this}setRGB(t,e,s,i=ui.workingColorSpace){return this.r=t,this.g=e,this.b=s,ui.toWorkingColorSpace(this,i),this}setHSL(t,e,s,i=ui.workingColorSpace){if(t=Hs(t,1),e=Ds(e,0,1),s=Ds(s,0,1),0===e)this.r=this.g=this.b=s;else{const i=s<=.5?s*(1+e):s+e-s*e,r=2*s-i;this.r=Gr(r,i,t+1/3),this.g=Gr(r,i,t),this.b=Gr(r,i,t-1/3)}return ui.toWorkingColorSpace(this,i),this}setStyle(t,e=Ge){function s(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 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,e);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,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(o))return s(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 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,e);if(6===r)return this.setHex(parseInt(s,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=Ge){const s=Xr[t.toLowerCase()];return void 0!==s?this.setHex(s,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=di(t.r),this.g=di(t.g),this.b=di(t.b),this}copyLinearToSRGB(t){return this.r=pi(t.r),this.g=pi(t.g),this.b=pi(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(t=Ge){return ui.fromWorkingColorSpace(Qr.copy(this),t),65536*Math.round(Ds(255*Qr.r,0,255))+256*Math.round(Ds(255*Qr.g,0,255))+Math.round(Ds(255*Qr.b,0,255))}getHexString(t=Ge){return("000000"+this.getHex(t).toString(16)).slice(-6)}getHSL(t,e=ui.workingColorSpace){ui.fromWorkingColorSpace(Qr.copy(this),e);const s=Qr.r,i=Qr.g,r=Qr.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 t=n-o;switch(h=l<=.5?t/(n+o):t/(2-n-o),n){case s:a=(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 s=t[e];if(void 0===s){console.warn(`THREE.Material: parameter '${e}' has value of undefined.`);continue}const i=this[e];void 0!==i?i&&i.isColor?i.set(s):i&&i.isVector3&&s&&s.isVector3?i.copy(s):this[e]=s: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 s={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};function i(t){const e=[];for(const s in t){const i=t[s];delete i.metadata,e.push(i)}return e}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(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(s.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(s.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).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(t).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(s.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(t).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(t).uuid),this.map&&this.map.isTexture&&(s.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(s.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(s.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(s.lightMap=this.lightMap.toJSON(t).uuid,s.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(s.aoMap=this.aoMap.toJSON(t).uuid,s.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(s.bumpMap=this.bumpMap.toJSON(t).uuid,s.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(s.normalMap=this.normalMap.toJSON(t).uuid,s.normalMapType=this.normalMapType,s.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(s.displacementMap=this.displacementMap.toJSON(t).uuid,s.displacementScale=this.displacementScale,s.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(s.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(s.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(s.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(s.specularMap=this.specularMap.toJSON(t).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(s.specularIntensityMap=this.specularIntensityMap.toJSON(t).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(s.specularColorMap=this.specularColorMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(s.envMap=this.envMap.toJSON(t).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(t).uuid),void 0!==this.transmission&&(s.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(s.transmissionMap=this.transmissionMap.toJSON(t).uuid),void 0!==this.thickness&&(s.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(s.thicknessMap=this.thicknessMap.toJSON(t).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),0!==this.side&&(s.side=this.side),!0===this.vertexColors&&(s.vertexColors=!0),this.opacity<1&&(s.opacity=this.opacity),!0===this.transparent&&(s.transparent=!0),204!==this.blendSrc&&(s.blendSrc=this.blendSrc),205!==this.blendDst&&(s.blendDst=this.blendDst),100!==this.blendEquation&&(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),519!==this.stencilFunc&&(s.stencilFunc=this.stencilFunc),0!==this.stencilRef&&(s.stencilRef=this.stencilRef),255!==this.stencilFuncMask&&(s.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==es&&(s.stencilFail=this.stencilFail),this.stencilZFail!==es&&(s.stencilZFail=this.stencilZFail),this.stencilZPass!==es&&(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),e){const e=i(t.textures),r=i(t.images);e.length>0&&(s.textures=e),r.length>0&&(s.images=r)}return s}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 s=null;if(null!==e){const t=e.length;s=new Array(t);for(let i=0;i!==t;++i)s[i]=e[i].clone()}return this.clippingPlanes=s,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 en extends tn{constructor(t){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new $r(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 yr,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(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 sn=rn();function rn(){const t=new ArrayBuffer(4),e=new Float32Array(t),s=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 n=new Uint32Array(2048),o=new Uint32Array(64),a=new Uint32Array(64);for(let t=1;t<1024;++t){let e=t<<13,s=0;for(;!(8388608&e);)e<<=1,s-=8388608;e&=-8388609,s+=947912704,n[t]=e|s}for(let t=1024;t<2048;++t)n[t]=939524096+(t-1024<<13);for(let t=1;t<31;++t)o[t]=t<<23;o[31]=1199570944,o[32]=2147483648;for(let t=33;t<63;++t)o[t]=2147483648+(t-32<<23);o[63]=3347054592;for(let t=1;t<64;++t)32!==t&&(a[t]=1024);return{floatView:e,uint32View:s,baseTable:i,shiftTable:r,mantissaTable:n,exponentTable:o,offsetTable:a}}function nn(t){Math.abs(t)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),t=Ds(t,-65504,65504),sn.floatView[0]=t;const e=sn.uint32View[0],s=e>>23&511;return sn.baseTable[s]+((8388607&e)>>sn.shiftTable[s])}function on(t){const e=t>>10;return sn.uint32View[0]=sn.mantissaTable[sn.offsetTable[e]+(1023&t)]+sn.exponentTable[e],sn.floatView[0]}const an={toHalfFloat:nn,fromHalfFloat:on},hn=new Ii,ln=new Zs;class cn{constructor(t,e,s=!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=s,this.usage=_s,this.updateRanges=[],this.gpuType=Et,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,s){t*=this.itemSize,s*=e.itemSize;for(let i=0,r=this.itemSize;ie.count&&console.warn("THREE.BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry."),e.needsUpdate=!0}return this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Ei);const t=this.attributes.position,e=this.morphAttributes.position;if(t&&t.isGLBufferAttribute)return console.error("THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.",this),void this.boundingBox.set(new Ii(-1/0,-1/0,-1/0),new Ii(1/0,1/0,1/0));if(void 0!==t){if(this.boundingBox.setFromBufferAttribute(t),e)for(let t=0,s=e.length;t0&&(t.userData=this.userData),void 0!==this.parameters){const e=this.parameters;for(const s in e)void 0!==e[s]&&(t[s]=e[s]);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 s=this.attributes;for(const e in s){const i=s[e];t.data.attributes[e]=i.toJSON(t.data)}const i={};let r=!1;for(const e in this.morphAttributes){const s=this.morphAttributes[e],n=[];for(let e=0,i=s.length;e0&&(i[e]=n,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const n=this.groups;n.length>0&&(t.data.groups=JSON.parse(JSON.stringify(n)));const o=this.boundingSphere;return null!==o&&(t.data.boundingSphere={center:o.center.toArray(),radius:o.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 s=t.index;null!==s&&this.setIndex(s.clone(e));const i=t.attributes;for(const t in i){const s=i[t];this.setAttribute(t,s.clone(e))}const r=t.morphAttributes;for(const t in r){const s=[],i=r[t];for(let t=0,r=i.length;t0){const s=t[e[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=s.length;t(t.far-t.near)**2)return}Cn.copy(r).invert(),In.copy(t.ray).applyMatrix4(Cn),null!==s.boundingBox&&!1===In.intersectsBox(s.boundingBox)||this._computeIntersections(t,e,In)}}_computeIntersections(t,e,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,c=r.attributes.normal,u=r.groups,d=r.drawRange;if(null!==o)if(Array.isArray(n))for(let r=0,a=u.length;rs.far?null:{distance:l,point:Ln.clone(),object:t}}(t,e,s,i,En,Pn,Rn,Nn);if(c){const t=new Ii;Jr.getBarycoord(Nn,En,Pn,Rn,t),r&&(c.uv=Jr.getInterpolatedAttribute(r,a,h,l,t,new Zs)),n&&(c.uv1=Jr.getInterpolatedAttribute(n,a,h,l,t,new Zs)),o&&(c.normal=Jr.getInterpolatedAttribute(o,a,h,l,t,new Ii),c.normal.dot(i.direction)>0&&c.normal.multiplyScalar(-1));const e={a:a,b:h,c:l,normal:new Ii,materialIndex:0};Jr.getNormal(En,Pn,Rn,e.normal),c.face=e,c.barycoord=t}return c}class jn extends zn{constructor(t=1,e=1,s=1,i=1,r=1,n=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,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=[],c=[];let u=0,d=0;function p(t,e,s,i,r,n,p,m,y,f,g){const x=n/y,b=p/f,v=n/2,w=p/2,M=m/2,S=y+1,_=f+1;let A=0,T=0;const z=new Ii;for(let n=0;n<_;n++){const o=n*b-w;for(let a=0;a0?1:-1,l.push(z.x,z.y,z.z),c.push(a/y),c.push(1-n/f),A+=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 s={};for(const t in this.extensions)!0===this.extensions[t]&&(s[t]=!0);return Object.keys(s).length>0&&(e.extensions=s),e}}class Xn extends Er{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new nr,this.projectionMatrix=new nr,this.projectionMatrixInverse=new nr,this.coordinateSystem=Os}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 Yn=new Ii,Zn=new Zs,Gn=new Zs;class $n extends Xn{constructor(t=50,e=1,s=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=t,this.zoom=1,this.near=s,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*js*Math.atan(e),this.updateProjectionMatrix()}getFocalLength(){const t=Math.tan(.5*Ws*this.fov);return.5*this.getFilmHeight()/t}getEffectiveFOV(){return 2*js*Math.atan(Math.tan(.5*Ws*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,s){Yn.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),e.set(Yn.x,Yn.y).multiplyScalar(-t/Yn.z),Yn.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),s.set(Yn.x,Yn.y).multiplyScalar(-t/Yn.z)}getViewSize(t,e){return this.getViewBounds(t,Zn,Gn),e.subVectors(Gn,Zn)}setViewOffset(t,e,s,i,r,n){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=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 t=this.near;let e=t*Math.tan(.5*Ws*this.fov)/this.zoom,s=2*e,i=this.aspect*s,r=-.5*i;const n=this.view;if(null!==this.view&&this.view.enabled){const t=n.fullWidth,o=n.fullHeight;r+=n.offsetX*i/t,e-=n.offsetY*s/o,i*=n.width/t,s*=n.height/o}const o=this.filmOffset;0!==o&&(r+=t*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,e,e-s,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 Qn=-90;class Kn extends Er{constructor(t,e,s){super(),this.type="CubeCamera",this.renderTarget=s,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new $n(Qn,1,t,e);i.layers=this.layers,this.add(i);const r=new $n(Qn,1,t,e);r.layers=this.layers,this.add(r);const n=new $n(Qn,1,t,e);n.layers=this.layers,this.add(n);const o=new $n(Qn,1,t,e);o.layers=this.layers,this.add(o);const a=new $n(Qn,1,t,e);a.layers=this.layers,this.add(a);const h=new $n(Qn,1,t,e);h.layers=this.layers,this.add(h)}updateCoordinateSystem(){const t=this.coordinateSystem,e=this.children.concat(),[s,i,r,n,o,a]=e;for(const t of e)this.remove(t);if(t===Os)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(t!==Fs)throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+t);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 t of e)this.add(t),t.updateMatrixWorld()}update(t,e){null===this.parent&&this.updateMatrixWorld();const{renderTarget:s,activeMipmapLevel:i}=this;this.coordinateSystem!==t.coordinateSystem&&(this.coordinateSystem=t.coordinateSystem,this.updateCoordinateSystem());const[r,n,o,a,h,l]=this.children,c=t.getRenderTarget(),u=t.getActiveCubeFace(),d=t.getActiveMipmapLevel(),p=t.xr.enabled;t.xr.enabled=!1;const m=s.texture.generateMipmaps;s.texture.generateMipmaps=!1,t.setRenderTarget(s,0,i),t.render(e,r),t.setRenderTarget(s,1,i),t.render(e,n),t.setRenderTarget(s,2,i),t.render(e,o),t.setRenderTarget(s,3,i),t.render(e,a),t.setRenderTarget(s,4,i),t.render(e,h),s.texture.generateMipmaps=m,t.setRenderTarget(s,5,i),t.render(e,l),t.setRenderTarget(c,u,d),t.xr.enabled=p,s.texture.needsPMREMUpdate=!0}}class to extends vi{constructor(t,e,s,i,r,n,o,a,h,l){super(t=void 0!==t?t:[],e=void 0!==e?e:ht,s,i,r,n,o,a,h,l),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}class eo extends Si{constructor(t=1,e={}){super(t,t,e),this.isWebGLCubeRenderTarget=!0;const s={width:t,height:t,depth:1},i=[s,s,s,s,s,s];this.texture=new to(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:wt}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 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 Jn({name:"CubemapFromEquirect",uniforms:Un(s.uniforms),vertexShader:s.vertexShader,fragmentShader:s.fragmentShader,side:1,blending:0});r.uniforms.tEquirect.value=e;const n=new Vn(i,r),o=e.minFilter;e.minFilter===_t&&(e.minFilter=wt);return new Kn(1,10,this).update(t,n),e.minFilter=o,n.geometry.dispose(),n.material.dispose(),this}clear(t,e,s,i){const r=t.getRenderTarget();for(let r=0;r<6;r++)t.setRenderTarget(this,r),t.clear(e,s,i);t.setRenderTarget(r)}}class so{constructor(t,e=25e-5){this.isFogExp2=!0,this.name="",this.color=new $r(t),this.density=e}clone(){return new so(this.color,this.density)}toJSON(){return{type:"FogExp2",name:this.name,color:this.color.getHex(),density:this.density}}}class io{constructor(t,e=1,s=1e3){this.isFog=!0,this.name="",this.color=new $r(t),this.near=e,this.far=s}clone(){return new io(this.color,this.near,this.far)}toJSON(){return{type:"Fog",name:this.name,color:this.color.getHex(),near:this.near,far:this.far}}}class ro extends Er{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 yr,this.environmentIntensity=1,this.environmentRotation=new yr,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 no{constructor(t,e){this.isInterleavedBuffer=!0,this.array=t,this.stride=e,this.count=void 0!==t?t.length/e:0,this.usage=_s,this.updateRanges=[],this.version=0,this.uuid=Us()}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,s){t*=this.stride,s*=e.stride;for(let i=0,r=this.stride;it.far||e.push({distance:a,point:co.clone(),uv:Jr.getInterpolation(co,go,xo,bo,vo,wo,Mo,new Zs),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 _o(t,e,s,i,r,n){mo.subVectors(t,s).addScalar(.5).multiply(i),void 0!==r?(yo.x=n*mo.x-r*mo.y,yo.y=r*mo.x+n*mo.y):yo.copy(mo),t.copy(e),t.x+=yo.x,t.y+=yo.y,t.applyMatrix4(fo)}const Ao=new Ii,To=new Ii;class zo extends Er{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,s=e.length;t0){let s,i;for(s=1,i=e.length;s0){Ao.setFromMatrixPosition(this.matrixWorld);const s=t.ray.origin.distanceTo(Ao);this.getObjectForDistance(s).raycast(t,e)}}update(t){const e=this.levels;if(e.length>1){Ao.setFromMatrixPosition(t.matrixWorld),To.setFromMatrixPosition(this.matrixWorld);const s=Ao.distanceTo(To)/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;i1?null:e.copy(t.start).addScaledVector(s,r)}intersectsLine(t){const e=this.distanceToPoint(t.start),s=this.distanceToPoint(t.end);return e<0&&s>0||s<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 s=e||ta.getNormalMatrix(t),i=this.coplanarPoint(Qo).applyMatrix4(t),r=this.normal.applyMatrix3(s).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 sa=new Gi,ia=new Ii;class ra{constructor(t=new ea,e=new ea,s=new ea,i=new ea,r=new ea,n=new ea){this.planes=[t,e,s,i,r,n]}set(t,e,s,i,r,n){const o=this.planes;return o[0].copy(t),o[1].copy(e),o[2].copy(s),o[3].copy(i),o[4].copy(r),o[5].copy(n),this}copy(t){const e=this.planes;for(let s=0;s<6;s++)e[s].copy(t.planes[s]);return this}setFromProjectionMatrix(t,e=2e3){const s=this.planes,i=t.elements,r=i[0],n=i[1],o=i[2],a=i[3],h=i[4],l=i[5],c=i[6],u=i[7],d=i[8],p=i[9],m=i[10],y=i[11],f=i[12],g=i[13],x=i[14],b=i[15];if(s[0].setComponents(a-r,u-h,y-d,b-f).normalize(),s[1].setComponents(a+r,u+h,y+d,b+f).normalize(),s[2].setComponents(a+n,u+l,y+p,b+g).normalize(),s[3].setComponents(a-n,u-l,y-p,b-g).normalize(),s[4].setComponents(a-o,u-c,y-m,b-x).normalize(),e===Os)s[5].setComponents(a+o,u+c,y+m,b+x).normalize();else{if(e!==Fs)throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+e);s[5].setComponents(o,c,m,x).normalize()}return this}intersectsObject(t){if(void 0!==t.boundingSphere)null===t.boundingSphere&&t.computeBoundingSphere(),sa.copy(t.boundingSphere).applyMatrix4(t.matrixWorld);else{const e=t.geometry;null===e.boundingSphere&&e.computeBoundingSphere(),sa.copy(e.boundingSphere).applyMatrix4(t.matrixWorld)}return this.intersectsSphere(sa)}intersectsSprite(t){return sa.center.set(0,0,0),sa.radius=.7071067811865476,sa.applyMatrix4(t.matrixWorld),this.intersectsSphere(sa)}intersectsSphere(t){const e=this.planes,s=t.center,i=-t.radius;for(let t=0;t<6;t++){if(e[t].distanceToPoint(s)0?t.max.x:t.min.x,ia.y=i.normal.y>0?t.max.y:t.min.y,ia.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(ia)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let s=0;s<6;s++)if(e[s].distanceToPoint(t)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function na(t,e){return t-e}function oa(t,e){return t.z-e.z}function aa(t,e){return e.z-t.z}class ha{constructor(){this.index=0,this.pool=[],this.list=[]}push(t,e,s,i){const r=this.pool,n=this.list;this.index>=r.length&&r.push({start:-1,count:-1,z:-1,index:-1});const o=r[this.index];n.push(o),this.index++,o.start=t,o.count=e,o.z=s,o.index=i}reset(){this.list.length=0,this.index=0}}const la=new nr,ca=new $r(1,1,1),ua=new ra,da=new Ei,pa=new Gi,ma=new Ii,ya=new Ii,fa=new Ii,ga=new ha,xa=new Vn,ba=[];function va(t,e,s=0){const i=e.itemSize;if(t.isInterleavedBufferAttribute||t.array.constructor!==e.array.constructor){const r=t.count;for(let n=0;n65535?new Uint32Array(i):new Uint16Array(i);e.setIndex(new cn(t,1))}this._geometryInitialized=!0}}_validateGeometry(t){const e=this.geometry;if(Boolean(t.getIndex())!==Boolean(e.getIndex()))throw new Error('THREE.BatchedMesh: All geometries must consistently have "index".');for(const s in e.attributes){if(!t.hasAttribute(s))throw new Error(`THREE.BatchedMesh: Added geometry missing "${s}". All geometries must have consistent attributes.`);const i=t.getAttribute(s),r=e.getAttribute(s);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("THREE.BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}validateInstanceId(t){const e=this._instanceInfo;if(t<0||t>=e.length||!1===e[t].active)throw new Error(`THREE.BatchedMesh: Invalid instanceId ${t}. Instance is either out of range or has been deleted.`)}validateGeometryId(t){const e=this._geometryInfo;if(t<0||t>=e.length||!1===e[t].active)throw new Error(`THREE.BatchedMesh: Invalid geometryId ${t}. Geometry is either out of range or has been deleted.`)}setCustomSort(t){return this.customSort=t,this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Ei);const t=this.boundingBox,e=this._instanceInfo;t.makeEmpty();for(let s=0,i=e.length;s=this.maxInstanceCount&&0===this._availableInstanceIds.length)throw new Error("THREE.BatchedMesh: Maximum item count reached.");const e={visible:!0,active:!0,geometryIndex:t};let s=null;this._availableInstanceIds.length>0?(this._availableInstanceIds.sort(na),s=this._availableInstanceIds.shift(),this._instanceInfo[s]=e):(s=this._instanceInfo.length,this._instanceInfo.push(e));const i=this._matricesTexture;la.identity().toArray(i.image.data,16*s),i.needsUpdate=!0;const r=this._colorsTexture;return r&&(ca.toArray(r.image.data,4*s),r.needsUpdate=!0),this._visibilityChanged=!0,s}addGeometry(t,e=-1,s=-1){this._initializeGeometry(t),this._validateGeometry(t);const i={vertexStart:-1,vertexCount:-1,reservedVertexCount:-1,indexStart:-1,indexCount:-1,reservedIndexCount:-1,start:-1,count:-1,boundingBox:null,boundingSphere:null,active:!0},r=this._geometryInfo;i.vertexStart=this._nextVertexStart,i.reservedVertexCount=-1===e?t.getAttribute("position").count:e;const n=t.getIndex();if(null!==n&&(i.indexStart=this._nextIndexStart,i.reservedIndexCount=-1===s?n.count:s),-1!==i.indexStart&&i.indexStart+i.reservedIndexCount>this._maxIndexCount||i.vertexStart+i.reservedVertexCount>this._maxVertexCount)throw new Error("THREE.BatchedMesh: Reserved space request exceeds the maximum buffer size.");let o;return this._availableGeometryIds.length>0?(this._availableGeometryIds.sort(na),o=this._availableGeometryIds.shift(),r[o]=i):(o=this._geometryCount,this._geometryCount++,r.push(i)),this.setGeometryAt(o,t),this._nextIndexStart=i.indexStart+i.reservedIndexCount,this._nextVertexStart=i.vertexStart+i.reservedVertexCount,o}setGeometryAt(t,e){if(t>=this._geometryCount)throw new Error("THREE.BatchedMesh: Maximum geometry count reached.");this._validateGeometry(e);const s=this.geometry,i=null!==s.getIndex(),r=s.getIndex(),n=e.getIndex(),o=this._geometryInfo[t];if(i&&n.count>o.reservedIndexCount||e.attributes.position.count>o.reservedVertexCount)throw new Error("THREE.BatchedMesh: Reserved space not large enough for provided geometry.");const a=o.vertexStart,h=o.reservedVertexCount;o.vertexCount=e.getAttribute("position").count;for(const t in s.attributes){const i=e.getAttribute(t),r=s.getAttribute(t);va(i,r,a);const n=i.itemSize;for(let t=i.count,e=h;t=e.length||!1===e[t].active)return this;const s=this._instanceInfo;for(let e=0,i=s.length;ee)).sort(((t,e)=>s[t].vertexStart-s[e].vertexStart)),r=this.geometry;for(let n=0,o=s.length;n=this._geometryCount)return null;const s=this.geometry,i=this._geometryInfo[t];if(null===i.boundingBox){const t=new Ei,e=s.index,r=s.attributes.position;for(let s=i.start,n=i.start+i.count;s=this._geometryCount)return null;const s=this.geometry,i=this._geometryInfo[t];if(null===i.boundingSphere){const e=new Gi;this.getBoundingBoxAt(t,da),da.getCenter(e.center);const r=s.index,n=s.attributes.position;let o=0;for(let t=i.start,s=i.start+i.count;tt.active));if(Math.max(...s.map((t=>t.vertexStart+t.reservedVertexCount)))>t)throw new Error(`BatchedMesh: Geometry vertex values are being used outside the range ${e}. Cannot shrink further.`);if(this.geometry.index){if(Math.max(...s.map((t=>t.indexStart+t.reservedIndexCount)))>e)throw new Error(`BatchedMesh: Geometry index values are being used outside the range ${e}. Cannot shrink further.`)}const i=this.geometry;i.dispose(),this._maxVertexCount=t,this._maxIndexCount=e,this._geometryInitialized&&(this._geometryInitialized=!1,this.geometry=new zn,this._initializeGeometry(i));const r=this.geometry;i.index&&wa(i.index.array,r.index.array);for(const t in i.attributes)wa(i.attributes[t].array,r.attributes[t].array)}raycast(t,e){const s=this._instanceInfo,i=this._geometryInfo,r=this.matrixWorld,n=this.geometry;xa.material=this.material,xa.geometry.index=n.index,xa.geometry.attributes=n.attributes,null===xa.geometry.boundingBox&&(xa.geometry.boundingBox=new Ei),null===xa.geometry.boundingSphere&&(xa.geometry.boundingSphere=new Gi);for(let n=0,o=s.length;n({...t,boundingBox:null!==t.boundingBox?t.boundingBox.clone():null,boundingSphere:null!==t.boundingSphere?t.boundingSphere.clone():null}))),this._instanceInfo=t._instanceInfo.map((t=>({...t}))),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,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._instanceInfo,h=this._multiDrawStarts,l=this._multiDrawCounts,c=this._geometryInfo,u=this.perObjectFrustumCulled,d=this._indirectTexture,p=d.image.data;u&&(la.multiplyMatrices(s.projectionMatrix,s.matrixWorldInverse).multiply(this.matrixWorld),ua.setFromProjectionMatrix(la,t.coordinateSystem));let m=0;if(this.sortObjects){la.copy(this.matrixWorld).invert(),ma.setFromMatrixPosition(s.matrixWorld).applyMatrix4(la),ya.set(0,0,-1).transformDirection(s.matrixWorld).transformDirection(la);for(let t=0,e=a.length;t0){const s=t[e[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=s.length;ti)return;Ia.applyMatrix4(t.matrixWorld);const a=e.ray.origin.distanceTo(Ia);return ae.far?void 0:{distance:a,point:Ba.clone().applyMatrix4(t.matrixWorld),index:r,face:null,faceIndex:null,barycoord:null,object:t}}const Pa=new Ii,Ra=new Ii;class Oa extends ka{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,s=[];for(let t=0,i=e.count;t0){const s=t[e[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=s.length;tr.far)return;n.push({distance:h,distanceToRay:Math.sqrt(a),point:s,index:e,face:null,faceIndex:null,barycoord:null,object:o})}}class Ha extends Er{constructor(){super(),this.isGroup=!0,this.type="Group"}}class qa extends vi{constructor(t,e,s,i,r,n,o,a,h){super(t,e,s,i,r,n,o,a,h),this.isVideoTexture=!0,this.minFilter=void 0!==n?n:wt,this.magFilter=void 0!==r?r:wt,this.generateMipmaps=!1;const l=this;"requestVideoFrameCallback"in t&&t.requestVideoFrameCallback((function e(){l.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 Ja extends vi{constructor(t,e){super({width:t,height:e}),this.isFramebufferTexture=!0,this.magFilter=ft,this.minFilter=ft,this.generateMipmaps=!1,this.needsUpdate=!0}}class Xa extends vi{constructor(t,e,s,i,r,n,o,a,h,l,c,u){super(null,n,o,a,h,l,i,r,c,u),this.isCompressedTexture=!0,this.image={width:e,height:s},this.mipmaps=t,this.flipY=!1,this.generateMipmaps=!1}}class Ya extends Xa{constructor(t,e,s,i,r,n){super(t,e,s,r,n),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 Za extends Xa{constructor(t,e,s){super(void 0,t[0].width,t[0].height,e,s,ht),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=t}}class Ga extends vi{constructor(t,e,s,i,r,n,o,a,h){super(t,e,s,i,r,n,o,a,h),this.isCanvasTexture=!0,this.needsUpdate=!0}}class $a extends vi{constructor(t,e,s,i,r,n,o,a,h,l=1026){if(l!==Dt&&l!==Ht)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===s&&l===Dt&&(s=kt),void 0===s&&l===Ht&&(s=1020),super(null,i,r,n,o,a,l,s,h),this.isDepthTexture=!0,this.image={width:t,height:e},this.magFilter=void 0!==o?o:ft,this.minFilter=void 0!==a?a:ft,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(t){return super.copy(t),this.compareFunction=t.compareFunction,this}toJSON(t){const e=super.toJSON(t);return null!==this.compareFunction&&(e.compareFunction=this.compareFunction),e}}class Qa{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(t,e){const s=this.getUtoTmapping(t);return this.getPoint(s,e)}getPoints(t=5){const e=[];for(let s=0;s<=t;s++)e.push(this.getPoint(s/t));return e}getSpacedPoints(t=5){const e=[];for(let s=0;s<=t;s++)e.push(this.getPointAt(s/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 s,i=this.getPoint(0),r=0;e.push(0);for(let n=1;n<=t;n++)s=this.getPoint(n/t),r+=s.distanceTo(i),e.push(r),i=s;return this.cacheArcLengths=e,e}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(t,e){const s=this.getLengths();let i=0;const r=s.length;let n;n=e||t*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(t,e){const s=1e-4;let i=t-s,r=t+s;i<0&&(i=0),r>1&&(r=1);const n=this.getPoint(i),o=this.getPoint(r),a=e||(n.isVector2?new Zs:new Ii);return a.copy(o).sub(n).normalize(),a}getTangentAt(t,e){const s=this.getUtoTmapping(t);return this.getTangent(s,e)}computeFrenetFrames(t,e){const s=new Ii,i=[],r=[],n=[],o=new Ii,a=new nr;for(let e=0;e<=t;e++){const s=e/t;i[e]=this.getTangentAt(s,new Ii)}r[0]=new Ii,n[0]=new Ii;let h=Number.MAX_VALUE;const l=Math.abs(i[0].x),c=Math.abs(i[0].y),u=Math.abs(i[0].z);l<=h&&(h=l,s.set(1,0,0)),c<=h&&(h=c,s.set(0,1,0)),u<=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 e=1;e<=t;e++){if(r[e]=r[e-1].clone(),n[e]=n[e-1].clone(),o.crossVectors(i[e-1],i[e]),o.length()>Number.EPSILON){o.normalize();const t=Math.acos(Ds(i[e-1].dot(i[e]),-1,1));r[e].applyMatrix4(a.makeRotationAxis(o,t))}n[e].crossVectors(i[e],r[e])}if(!0===e){let e=Math.acos(Ds(r[0].dot(r[t]),-1,1));e/=t,i[0].dot(o.crossVectors(r[0],r[t]))>0&&(e=-e);for(let s=1;s<=t;s++)r[s].applyMatrix4(a.makeRotationAxis(i[s],e*s)),n[s].crossVectors(i[s],r[s])}return{tangents:i,normals:r,binormals:n}}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 Ka extends Qa{constructor(t=0,e=0,s=1,i=1,r=0,n=2*Math.PI,o=!1,a=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=s,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=n,this.aClockwise=o,this.aRotation=a}getPoint(t,e=new Zs){const s=e,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]:(sh.subVectors(i[0],i[1]).add(i[0]),o=sh);const c=i[h%r],u=i[(h+1)%r];if(this.closed||h+2i.length-2?i.length-1:n+1],c=i[n>i.length-3?i.length-1:n+2];return s.set(ah(o,a.x,h.x,l.x,c.x),ah(o,a.y,h.y,l.y,c.y)),s}copy(t){super.copy(t),this.points=[];for(let e=0,s=t.points.length;e=s){const t=i[r]-s,n=this.curves[r],o=n.getLength(),a=0===o?0:1-t/o;return n.getPointAt(a,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 s=0,i=this.curves.length;s1&&!e[e.length-1].equals(e[0])&&e.push(e[0]),e}copy(t){super.copy(t),this.curves=[];for(let e=0,s=t.curves.length;e0){const t=h.getPoint(0);t.equals(this.currentPoint)||this.lineTo(t.x,t.y)}this.curves.push(h);const l=h.getPoint(1);return this.currentPoint.copy(l),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 vh extends zn{constructor(t=[new Zs(0,-.5),new Zs(.5,0),new Zs(0,.5)],e=12,s=0,i=2*Math.PI){super(),this.type="LatheGeometry",this.parameters={points:t,segments:e,phiStart:s,phiLength:i},e=Math.floor(e),i=Ds(i,0,2*Math.PI);const r=[],n=[],o=[],a=[],h=[],l=1/e,c=new Ii,u=new Zs,d=new Ii,p=new Ii,m=new Ii;let y=0,f=0;for(let e=0;e<=t.length-1;e++)switch(e){case 0:y=t[e+1].x-t[e].x,f=t[e+1].y-t[e].y,d.x=1*f,d.y=-y,d.z=0*f,m.copy(d),d.normalize(),a.push(d.x,d.y,d.z);break;case t.length-1:a.push(m.x,m.y,m.z);break;default:y=t[e+1].x-t[e].x,f=t[e+1].y-t[e].y,d.x=1*f,d.y=-y,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<=e;r++){const d=s+r*l*i,p=Math.sin(d),m=Math.cos(d);for(let s=0;s<=t.length-1;s++){c.x=t[s].x*p,c.y=t[s].y,c.z=t[s].x*m,n.push(c.x,c.y,c.z),u.x=r/e,u.y=s/(t.length-1),o.push(u.x,u.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||0!==i)&&(l.push(n,o,h),x+=3),(e>0||i!==r-1)&&(l.push(o,a,h),x+=3)}h.addGroup(f,x,0),f+=x}(),!1===n&&(t>0&&g(!0),e>0&&g(!1)),this.setIndex(l),this.setAttribute("position",new bn(c,3)),this.setAttribute("normal",new bn(u,3)),this.setAttribute("uv",new bn(d,2))}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new Sh(t.radiusTop,t.radiusBottom,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class _h extends Sh{constructor(t=1,e=1,s=32,i=1,r=!1,n=0,o=2*Math.PI){super(0,t,e,s,i,r,n,o),this.type="ConeGeometry",this.parameters={radius:t,height:e,radialSegments:s,heightSegments:i,openEnded:r,thetaStart:n,thetaLength:o}}static fromJSON(t){return new _h(t.radius,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class Ah extends zn{constructor(t=[],e=[],s=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:t,indices:e,radius:s,detail:i};const r=[],n=[];function o(t,e,s,i){const r=i+1,n=[];for(let i=0;i<=r;i++){n[i]=[];const o=t.clone().lerp(s,i/r),a=e.clone().lerp(s,i/r),h=r-i;for(let t=0;t<=h;t++)n[i][t]=0===t&&i===r?o:o.clone().lerp(a,t/h)}for(let t=0;t.9&&o<.1&&(e<.2&&(n[t+0]+=1),s<.2&&(n[t+2]+=1),i<.2&&(n[t+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(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new Ah(t.vertices,t.indices,t.radius,t.details)}}class Th extends Ah{constructor(t=1,e=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],t,e),this.type="DodecahedronGeometry",this.parameters={radius:t,detail:e}}static fromJSON(t){return new Th(t.radius,t.detail)}}const zh=new Ii,Ch=new Ii,Ih=new Ii,Bh=new Jr;class kh extends zn{constructor(t=null,e=1){if(super(),this.type="EdgesGeometry",this.parameters={geometry:t,thresholdAngle:e},null!==t){const s=4,i=Math.pow(10,s),r=Math.cos(Ws*e),n=t.getIndex(),o=t.getAttribute("position"),a=n?n.count:o.count,h=[0,0,0],l=["a","b","c"],c=new Array(3),u={},d=[];for(let t=0;t80*s){a=l=t[0],h=c=t[1];for(let e=s;el&&(l=u),d>c&&(c=d);p=Math.max(l-a,c-h),p=0!==p?32767/p:0}return Fh(n,o,s,a,h,p,0),o};function Rh(t,e,s,i,r){let n,o;if(r===function(t,e,s,i){let r=0;for(let n=e,o=s-i;n0)for(n=e;n=e;n-=i)o=el(n,t[n],t[n+1],o);return o&&Zh(o,o.next)&&(sl(o),o=o.next),o}function Oh(t,e){if(!t)return t;e||(e=t);let s,i=t;do{if(s=!1,i.steiner||!Zh(i,i.next)&&0!==Yh(i.prev,i,i.next))i=i.next;else{if(sl(i),i=e=i.prev,i===i.next)break;s=!0}}while(s||i!==e);return e}function Fh(t,e,s,i,r,n,o){if(!t)return;!o&&n&&function(t,e,s,i){let r=t;do{0===r.z&&(r.z=Hh(r.x,r.y,e,s,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,s,i,r,n,o,a,h,l=1;do{for(s=t,t=null,n=null,o=0;s;){for(o++,i=s,a=0,e=0;e0||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:t=r,r.prevZ=n,n=r;s=i}n.nextZ=null,l*=2}while(o>1)}(r)}(t,i,r,n);let a,h,l=t;for(;t.prev!==t.next;)if(a=t.prev,h=t.next,n?Lh(t,i,r,n):Nh(t))e.push(a.i/s|0),e.push(t.i/s|0),e.push(h.i/s|0),sl(t),t=h.next,l=h.next;else if((t=h)===l){o?1===o?Fh(t=Vh(Oh(t),e,s),e,s,i,r,n,2):2===o&&Wh(t,e,s,i,r,n):Fh(Oh(t),e,s,i,r,n,1);break}}function Nh(t){const e=t.prev,s=t,i=t.next;if(Yh(e,s,i)>=0)return!1;const r=e.x,n=s.x,o=i.x,a=e.y,h=s.y,l=i.y,c=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!==e;){if(m.x>=c&&m.x<=d&&m.y>=u&&m.y<=p&&Jh(r,a,n,h,o,l,m.x,m.y)&&Yh(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function Lh(t,e,s,i){const r=t.prev,n=t,o=t.next;if(Yh(r,n,o)>=0)return!1;const a=r.x,h=n.x,l=o.x,c=r.y,u=n.y,d=o.y,p=ah?a>l?a:l:h>l?h:l,f=c>u?c>d?c:d:u>d?u:d,g=Hh(p,m,e,s,i),x=Hh(y,f,e,s,i);let b=t.prevZ,v=t.nextZ;for(;b&&b.z>=g&&v&&v.z<=x;){if(b.x>=p&&b.x<=y&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&Jh(a,c,h,u,l,d,b.x,b.y)&&Yh(b.prev,b,b.next)>=0)return!1;if(b=b.prevZ,v.x>=p&&v.x<=y&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&Jh(a,c,h,u,l,d,v.x,v.y)&&Yh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}for(;b&&b.z>=g;){if(b.x>=p&&b.x<=y&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&Jh(a,c,h,u,l,d,b.x,b.y)&&Yh(b.prev,b,b.next)>=0)return!1;b=b.prevZ}for(;v&&v.z<=x;){if(v.x>=p&&v.x<=y&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&Jh(a,c,h,u,l,d,v.x,v.y)&&Yh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}return!0}function Vh(t,e,s){let i=t;do{const r=i.prev,n=i.next.next;!Zh(r,n)&&Gh(r,i,i.next,n)&&Kh(r,n)&&Kh(n,r)&&(e.push(r.i/s|0),e.push(i.i/s|0),e.push(n.i/s|0),sl(i),sl(i.next),i=t=n),i=i.next}while(i!==t);return Oh(i)}function Wh(t,e,s,i,r,n){let o=t;do{let t=o.next.next;for(;t!==o.prev;){if(o.i!==t.i&&Xh(o,t)){let a=tl(o,t);return o=Oh(o,o.next),a=Oh(a,a.next),Fh(o,e,s,i,r,n,0),void Fh(a,e,s,i,r,n,0)}t=t.next}o=o.next}while(o!==t)}function jh(t,e){return t.x-e.x}function Uh(t,e){const s=function(t,e){let s,i=e,r=-1/0;const n=t.x,o=t.y;do{if(o<=i.y&&o>=i.next.y&&i.next.y!==i.y){const t=i.x+(o-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(t<=n&&t>r&&(r=t,s=i.x=i.x&&i.x>=h&&n!==i.x&&Jh(os.x||i.x===s.x&&Dh(s,i)))&&(s=i,u=c)),i=i.next}while(i!==a);return s}(t,e);if(!s)return e;const i=tl(s,t);return Oh(i,i.next),Oh(s,s.next)}function Dh(t,e){return Yh(t.prev,t,e.prev)<0&&Yh(e.next,t,t.next)<0}function Hh(t,e,s,i,r){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-s)*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 qh(t){let e=t,s=t;do{(e.x=(t-o)*(n-a)&&(t-o)*(i-a)>=(s-o)*(e-a)&&(s-o)*(n-a)>=(r-o)*(i-a)}function Xh(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let s=t;do{if(s.i!==t.i&&s.next.i!==t.i&&s.i!==e.i&&s.next.i!==e.i&&Gh(s,s.next,t,e))return!0;s=s.next}while(s!==t);return!1}(t,e)&&(Kh(t,e)&&Kh(e,t)&&function(t,e){let s=t,i=!1;const r=(t.x+e.x)/2,n=(t.y+e.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!==t);return i}(t,e)&&(Yh(t.prev,t,e.prev)||Yh(t,e.prev,e))||Zh(t,e)&&Yh(t.prev,t,t.next)>0&&Yh(e.prev,e,e.next)>0)}function Yh(t,e,s){return(e.y-t.y)*(s.x-e.x)-(e.x-t.x)*(s.y-e.y)}function Zh(t,e){return t.x===e.x&&t.y===e.y}function Gh(t,e,s,i){const r=Qh(Yh(t,e,s)),n=Qh(Yh(t,e,i)),o=Qh(Yh(s,i,t)),a=Qh(Yh(s,i,e));return r!==n&&o!==a||(!(0!==r||!$h(t,s,e))||(!(0!==n||!$h(t,i,e))||(!(0!==o||!$h(s,t,i))||!(0!==a||!$h(s,e,i)))))}function $h(t,e,s){return e.x<=Math.max(t.x,s.x)&&e.x>=Math.min(t.x,s.x)&&e.y<=Math.max(t.y,s.y)&&e.y>=Math.min(t.y,s.y)}function Qh(t){return t>0?1:t<0?-1:0}function Kh(t,e){return Yh(t.prev,t,t.next)<0?Yh(t,e,t.next)>=0&&Yh(t,t.prev,e)>=0:Yh(t,e,t.prev)<0||Yh(t,t.next,e)<0}function tl(t,e){const s=new il(t.i,t.x,t.y),i=new il(e.i,e.x,e.y),r=t.next,n=e.prev;return t.next=e,e.prev=t,s.next=r,r.prev=s,i.next=s,s.prev=i,n.next=i,i.prev=n,i}function el(t,e,s,i){const r=new il(t,e,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 sl(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 il(t,e,s){this.i=t,this.x=e,this.y=s,this.prev=null,this.next=null,this.z=0,this.prevZ=null,this.nextZ=null,this.steiner=!1}class rl{static area(t){const e=t.length;let s=0;for(let i=e-1,r=0;r2&&t[e-1].equals(t[0])&&t.pop()}function ol(t,e){for(let s=0;sNumber.EPSILON){const u=Math.sqrt(c),d=Math.sqrt(h*h+l*l),p=e.x-a/u,m=e.y+o/u,y=((s.x-l/d-p)*l-(s.y+h/d-m)*h)/(o*l-a*h);i=p+o*y-t.x,r=m+a*y-t.y;const f=i*i+r*r;if(f<=2)return new Zs(i,r);n=Math.sqrt(f/2)}else{let t=!1;o>Number.EPSILON?h>Number.EPSILON&&(t=!0):o<-Number.EPSILON?h<-Number.EPSILON&&(t=!0):Math.sign(a)===Math.sign(l)&&(t=!0),t?(i=-a,r=o,n=Math.sqrt(c)):(i=o,r=a,n=Math.sqrt(c/2))}return new Zs(i/n,r/n)}const k=[];for(let t=0,e=T.length,s=e-1,i=t+1;t=0;t--){const e=t/p,s=c*Math.cos(e*Math.PI/2),i=u*Math.sin(e*Math.PI/2)+d;for(let t=0,e=T.length;t=0;){const i=s;let r=s-1;r<0&&(r=t.length-1);for(let t=0,s=a+2*p;t0)&&d.push(e,r,h),(t!==s-1||a0!=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 Tl extends tn{constructor(t){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new $r(16777215),this.specular=new $r(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new $r(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new yr,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(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 zl extends tn{constructor(t){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new $r(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new $r(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(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 Cl extends tn{constructor(t){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(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 Il extends tn{constructor(t){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new $r(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new $r(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new yr,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(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 Bl extends tn{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 tn{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}}class El extends tn{constructor(t){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new $r(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(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 Pl extends Sa{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 Rl(t,e,s){return!t||!s&&t.constructor===e?t:"number"==typeof e.BYTES_PER_ELEMENT?new e(t):Array.prototype.slice.call(t)}function Ol(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function Fl(t){const e=t.length,s=new Array(e);for(let t=0;t!==e;++t)s[t]=t;return s.sort((function(e,s){return t[e]-t[s]})),s}function Nl(t,e,s){const i=t.length,r=new t.constructor(i);for(let n=0,o=0;o!==i;++n){const i=s[n]*e;for(let s=0;s!==e;++s)r[o++]=t[i+s]}return r}function Ll(t,e,s,i){let r=1,n=t[0];for(;void 0!==n&&void 0===n[i];)n=t[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&&(e.push(n.time),s.push.apply(s,o)),n=t[r++]}while(void 0!==n);else if(void 0!==o.toArray)do{o=n[i],void 0!==o&&(e.push(n.time),o.toArray(s,s.length)),n=t[r++]}while(void 0!==n);else do{o=n[i],void 0!==o&&(e.push(n.time),s.push(o)),n=t[r++]}while(void 0!==n)}const Vl={convertArray:Rl,isTypedArray:Ol,getKeyframeOrder:Fl,sortedArray:Nl,flattenJSON:Ll,subclip:function(t,e,s,i,r=30){const n=t.clone();n.name=e;const o=[];for(let t=0;t=i)){h.push(e.times[t]);for(let s=0;sn.tracks[t].times[0]&&(a=n.tracks[t].times[0]);for(let t=0;t=i.times[u]){const t=u*h+a,e=t+h-a;d=i.values.slice(t,e)}else{const t=i.createInterpolant(),e=a,s=h-a;t.evaluate(n),d=t.resultBuffer.slice(e,s)}if("quaternion"===r){(new Ci).fromArray(d).normalize().conjugate().toArray(d)}const p=o.times.length;for(let t=0;t=r)break t;{const o=e[1];t=r)break e}n=s,s=0}}for(;s>>1;te;)--n;if(++n,0!==r||n!==i){r>=n&&(n=Math.max(n,1),r=n-1);const t=this.getValueSize();this.times=s.slice(r,n),this.values=this.values.slice(r*t,n*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 s=this.times,i=this.values,r=s.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),t=!1);let n=null;for(let e=0;e!==r;e++){const i=s[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!==n&&n>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,e,i,n),t=!1;break}n=i}if(void 0!==i&&Ol(i))for(let e=0,s=i.length;e!==s;++e){const s=i[e];if(isNaN(s)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,e,s),t=!1;break}}return t}optimize(){const t=this.times.slice(),e=this.values.slice(),s=this.getValueSize(),i=this.getInterpolation()===Re,r=t.length-1;let n=1;for(let o=1;o0){t[n]=t[r];for(let t=r*s,i=n*s,o=0;o!==s;++o)e[i+o]=e[t+o];++n}return n!==t.length?(this.times=t.slice(0,n),this.values=e.slice(0,n*s)):(this.times=t,this.values=e),this}clone(){const t=this.times.slice(),e=this.values.slice(),s=new(0,this.constructor)(this.name,t,e);return s.createInterpolant=this.createInterpolant,s}}Hl.prototype.TimeBufferType=Float32Array,Hl.prototype.ValueBufferType=Float32Array,Hl.prototype.DefaultInterpolation=Pe;class ql extends Hl{constructor(t,e,s){super(t,e,s)}}ql.prototype.ValueTypeName="bool",ql.prototype.ValueBufferType=Array,ql.prototype.DefaultInterpolation=Ee,ql.prototype.InterpolantFactoryMethodLinear=void 0,ql.prototype.InterpolantFactoryMethodSmooth=void 0;class Jl extends Hl{}Jl.prototype.ValueTypeName="color";class Xl extends Hl{}Xl.prototype.ValueTypeName="number";class Yl extends Wl{constructor(t,e,s,i){super(t,e,s,i)}interpolate_(t,e,s,i){const r=this.resultBuffer,n=this.sampleValues,o=this.valueSize,a=(s-e)/(i-e);let h=t*o;for(let t=h+o;h!==t;h+=4)Ci.slerpFlat(r,0,n,h-o,n,h,a);return r}}class Zl extends Hl{InterpolantFactoryMethodLinear(t){return new Yl(this.times,this.values,this.getValueSize(),t)}}Zl.prototype.ValueTypeName="quaternion",Zl.prototype.InterpolantFactoryMethodSmooth=void 0;class Gl extends Hl{constructor(t,e,s){super(t,e,s)}}Gl.prototype.ValueTypeName="string",Gl.prototype.ValueBufferType=Array,Gl.prototype.DefaultInterpolation=Ee,Gl.prototype.InterpolantFactoryMethodLinear=void 0,Gl.prototype.InterpolantFactoryMethodSmooth=void 0;class $l extends Hl{}$l.prototype.ValueTypeName="vector";class Ql{constructor(t="",e=-1,s=[],i=2500){this.name=t,this.tracks=s,this.duration=e,this.blendMode=i,this.uuid=Us(),this.duration<0&&this.resetDuration()}static parse(t){const e=[],s=t.tracks,i=1/(t.fps||1);for(let t=0,r=s.length;t!==r;++t)e.push(Kl(s[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=[],s=t.tracks,i={name:t.name,duration:t.duration,tracks:e,uuid:t.uuid,blendMode:t.blendMode};for(let t=0,i=s.length;t!==i;++t)e.push(Hl.toJSON(s[t]));return i}static CreateFromMorphTargetSequence(t,e,s,i){const r=e.length,n=[];for(let t=0;t1){const t=n[1];let e=i[t];e||(i[t]=e=[]),e.push(s)}}const n=[];for(const t in i)n.push(this.CreateFromMorphTargetSequence(t,i[t],e,s));return n}static parseAnimation(t,e){if(!t)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const s=function(t,e,s,i,r){if(0!==s.length){const n=[],o=[];Ll(s,n,o,i),0!==n.length&&r.push(new t(e,n,o))}},i=[],r=t.name||"default",n=t.fps||30,o=t.blendMode;let a=t.length||-1;const h=t.hierarchy||[];for(let t=0;t{e&&e(r),this.manager.itemEnd(t)}),0),r;if(void 0!==rc[t])return void rc[t].push({onLoad:e,onProgress:s,onError:i});rc[t]=[],rc[t].push({onLoad:e,onProgress:s,onError:i});const n=new Request(t,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),o=this.mimeType,a=this.responseType;fetch(n).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 s=rc[t],i=e.body.getReader(),r=e.headers.get("X-File-Size")||e.headers.get("Content-Length"),n=r?parseInt(r):0,o=0!==n;let a=0;const h=new ReadableStream({start(t){!function e(){i.read().then((({done:i,value:r})=>{if(i)t.close();else{a+=r.byteLength;const i=new ProgressEvent("progress",{lengthComputable:o,loaded:a,total:n});for(let t=0,e=s.length;t{t.error(e)}))}()}});return new Response(h)}throw new nc(`fetch for "${e.url}" responded with ${e.status}: ${e.statusText}`,e)})).then((t=>{switch(a){case"arraybuffer":return t.arrayBuffer();case"blob":return t.blob();case"document":return t.text().then((t=>(new DOMParser).parseFromString(t,o)));case"json":return t.json();default:if(void 0===o)return t.text();{const e=/charset="?([^;"\s]*)"?/i.exec(o),s=e&&e[1]?e[1].toLowerCase():void 0,i=new TextDecoder(s);return t.arrayBuffer().then((t=>i.decode(t)))}}})).then((e=>{tc.add(t,e);const s=rc[t];delete rc[t];for(let t=0,i=s.length;t{const s=rc[t];if(void 0===s)throw this.manager.itemError(t),e;delete rc[t];for(let t=0,i=s.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 ac extends ic{constructor(t){super(t)}load(t,e,s,i){const r=this,n=new oc(this.manager);n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(t,(function(s){try{e(r.parse(JSON.parse(s)))}catch(e){i?i(e):console.error(e),r.manager.itemError(t)}}),s,i)}parse(t){const e=[];for(let s=0;s0: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=s(r.value);break;case"c":i.uniforms[e].value=(new $r).setHex(r.value);break;case"v2":i.uniforms[e].value=(new Zs).fromArray(r.value);break;case"v3":i.uniforms[e].value=(new Ii).fromArray(r.value);break;case"v4":i.uniforms[e].value=(new wi).fromArray(r.value);break;case"m3":i.uniforms[e].value=(new Gs).fromArray(r.value);break;case"m4":i.uniforms[e].value=(new nr).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=s(t.map)),void 0!==t.matcap&&(i.matcap=s(t.matcap)),void 0!==t.alphaMap&&(i.alphaMap=s(t.alphaMap)),void 0!==t.bumpMap&&(i.bumpMap=s(t.bumpMap)),void 0!==t.bumpScale&&(i.bumpScale=t.bumpScale),void 0!==t.normalMap&&(i.normalMap=s(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 Zs).fromArray(e)}return void 0!==t.displacementMap&&(i.displacementMap=s(t.displacementMap)),void 0!==t.displacementScale&&(i.displacementScale=t.displacementScale),void 0!==t.displacementBias&&(i.displacementBias=t.displacementBias),void 0!==t.roughnessMap&&(i.roughnessMap=s(t.roughnessMap)),void 0!==t.metalnessMap&&(i.metalnessMap=s(t.metalnessMap)),void 0!==t.emissiveMap&&(i.emissiveMap=s(t.emissiveMap)),void 0!==t.emissiveIntensity&&(i.emissiveIntensity=t.emissiveIntensity),void 0!==t.specularMap&&(i.specularMap=s(t.specularMap)),void 0!==t.specularIntensityMap&&(i.specularIntensityMap=s(t.specularIntensityMap)),void 0!==t.specularColorMap&&(i.specularColorMap=s(t.specularColorMap)),void 0!==t.envMap&&(i.envMap=s(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=s(t.lightMap)),void 0!==t.lightMapIntensity&&(i.lightMapIntensity=t.lightMapIntensity),void 0!==t.aoMap&&(i.aoMap=s(t.aoMap)),void 0!==t.aoMapIntensity&&(i.aoMapIntensity=t.aoMapIntensity),void 0!==t.gradientMap&&(i.gradientMap=s(t.gradientMap)),void 0!==t.clearcoatMap&&(i.clearcoatMap=s(t.clearcoatMap)),void 0!==t.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=s(t.clearcoatRoughnessMap)),void 0!==t.clearcoatNormalMap&&(i.clearcoatNormalMap=s(t.clearcoatNormalMap)),void 0!==t.clearcoatNormalScale&&(i.clearcoatNormalScale=(new Zs).fromArray(t.clearcoatNormalScale)),void 0!==t.iridescenceMap&&(i.iridescenceMap=s(t.iridescenceMap)),void 0!==t.iridescenceThicknessMap&&(i.iridescenceThicknessMap=s(t.iridescenceThicknessMap)),void 0!==t.transmissionMap&&(i.transmissionMap=s(t.transmissionMap)),void 0!==t.thicknessMap&&(i.thicknessMap=s(t.thicknessMap)),void 0!==t.anisotropyMap&&(i.anisotropyMap=s(t.anisotropyMap)),void 0!==t.sheenColorMap&&(i.sheenColorMap=s(t.sheenColorMap)),void 0!==t.sheenRoughnessMap&&(i.sheenRoughnessMap=s(t.sheenRoughnessMap)),i}setTextures(t){return this.textures=t,this}createMaterialFromType(t){return Pc.createMaterialFromType(t)}static createMaterialFromType(t){return new{ShadowMaterial:Ml,SpriteMaterial:ho,RawShaderMaterial:Sl,ShaderMaterial:Jn,PointsMaterial:Na,MeshPhysicalMaterial:Al,MeshStandardMaterial:_l,MeshPhongMaterial:Tl,MeshToonMaterial:zl,MeshNormalMaterial:Cl,MeshLambertMaterial:Il,MeshDepthMaterial:Bl,MeshDistanceMaterial:kl,MeshBasicMaterial:en,MeshMatcapMaterial:El,LineDashedMaterial:Pl,LineBasicMaterial:Sa,Material:tn}[t]}}class Rc{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 s=0,i=t.length;s0){const s=new ec(e);r=new lc(s),r.setCrossOrigin(this.crossOrigin);for(let e=0,s=t.length;e0){i=new lc(this.manager),i.setCrossOrigin(this.crossOrigin);for(let e=0,i=t.length;e{const e=new Ei;e.min.fromArray(t.boxMin),e.max.fromArray(t.boxMax);const s=new Gi;return s.radius=t.sphereRadius,s.center.fromArray(t.sphereCenter),{boxInitialized:t.boxInitialized,box:e,sphereInitialized:t.sphereInitialized,sphere:s}})),n._maxInstanceCount=t.maxInstanceCount,n._maxVertexCount=t.maxVertexCount,n._maxIndexCount=t.maxIndexCount,n._geometryInitialized=t.geometryInitialized,n._geometryCount=t.geometryCount,n._matricesTexture=c(t.matricesTexture.uuid),void 0!==t.colorsTexture&&(n._colorsTexture=c(t.colorsTexture.uuid));break;case"LOD":n=new zo;break;case"Line":n=new ka(h(t.geometry),l(t.material));break;case"LineLoop":n=new Fa(h(t.geometry),l(t.material));break;case"LineSegments":n=new Oa(h(t.geometry),l(t.material));break;case"PointCloud":case"Points":n=new Ua(h(t.geometry),l(t.material));break;case"Sprite":n=new So(l(t.material));break;case"Group":n=new Ha;break;case"Bone":n=new Lo;break;default:n=new Er}if(n.uuid=t.uuid,void 0!==t.name&&(n.name=t.name),void 0!==t.matrix?(n.matrix.fromArray(t.matrix),void 0!==t.matrixAutoUpdate&&(n.matrixAutoUpdate=t.matrixAutoUpdate),n.matrixAutoUpdate&&n.matrix.decompose(n.position,n.quaternion,n.scale)):(void 0!==t.position&&n.position.fromArray(t.position),void 0!==t.rotation&&n.rotation.fromArray(t.rotation),void 0!==t.quaternion&&n.quaternion.fromArray(t.quaternion),void 0!==t.scale&&n.scale.fromArray(t.scale)),void 0!==t.up&&n.up.fromArray(t.up),void 0!==t.castShadow&&(n.castShadow=t.castShadow),void 0!==t.receiveShadow&&(n.receiveShadow=t.receiveShadow),t.shadow&&(void 0!==t.shadow.intensity&&(n.shadow.intensity=t.shadow.intensity),void 0!==t.shadow.bias&&(n.shadow.bias=t.shadow.bias),void 0!==t.shadow.normalBias&&(n.shadow.normalBias=t.shadow.normalBias),void 0!==t.shadow.radius&&(n.shadow.radius=t.shadow.radius),void 0!==t.shadow.mapSize&&n.shadow.mapSize.fromArray(t.shadow.mapSize),void 0!==t.shadow.camera&&(n.shadow.camera=this.parseObject(t.shadow.camera))),void 0!==t.visible&&(n.visible=t.visible),void 0!==t.frustumCulled&&(n.frustumCulled=t.frustumCulled),void 0!==t.renderOrder&&(n.renderOrder=t.renderOrder),void 0!==t.userData&&(n.userData=t.userData),void 0!==t.layers&&(n.layers.mask=t.layers),void 0!==t.children){const o=t.children;for(let t=0;t{e&&e(s),r.manager.itemEnd(t)})).catch((t=>{i&&i(t)})):(setTimeout((function(){e&&e(n),r.manager.itemEnd(t)}),0),n);const o={};o.credentials="anonymous"===this.crossOrigin?"same-origin":"include",o.headers=this.requestHeader;const a=fetch(t,o).then((function(t){return t.blob()})).then((function(t){return createImageBitmap(t,Object.assign(r.options,{colorSpaceConversion:"none"}))})).then((function(s){return tc.add(t,s),e&&e(s),r.manager.itemEnd(t),s})).catch((function(e){i&&i(e),tc.remove(t),r.manager.itemError(t),r.manager.itemEnd(t)}));tc.add(t,a),r.manager.itemStart(t)}}let Uc;class Dc{static getContext(){return void 0===Uc&&(Uc=new(window.AudioContext||window.webkitAudioContext)),Uc}static setContext(t){Uc=t}}class Hc extends ic{constructor(t){super(t)}load(t,e,s,i){const r=this,n=new oc(this.manager);function o(e){i?i(e):console.error(e),r.manager.itemError(t)}n.setResponseType("arraybuffer"),n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(t,(function(t){try{const s=t.slice(0);Dc.getContext().decodeAudioData(s,(function(t){e(t)})).catch(o)}catch(t){o(t)}}),s,i)}}const qc=new nr,Jc=new nr,Xc=new nr;class Yc{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new $n,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new $n,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,Xc.copy(t.projectionMatrix);const s=e.eyeSep/2,i=s*e.near/e.focus,r=e.near*Math.tan(Ws*e.fov*.5)/e.zoom;let n,o;Jc.elements[12]=-s,qc.elements[12]=s,n=-r*e.aspect+i,o=r*e.aspect+i,Xc.elements[0]=2*e.near/(o-n),Xc.elements[8]=(o+n)/(o-n),this.cameraL.projectionMatrix.copy(Xc),n=-r*e.aspect-i,o=r*e.aspect-i,Xc.elements[0]=2*e.near/(o-n),Xc.elements[8]=(o+n)/(o-n),this.cameraR.projectionMatrix.copy(Xc)}this.cameraL.matrixWorld.copy(t.matrixWorld).multiply(Jc),this.cameraR.matrixWorld.copy(t.matrixWorld).multiply(qc)}}class Zc extends $n{constructor(t=[]){super(),this.isArrayCamera=!0,this.cameras=t}}class Gc{constructor(t=!0){this.autoStart=t,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=$c(),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=$c();t=(e-this.oldTime)/1e3,this.oldTime=e,this.elapsedTime+=t}return t}}function $c(){return performance.now()}const Qc=new Ii,Kc=new Ci,tu=new Ii,eu=new Ii;class su extends Er{constructor(){super(),this.type="AudioListener",this.context=Dc.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new Gc}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,s=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(Qc,Kc,tu),eu.set(0,0,-1).applyQuaternion(Kc),e.positionX){const t=this.context.currentTime+this.timeDelta;e.positionX.linearRampToValueAtTime(Qc.x,t),e.positionY.linearRampToValueAtTime(Qc.y,t),e.positionZ.linearRampToValueAtTime(Qc.z,t),e.forwardX.linearRampToValueAtTime(eu.x,t),e.forwardY.linearRampToValueAtTime(eu.y,t),e.forwardZ.linearRampToValueAtTime(eu.z,t),e.upX.linearRampToValueAtTime(s.x,t),e.upY.linearRampToValueAtTime(s.y,t),e.upZ.linearRampToValueAtTime(s.z,t)}else e.setPosition(Qc.x,Qc.y,Qc.z),e.setOrientation(eu.x,eu.y,eu.z,s.x,s.y,s.z)}}class iu extends Er{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(s,i,this._addIndex*e,1,e);for(let t=e,r=e+e;t!==r;++t)if(s[t]!==s[t+e]){o.setValue(s,i);break}}saveOriginalState(){const t=this.binding,e=this.buffer,s=this.valueSize,i=s*this._origIndex;t.getValue(e,i);for(let t=s,r=i;t!==r;++t)e[t]=e[i+t%s];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 s=t;s=.5)for(let i=0;i!==r;++i)t[e+i]=t[s+i]}_slerp(t,e,s,i){Ci.slerpFlat(t,e,t,e,t,s,i)}_slerpAdditive(t,e,s,i,r){const n=this._workIndex*r;Ci.multiplyQuaternionsFlat(t,n,t,e,t,s),Ci.slerpFlat(t,e,t,e,t,n,i)}_lerp(t,e,s,i,r){const n=1-i;for(let o=0;o!==r;++o){const r=e+o;t[r]=t[r]*n+t[s+o]*i}}_lerpAdditive(t,e,s,i,r){for(let n=0;n!==r;++n){const r=e+n;t[r]=t[r]+t[s+n]*i}}}const uu="\\[\\]\\.:\\/",du=new RegExp("["+uu+"]","g"),pu="[^"+uu+"]",mu="[^"+uu.replace("\\.","")+"]",yu=new RegExp("^"+/((?:WC+[\/:])*)/.source.replace("WC",pu)+/(WCOD+)?/.source.replace("WCOD",mu)+/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",pu)+/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",pu)+"$"),fu=["material","materials","bones","map"];class gu{constructor(t,e,s){this.path=e,this.parsedPath=s||gu.parseTrackName(e),this.node=gu.findNode(t,this.parsedPath.nodeName),this.rootNode=t,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(t,e,s){return t&&t.isAnimationObjectGroup?new gu.Composite(t,e,s):new gu(t,e,s)}static sanitizeNodeName(t){return t.replace(/\s/g,"_").replace(du,"")}static parseTrackName(t){const e=yu.exec(t);if(null===e)throw new Error("PropertyBinding: Cannot parse trackName: "+t);const s={nodeName:e[2],objectName:e[3],objectIndex:e[4],propertyName:e[5],propertyIndex:e[6]},i=s.nodeName&&s.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const t=s.nodeName.substring(i+1);-1!==fu.indexOf(t)&&(s.nodeName=s.nodeName.substring(0,i),s.objectName=t)}if(null===s.propertyName||0===s.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+t);return s}static findNode(t,e){if(void 0===e||""===e||"."===e||-1===e||e===t.name||e===t.uuid)return t;if(t.skeleton){const s=t.skeleton.getBoneByName(e);if(void 0!==s)return s}if(t.children){const s=function(t){for(let i=0;i=r){const n=r++,l=t[n];e[l.uuid]=h,t[h]=l,e[a]=n,t[n]=o;for(let t=0,e=i;t!==e;++t){const e=s[t],i=e[n],r=e[h];e[h]=i,e[n]=r}}}this.nCachedObjects_=r}uncache(){const t=this._objects,e=this._indicesByUUID,s=this._bindings,i=s.length;let r=this.nCachedObjects_,n=t.length;for(let o=0,a=arguments.length;o!==a;++o){const a=arguments[o].uuid,h=e[a];if(void 0!==h)if(delete e[a],h0&&(e[o.uuid]=h),t[h]=o,t.pop();for(let t=0,e=i;t!==e;++t){const e=s[t];e[h]=e[r],e.pop()}}}this.nCachedObjects_=r}subscribe_(t,e){const s=this._bindingsIndicesByPath;let i=s[t];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_,c=new Array(h);i=r.length,s[t]=i,n.push(t),o.push(e),r.push(c);for(let s=l,i=a.length;s!==i;++s){const i=a[s];c[s]=new gu(i,t,e)}return c}unsubscribe_(t){const e=this._bindingsIndicesByPath,s=e[t];if(void 0!==s){const i=this._paths,r=this._parsedPaths,n=this._bindings,o=n.length-1,a=n[o];e[t[o]]=s,n[s]=a,n.pop(),r[s]=r[o],r.pop(),i[s]=i[o],i.pop()}}}class bu{constructor(t,e,s=null,i=e.blendMode){this._mixer=t,this._clip=e,this._localRoot=s,this.blendMode=i;const r=e.tracks,n=r.length,o=new Array(n),a={endingStart:Oe,endingEnd:Oe};for(let t=0;t!==n;++t){const e=r[t].createInterpolant(null);o[t]=e,e.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(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,s){if(t.fadeOut(e),this.fadeIn(e),s){const s=this._clip.duration,i=t._clip.duration,r=i/s,n=s/i;t.warp(1,r,e),this.warp(n,1,e)}return this}crossFadeTo(t,e,s){return t.crossFadeFrom(this,e,s)}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,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]=t/n,h[1]=e/n,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,s,i){if(!this.enabled)return void this._updateWeight(t);const r=this._startTime;if(null!==r){const i=(t-r)*s;i<0||0===s?e=0:(this._startTime=null,e=s*i)}e*=this._updateTimeScale(t);const n=this._updateTime(e),o=this._updateWeight(t);if(o>0){const t=this._interpolants,e=this._propertyBindings;if(this.blendMode===Ve)for(let s=0,i=t.length;s!==i;++s)t[s].evaluate(n),e[s].accumulateAdditive(o);else for(let s=0,r=t.length;s!==r;++s)t[s].evaluate(n),e[s].accumulate(i,o)}}_updateWeight(t){let e=0;if(this.enabled){e=this.weight;const s=this._weightInterpolant;if(null!==s){const i=s.evaluate(t)[0];e*=i,t>s.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 s=this._timeScaleInterpolant;if(null!==s){e*=s.evaluate(t)[0],t>s.parameterPositions[1]&&(this.stopWarping(),0===e?this.paused=!0:this.timeScale=e)}}return this._effectiveTimeScale=e,e}_updateTime(t){const e=this._clip.duration,s=this.loop;let i=this.time+t,r=this._loopCount;const n=2202===s;if(0===t)return-1===r||!n||1&~r?i:e-i;if(2200===s){-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,n)):this._setEndings(0===this.repetitions,!0,n)),i>=e||i<0){const s=Math.floor(i/e);i-=e*s,r+=Math.abs(s);const o=this.repetitions-r;if(o<=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===o){const e=t<0;this._setEndings(e,!e,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&~r))return e-i}return i}_setEndings(t,e,s){const i=this._interpolantSettings;s?(i.endingStart=Fe,i.endingEnd=Fe):(i.endingStart=t?this.zeroSlopeAtStart?Fe:Oe:Ne,i.endingEnd=e?this.zeroSlopeAtEnd?Fe:Oe:Ne)}_scheduleFading(t,e,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]=e,o[1]=r+t,a[1]=s,this}}const vu=new Float32Array(1);class wu extends Ns{constructor(t){super(),this._root=t,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(t,e){const s=t._localRoot||this._root,i=t._clip.tracks,r=i.length,n=t._propertyBindings,o=t._interpolants,a=s.uuid,h=this._bindingsByRootAndName;let l=h[a];void 0===l&&(l={},h[a]=l);for(let t=0;t!==r;++t){const r=i[t],h=r.name;let c=l[h];if(void 0!==c)++c.referenceCount,n[t]=c;else{if(c=n[t],void 0!==c){null===c._cacheIndex&&(++c.referenceCount,this._addInactiveBinding(c,a,h));continue}const i=e&&e._propertyBindings[t].binding.parsedPath;c=new cu(gu.create(s,h,i),r.ValueTypeName,r.getValueSize()),++c.referenceCount,this._addInactiveBinding(c,a,h),n[t]=c}o[t].resultBuffer=c.buffer}}_activateAction(t){if(!this._isActiveAction(t)){if(null===t._cacheIndex){const e=(t._localRoot||this._root).uuid,s=t._clip.uuid,i=this._actionsByClip[s];this._bindAction(t,i&&i.knownActions[0]),this._addInactiveAction(t,s,e)}const e=t._propertyBindings;for(let t=0,s=e.length;t!==s;++t){const s=e[t];0==s.useCount++&&(this._lendBinding(s),s.saveOriginalState())}this._lendAction(t)}}_deactivateAction(t){if(this._isActiveAction(t)){const e=t._propertyBindings;for(let t=0,s=e.length;t!==s;++t){const s=e[t];0==--s.useCount&&(s.restoreOriginalState(),this._takeBackBinding(s))}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,s=this._nActiveActions,i=this.time+=t,r=Math.sign(t),n=this._accuIndex^=1;for(let o=0;o!==s;++o){e[o]._update(i,t,r,n)}const o=this._bindings,a=this._nActiveBindings;for(let t=0;t!==a;++t)o[t].apply(n);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,Ru).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 Fu=new Ii,Nu=new Ii;class Lu{constructor(t=new Ii,e=new Ii){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){Fu.subVectors(t,this.start),Nu.subVectors(this.end,this.start);const s=Nu.dot(Nu);let i=Nu.dot(Fu)/s;return e&&(i=Ds(i,0,1)),i}closestPointToPoint(t,e,s){const i=this.closestPointToPointParameter(t,e);return this.delta(s).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 Vu=new Ii;class Wu extends Er{constructor(t,e){super(),this.light=t,this.matrixAutoUpdate=!1,this.color=e,this.type="SpotLightHelper";const s=new zn,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,s=32;t1)for(let s=0;s.99999)this.quaternion.set(0,0,0,1);else if(t.y<-.99999)this.quaternion.set(1,0,0,0);else{ud.set(t.z,0,-t.x).normalize();const e=Math.acos(t.y);this.quaternion.setFromAxisAngle(ud,e)}}setLength(t,e=.2*t,s=.2*e){this.line.scale.set(1,Math.max(1e-4,t-e),1),this.line.updateMatrix(),this.cone.scale.set(s,e,s),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 yd extends Oa{constructor(t=1){const e=[0,0,0,t,0,0,0,0,0,0,t,0,0,0,0,0,0,t],s=new zn;s.setAttribute("position",new bn(e,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 Sa({vertexColors:!0,toneMapped:!1})),this.type="AxesHelper"}setColors(t,e,s){const i=new $r,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(s),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class fd{constructor(){this.type="ShapePath",this.color=new $r,this.subPaths=[],this.currentPath=null}moveTo(t,e){return this.currentPath=new bh,this.subPaths.push(this.currentPath),this.currentPath.moveTo(t,e),this}lineTo(t,e){return this.currentPath.lineTo(t,e),this}quadraticCurveTo(t,e,s,i){return this.currentPath.quadraticCurveTo(t,e,s,i),this}bezierCurveTo(t,e,s,i,r,n){return this.currentPath.bezierCurveTo(t,e,s,i,r,n),this}splineThru(t){return this.currentPath.splineThru(t),this}toShapes(t){function e(t,e){const s=e.length;let i=!1;for(let r=s-1,n=0;nNumber.EPSILON){if(h<0&&(s=e[n],a=-a,o=e[r],h=-h),t.yo.y)continue;if(t.y===s.y){if(t.x===s.x)return!0}else{const e=h*(t.x-s.x)-a*(t.y-s.y);if(0===e)return!0;if(e<0)continue;i=!i}}else{if(t.y!==s.y)continue;if(o.x<=t.x&&t.x<=s.x||s.x<=t.x&&t.x<=o.x)return!0}}return i}const s=rl.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=t?!h:h;const l=[],c=[];let u,d,p=[],m=0;c[m]=void 0,p[m]=[];for(let e=0,o=i.length;e1){let t=!1,s=0;for(let t=0,e=c.length;t0&&!1===t&&(p=l)}for(let t=0,e=c.length;te?(t.repeat.x=1,t.repeat.y=s/e,t.offset.x=0,t.offset.y=(1-t.repeat.y)/2):(t.repeat.x=e/s,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0),t},cover:function(t,e){const s=t.image&&t.image.width?t.image.width/t.image.height:1;return s>e?(t.repeat.x=e/s,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0):(t.repeat.x=1,t.repeat.y=s/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:xd};"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("register",{detail:{revision:t}})),"undefined"!=typeof window&&(window.__THREE__?console.warn("WARNING: Multiple instances of Three.js being imported."):window.__THREE__=t);export{et as ACESFilmicToneMapping,v as AddEquation,G as AddOperation,Ve as AdditiveAnimationBlendMode,f as AdditiveBlending,it as AgXToneMapping,Lt as AlphaFormat,Ss as AlwaysCompare,j as AlwaysDepth,ys as AlwaysStencilFunc,Ic as AmbientLight,bu as AnimationAction,Ql as AnimationClip,ac as AnimationLoader,wu as AnimationMixer,xu as AnimationObjectGroup,Vl as AnimationUtils,th as ArcCurve,Zc as ArrayCamera,md as ArrowHelper,nt as AttachedBindMode,iu as Audio,lu as AudioAnalyser,Dc as AudioContext,su as AudioListener,Hc as AudioLoader,yd as AxesHelper,d as BackSide,De as BasicDepthPacking,a as BasicShadowMap,Ma as BatchedMesh,Lo as Bone,ql as BooleanKeyframeTrack,Ou as Box2,Ei as Box3,ld as Box3Helper,jn as BoxGeometry,hd as BoxHelper,cn as BufferAttribute,zn as BufferGeometry,Fc as BufferGeometryLoader,zt as ByteType,tc as Cache,Xn as Camera,nd as CameraHelper,Ga as CanvasTexture,wh as CapsuleGeometry,oh as CatmullRomCurve3,tt as CineonToneMapping,Mh as CircleGeometry,mt as ClampToEdgeWrapping,Gc as Clock,$r as Color,Jl as ColorKeyframeTrack,ui as ColorManagement,Ya as CompressedArrayTexture,Za as CompressedCubeTexture,Xa as CompressedTexture,hc as CompressedTextureLoader,_h as ConeGeometry,L as ConstantAlphaFactor,F as ConstantColorFactor,gd as Controls,Kn as CubeCamera,ht as CubeReflectionMapping,lt as CubeRefractionMapping,to as CubeTexture,cc as CubeTextureLoader,dt as CubeUVReflectionMapping,ch as CubicBezierCurve,uh as CubicBezierCurve3,jl as CubicInterpolant,r as CullFaceBack,n as CullFaceFront,o as CullFaceFrontBack,i as CullFaceNone,Qa as Curve,xh as CurvePath,b as CustomBlending,st as CustomToneMapping,Sh as CylinderGeometry,Eu as Cylindrical,Ti as Data3DTexture,_i as DataArrayTexture,Vo as DataTexture,uc as DataTextureLoader,an as DataUtils,rs as DecrementStencilOp,os as DecrementWrapStencilOp,sc as DefaultLoadingManager,Dt as DepthFormat,Ht as DepthStencilFormat,$a as DepthTexture,ot as DetachedBindMode,Cc as DirectionalLight,sd as DirectionalLightHelper,Dl as DiscreteInterpolant,Th as DodecahedronGeometry,p as DoubleSide,k as DstAlphaFactor,P as DstColorFactor,ks as DynamicCopyUsage,As as DynamicDrawUsage,Cs as DynamicReadUsage,kh as EdgesGeometry,Ka as EllipseCurve,xs as EqualCompare,H as EqualDepth,cs as EqualStencilFunc,ct as EquirectangularReflectionMapping,ut as EquirectangularRefractionMapping,yr as Euler,Ns as EventDispatcher,al as ExtrudeGeometry,oc as FileLoader,xn as Float16BufferAttribute,bn as Float32BufferAttribute,Et as FloatType,io as Fog,so as FogExp2,Ja as FramebufferTexture,u as FrontSide,ra as Frustum,Tu as GLBufferAttribute,Ps as GLSL1,Rs as GLSL3,vs as GreaterCompare,J as GreaterDepth,Ms as GreaterEqualCompare,q as GreaterEqualDepth,ms as GreaterEqualStencilFunc,ds as GreaterStencilFunc,$u as GridHelper,Ha as Group,Pt as HalfFloatType,mc as HemisphereLight,Gu as HemisphereLightHelper,ll as IcosahedronGeometry,jc as ImageBitmapLoader,lc as ImageLoader,yi as ImageUtils,is as IncrementStencilOp,ns as IncrementWrapStencilOp,Do as InstancedBufferAttribute,Oc as InstancedBufferGeometry,Au as InstancedInterleavedBuffer,$o as InstancedMesh,mn as Int16BufferAttribute,fn as Int32BufferAttribute,un as Int8BufferAttribute,Bt as IntType,no as InterleavedBuffer,ao as InterleavedBufferAttribute,Wl as Interpolant,Ee as InterpolateDiscrete,Pe as InterpolateLinear,Re as InterpolateSmooth,as as InvertStencilOp,es as KeepStencilOp,Hl as KeyframeTrack,zo as LOD,vh as LatheGeometry,fr as Layers,gs as LessCompare,U as LessDepth,bs as LessEqualCompare,D as LessEqualDepth,us as LessEqualStencilFunc,ls as LessStencilFunc,pc as Light,Ec as LightProbe,ka as Line,Lu as Line3,Sa as LineBasicMaterial,dh as LineCurve,ph as LineCurve3,Pl as LineDashedMaterial,Fa as LineLoop,Oa as LineSegments,wt as LinearFilter,Ul as LinearInterpolant,At as LinearMipMapLinearFilter,St as LinearMipMapNearestFilter,_t as LinearMipmapLinearFilter,Mt as LinearMipmapNearestFilter,$e as LinearSRGBColorSpace,Q as LinearToneMapping,Qe as LinearTransfer,ic as Loader,Rc as LoaderUtils,ec as LoadingManager,Ie as LoopOnce,ke as LoopPingPong,Be as LoopRepeat,Ut as LuminanceAlphaFormat,jt as LuminanceFormat,e as MOUSE,tn as Material,Pc as MaterialLoader,Ys as MathUtils,Pu as Matrix2,Gs as Matrix3,nr as Matrix4,_ as MaxEquation,Vn as Mesh,en as MeshBasicMaterial,Bl as MeshDepthMaterial,kl as MeshDistanceMaterial,Il as MeshLambertMaterial,El as MeshMatcapMaterial,Cl as MeshNormalMaterial,Tl as MeshPhongMaterial,Al as MeshPhysicalMaterial,_l as MeshStandardMaterial,zl as MeshToonMaterial,S as MinEquation,yt as MirroredRepeatWrapping,Z as MixOperation,x as MultiplyBlending,Y as MultiplyOperation,ft as NearestFilter,vt as NearestMipMapLinearFilter,xt as NearestMipMapNearestFilter,bt as NearestMipmapLinearFilter,gt as NearestMipmapNearestFilter,rt as NeutralToneMapping,fs as NeverCompare,W as NeverDepth,hs as NeverStencilFunc,m as NoBlending,Ze as NoColorSpace,$ as NoToneMapping,Le as NormalAnimationBlendMode,y as NormalBlending,ws as NotEqualCompare,X as NotEqualDepth,ps as NotEqualStencilFunc,Xl as NumberKeyframeTrack,Er as Object3D,Nc as ObjectLoader,Ye as ObjectSpaceNormalMap,cl as OctahedronGeometry,T as OneFactor,V as OneMinusConstantAlphaFactor,N as OneMinusConstantColorFactor,E as OneMinusDstAlphaFactor,R as OneMinusDstColorFactor,B as OneMinusSrcAlphaFactor,C as OneMinusSrcColorFactor,Tc as OrthographicCamera,h as PCFShadowMap,l as PCFSoftShadowMap,bh as Path,$n as PerspectiveCamera,ea as Plane,ul as PlaneGeometry,cd as PlaneHelper,Ac as PointLight,Ju as PointLightHelper,Ua as Points,Na as PointsMaterial,Qu as PolarGridHelper,Ah as PolyhedronGeometry,hu as PositionalAudio,gu as PropertyBinding,cu as PropertyMixer,mh as QuadraticBezierCurve,yh as QuadraticBezierCurve3,Ci as Quaternion,Zl as QuaternionKeyframeTrack,Yl as QuaternionLinearInterpolant,js as RAD2DEG,ze as RED_GREEN_RGTC2_Format,Ae as RED_RGTC1_Format,t as REVISION,He as RGBADepthPacking,Wt as RGBAFormat,Gt as RGBAIntegerFormat,be as RGBA_ASTC_10x10_Format,fe as RGBA_ASTC_10x5_Format,ge as RGBA_ASTC_10x6_Format,xe as RGBA_ASTC_10x8_Format,ve as RGBA_ASTC_12x10_Format,we as RGBA_ASTC_12x12_Format,he as RGBA_ASTC_4x4_Format,le as RGBA_ASTC_5x4_Format,ce as RGBA_ASTC_5x5_Format,ue as RGBA_ASTC_6x5_Format,de as RGBA_ASTC_6x6_Format,pe as RGBA_ASTC_8x5_Format,me as RGBA_ASTC_8x6_Format,ye as RGBA_ASTC_8x8_Format,Me as RGBA_BPTC_Format,ae as RGBA_ETC2_EAC_Format,re as RGBA_PVRTC_2BPPV1_Format,ie as RGBA_PVRTC_4BPPV1_Format,Qt as RGBA_S3TC_DXT1_Format,Kt as RGBA_S3TC_DXT3_Format,te as RGBA_S3TC_DXT5_Format,qe as RGBDepthPacking,Vt as RGBFormat,Zt as RGBIntegerFormat,Se as RGB_BPTC_SIGNED_Format,_e as RGB_BPTC_UNSIGNED_Format,ne as RGB_ETC1_Format,oe as RGB_ETC2_Format,se as RGB_PVRTC_2BPPV1_Format,ee as RGB_PVRTC_4BPPV1_Format,$t as RGB_S3TC_DXT1_Format,Je as RGDepthPacking,Xt as RGFormat,Yt as RGIntegerFormat,Sl as RawShaderMaterial,rr as Ray,Cu as Raycaster,Bc as RectAreaLight,qt as RedFormat,Jt as RedIntegerFormat,K as ReinhardToneMapping,Mi as RenderTarget,pt as RepeatWrapping,ss as ReplaceStencilOp,M as ReverseSubtractEquation,dl as RingGeometry,Ce as SIGNED_RED_GREEN_RGTC2_Format,Te as SIGNED_RED_RGTC1_Format,Ge as SRGBColorSpace,Ke as SRGBTransfer,ro as Scene,Jn as ShaderMaterial,Ml as ShadowMaterial,Eh as Shape,pl as ShapeGeometry,fd as ShapePath,rl as ShapeUtils,Ct as ShortType,Uo as Skeleton,Hu as SkeletonHelper,No as SkinnedMesh,gi as Source,Gi as Sphere,ml as SphereGeometry,ku as Spherical,kc as SphericalHarmonics3,fh as SplineCurve,vc as SpotLight,Wu as SpotLightHelper,So as Sprite,ho as SpriteMaterial,I as SrcAlphaFactor,O as SrcAlphaSaturateFactor,z as SrcColorFactor,Bs as StaticCopyUsage,_s as StaticDrawUsage,zs as StaticReadUsage,Yc as StereoCamera,Es as StreamCopyUsage,Ts as StreamDrawUsage,Is as StreamReadUsage,Gl as StringKeyframeTrack,w as SubtractEquation,g as SubtractiveBlending,s as TOUCH,Xe as TangentSpaceNormalMap,yl as TetrahedronGeometry,vi as Texture,dc as TextureLoader,bd as TextureUtils,fl as TorusGeometry,gl as TorusKnotGeometry,Jr as Triangle,Ue as TriangleFanDrawMode,je as TriangleStripDrawMode,We as TrianglesDrawMode,xl as TubeGeometry,at as UVMapping,yn as Uint16BufferAttribute,gn as Uint32BufferAttribute,dn as Uint8BufferAttribute,pn as Uint8ClampedBufferAttribute,Mu as Uniform,_u as UniformsGroup,qn as UniformsUtils,Tt as UnsignedByteType,Ft as UnsignedInt248Type,Nt as UnsignedInt5999Type,kt as UnsignedIntType,Rt as UnsignedShort4444Type,Ot as UnsignedShort5551Type,It as UnsignedShortType,c as VSMShadowMap,Zs as Vector2,Ii as Vector3,wi as Vector4,$l as VectorKeyframeTrack,qa as VideoTexture,zi as WebGL3DRenderTarget,Ai as WebGLArrayRenderTarget,Os as WebGLCoordinateSystem,eo as WebGLCubeRenderTarget,Si as WebGLRenderTarget,Fs as WebGPUCoordinateSystem,bl as WireframeGeometry,Ne as WrapAroundEnding,Oe as ZeroCurvatureEnding,A as ZeroFactor,Fe as ZeroSlopeEnding,ts as ZeroStencilOp,Qs as arrayNeedsUint32,Un as cloneUniforms,si as createCanvasElement,ei as createElementNS,xd as getByteLength,Hn as getUnlitUniformColorSpace,Dn as mergeUniforms,ni as probeAsync,oi as toNormalizedProjectionMatrix,ai as toReversedProjectionMatrix,ri as warnOnce}; +const t="173dev",e={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,c=3,u=0,d=1,p=2,m=0,y=1,f=2,g=3,x=4,b=5,v=100,w=101,M=102,S=103,_=104,A=200,T=201,z=202,C=203,I=204,B=205,k=206,R=207,P=208,E=209,O=210,F=211,N=212,L=213,V=214,W=0,j=1,U=2,D=3,H=4,q=5,J=6,X=7,Y=0,Z=1,G=2,$=0,Q=1,K=2,tt=3,et=4,st=5,it=6,rt=7,nt="attached",ot="detached",at=300,ht=301,lt=302,ct=303,ut=304,dt=306,pt=1e3,mt=1001,yt=1002,ft=1003,gt=1004,xt=1004,bt=1005,vt=1005,wt=1006,Mt=1007,St=1007,_t=1008,At=1008,Tt=1009,zt=1010,Ct=1011,It=1012,Bt=1013,kt=1014,Rt=1015,Pt=1016,Et=1017,Ot=1018,Ft=1020,Nt=35902,Lt=1021,Vt=1022,Wt=1023,jt=1024,Ut=1025,Dt=1026,Ht=1027,qt=1028,Jt=1029,Xt=1030,Yt=1031,Zt=1032,Gt=1033,$t=33776,Qt=33777,Kt=33778,te=33779,ee=35840,se=35841,ie=35842,re=35843,ne=36196,oe=37492,ae=37496,he=37808,le=37809,ce=37810,ue=37811,de=37812,pe=37813,me=37814,ye=37815,fe=37816,ge=37817,xe=37818,be=37819,ve=37820,we=37821,Me=36492,Se=36494,_e=36495,Ae=36283,Te=36284,ze=36285,Ce=36286,Ie=2200,Be=2201,ke=2202,Re=2300,Pe=2301,Ee=2302,Oe=2400,Fe=2401,Ne=2402,Le=2500,Ve=2501,We=0,je=1,Ue=2,De=3200,He=3201,qe=3202,Je=3203,Xe=0,Ye=1,Ze="",Ge="srgb",$e="srgb-linear",Qe="linear",Ke="srgb",ts=0,es=7680,ss=7681,is=7682,rs=7683,ns=34055,os=34056,as=5386,hs=512,ls=513,cs=514,us=515,ds=516,ps=517,ms=518,ys=519,fs=512,gs=513,xs=514,bs=515,vs=516,ws=517,Ms=518,Ss=519,_s=35044,As=35048,Ts=35040,zs=35045,Cs=35049,Is=35041,Bs=35046,ks=35050,Rs=35042,Ps="100",Es="300 es",Os=2e3,Fs=2001;class Ns{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const s=this._listeners;void 0===s[t]&&(s[t]=[]),-1===s[t].indexOf(e)&&s[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const s=this._listeners;return void 0!==s[t]&&-1!==s[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const s=this._listeners[t];if(void 0!==s){const t=s.indexOf(e);-1!==t&&s.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 s=e.slice(0);for(let e=0,i=s.length;e>8&255]+Ls[t>>16&255]+Ls[t>>24&255]+"-"+Ls[255&e]+Ls[e>>8&255]+"-"+Ls[e>>16&15|64]+Ls[e>>24&255]+"-"+Ls[63&s|128]+Ls[s>>8&255]+"-"+Ls[s>>16&255]+Ls[s>>24&255]+Ls[255&i]+Ls[i>>8&255]+Ls[i>>16&255]+Ls[i>>24&255]).toLowerCase()}function Ds(t,e,s){return Math.max(e,Math.min(s,t))}function Hs(t,e){return(t%e+e)%e}function qs(t,e,s){return(1-s)*t+s*e}function Js(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 Xs(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 Ys={DEG2RAD:Ws,RAD2DEG:js,generateUUID:Us,clamp:Ds,euclideanModulo:Hs,mapLinear:function(t,e,s,i,r){return i+(t-e)*(r-i)/(s-e)},inverseLerp:function(t,e,s){return t!==e?(s-t)/(e-t):0},lerp:qs,damp:function(t,e,s,i){return qs(t,e,1-Math.exp(-s*i))},pingpong:function(t,e=1){return e-Math.abs(Hs(t,2*e)-e)},smoothstep:function(t,e,s){return t<=e?0:t>=s?1:(t=(t-e)/(s-e))*t*(3-2*t)},smootherstep:function(t,e,s){return t<=e?0:t>=s?1:(t=(t-e)/(s-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&&(Vs=t);let e=Vs+=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*Ws},radToDeg:function(t){return t*js},isPowerOfTwo:function(t){return!(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,s,i,r){const n=Math.cos,o=Math.sin,a=n(s/2),h=o(s/2),l=n((e+i)/2),c=o((e+i)/2),u=n((e-i)/2),d=o((e-i)/2),p=n((i-e)/2),m=o((i-e)/2);switch(r){case"XYX":t.set(a*c,h*u,h*d,a*l);break;case"YZY":t.set(h*d,a*c,h*u,a*l);break;case"ZXZ":t.set(h*u,h*d,a*c,a*l);break;case"XZX":t.set(a*c,h*m,h*p,a*l);break;case"YXY":t.set(h*p,a*c,h*m,a*l);break;case"ZYZ":t.set(h*m,h*p,a*c,a*l);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:Xs,denormalize:Js};class Zs{constructor(t=0,e=0){Zs.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,s=this.y,i=t.elements;return this.x=i[0]*e+i[3]*s+i[6],this.y=i[1]*e+i[4]*s+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=Ds(this.x,t.x,e.x),this.y=Ds(this.y,t.y,e.y),this}clampScalar(t,e){return this.x=Ds(this.x,t,e),this.y=Ds(this.y,t,e),this}clampLength(t,e){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Ds(s,t,e))}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 s=this.dot(t)/e;return Math.acos(Ds(s,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,s=this.y-t.y;return e*e+s*s}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,s){return this.x=t.x+(e.x-t.x)*s,this.y=t.y+(e.y-t.y)*s,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 s=Math.cos(e),i=Math.sin(e),r=this.x-t.x,n=this.y-t.y;return this.x=r*s-n*i+t.x,this.y=r*i+n*s+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class Gs{constructor(t,e,s,i,r,n,o,a,h){Gs.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],void 0!==t&&this.set(t,e,s,i,r,n,o,a,h)}set(t,e,s,i,r,n,o,a,h){const l=this.elements;return l[0]=t,l[1]=i,l[2]=o,l[3]=e,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(t){const e=this.elements,s=t.elements;return e[0]=s[0],e[1]=s[1],e[2]=s[2],e[3]=s[3],e[4]=s[4],e[5]=s[5],e[6]=s[6],e[7]=s[7],e[8]=s[8],this}extractBasis(t,e,s){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),s.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 s=t.elements,i=e.elements,r=this.elements,n=s[0],o=s[3],a=s[6],h=s[1],l=s[4],c=s[7],u=s[2],d=s[5],p=s[8],m=i[0],y=i[3],f=i[6],g=i[1],x=i[4],b=i[7],v=i[2],w=i[5],M=i[8];return r[0]=n*m+o*g+a*v,r[3]=n*y+o*x+a*w,r[6]=n*f+o*b+a*M,r[1]=h*m+l*g+c*v,r[4]=h*y+l*x+c*w,r[7]=h*f+l*b+c*M,r[2]=u*m+d*g+p*v,r[5]=u*y+d*x+p*w,r[8]=u*f+d*b+p*M,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],s=t[1],i=t[2],r=t[3],n=t[4],o=t[5],a=t[6],h=t[7],l=t[8];return e*n*l-e*o*h-s*r*l+s*o*a+i*r*h-i*n*a}invert(){const t=this.elements,e=t[0],s=t[1],i=t[2],r=t[3],n=t[4],o=t[5],a=t[6],h=t[7],l=t[8],c=l*n-o*h,u=o*a-l*r,d=h*r-n*a,p=e*c+s*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]=c*m,t[1]=(i*h-l*s)*m,t[2]=(o*s-i*n)*m,t[3]=u*m,t[4]=(l*e-i*a)*m,t[5]=(i*r-o*e)*m,t[6]=d*m,t[7]=(s*a-h*e)*m,t[8]=(n*e-s*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,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+t,-i*h,i*a,-i*(-h*n+a*o)+o+e,0,0,1),this}scale(t,e){return this.premultiply($s.makeScale(t,e)),this}rotate(t){return this.premultiply($s.makeRotation(-t)),this}translate(t,e){return this.premultiply($s.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),s=Math.sin(t);return this.set(e,-s,0,s,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,s=t.elements;for(let t=0;t<9;t++)if(e[t]!==s[t])return!1;return!0}fromArray(t,e=0){for(let s=0;s<9;s++)this.elements[s]=t[s+e];return this}toArray(t=[],e=0){const s=this.elements;return t[e]=s[0],t[e+1]=s[1],t[e+2]=s[2],t[e+3]=s[3],t[e+4]=s[4],t[e+5]=s[5],t[e+6]=s[6],t[e+7]=s[7],t[e+8]=s[8],t}clone(){return(new this.constructor).fromArray(this.elements)}}const $s=new Gs;function Qs(t){for(let e=t.length-1;e>=0;--e)if(t[e]>=65535)return!0;return!1}const Ks={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function ti(t,e){return new Ks[t](e)}function ei(t){return document.createElementNS("http://www.w3.org/1999/xhtml",t)}function si(){const t=ei("canvas");return t.style.display="block",t}const ii={};function ri(t){t in ii||(ii[t]=!0,console.warn(t))}function ni(t,e,s){return new Promise((function(i,r){setTimeout((function n(){switch(t.clientWaitSync(e,t.SYNC_FLUSH_COMMANDS_BIT,0)){case t.WAIT_FAILED:r();break;case t.TIMEOUT_EXPIRED:setTimeout(n,s);break;default:i()}}),s)}))}function oi(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]}function ai(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])}const hi=(new Gs).set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),li=(new Gs).set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);function ci(){const t={enabled:!0,workingColorSpace:$e,spaces:{},convert:function(t,e,s){return!1!==this.enabled&&e!==s&&e&&s?(this.spaces[e].transfer===Ke&&(t.r=di(t.r),t.g=di(t.g),t.b=di(t.b)),this.spaces[e].primaries!==this.spaces[s].primaries&&(t.applyMatrix3(this.spaces[e].toXYZ),t.applyMatrix3(this.spaces[s].fromXYZ)),this.spaces[s].transfer===Ke&&(t.r=pi(t.r),t.g=pi(t.g),t.b=pi(t.b)),t):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 this.spaces[t].primaries},getTransfer:function(t){return""===t?Qe:this.spaces[t].transfer},getLuminanceCoefficients:function(t,e=this.workingColorSpace){return t.fromArray(this.spaces[e].luminanceCoefficients)},define:function(t){Object.assign(this.spaces,t)},_getMatrix:function(t,e,s){return t.copy(this.spaces[e].toXYZ).multiply(this.spaces[s].fromXYZ)},_getDrawingBufferColorSpace:function(t){return this.spaces[t].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(t=this.workingColorSpace){return this.spaces[t].workingColorSpaceConfig.unpackColorSpace}},e=[.64,.33,.3,.6,.15,.06],s=[.2126,.7152,.0722],i=[.3127,.329];return t.define({[$e]:{primaries:e,whitePoint:i,transfer:Qe,toXYZ:hi,fromXYZ:li,luminanceCoefficients:s,workingColorSpaceConfig:{unpackColorSpace:Ge},outputColorSpaceConfig:{drawingBufferColorSpace:Ge}},[Ge]:{primaries:e,whitePoint:i,transfer:Ke,toXYZ:hi,fromXYZ:li,luminanceCoefficients:s,outputColorSpaceConfig:{drawingBufferColorSpace:Ge}}}),t}const ui=ci();function di(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function pi(t){return t<.0031308?12.92*t:1.055*Math.pow(t,.41666)-.055}let mi;class yi{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===mi&&(mi=ei("canvas")),mi.width=t.width,mi.height=t.height;const s=mi.getContext("2d");t instanceof ImageData?s.putImageData(t,0,0):s.drawImage(t,0,0,t.width,t.height),e=mi}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=ei("canvas");e.width=t.width,e.height=t.height;const s=e.getContext("2d");s.drawImage(t,0,0,t.width,t.height);const i=s.getImageData(0,0,t.width,t.height),r=i.data;for(let t=0;t0&&(s.userData=this.userData),e||(t.textures[this.uuid]=s),s}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(t){if(this.mapping!==at)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 yt: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 yt: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++}}vi.DEFAULT_IMAGE=null,vi.DEFAULT_MAPPING=at,vi.DEFAULT_ANISOTROPY=1;class wi{constructor(t=0,e=0,s=0,i=1){wi.prototype.isVector4=!0,this.x=t,this.y=e,this.z=s,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,s,i){return this.x=t,this.y=e,this.z=s,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,s=this.y,i=this.z,r=this.w,n=t.elements;return this.x=n[0]*e+n[4]*s+n[8]*i+n[12]*r,this.y=n[1]*e+n[5]*s+n[9]*i+n[13]*r,this.z=n[2]*e+n[6]*s+n[10]*i+n[14]*r,this.w=n[3]*e+n[7]*s+n[11]*i+n[15]*r,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this.w/=t.w,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,s,i,r;const n=.01,o=.1,a=t.elements,h=a[0],l=a[4],c=a[8],u=a[1],d=a[5],p=a[9],m=a[2],y=a[6],f=a[10];if(Math.abs(l-u)a&&t>g?tg?a=0?1:-1,i=1-e*e;if(i>Number.EPSILON){const r=Math.sqrt(i),n=Math.atan2(r,e*s);t=Math.sin(t*n)/r,o=Math.sin(o*n)/r}const r=o*s;if(a=a*t+u*r,h=h*t+d*r,l=l*t+p*r,c=c*t+m*r,t===1-o){const t=1/Math.sqrt(a*a+h*h+l*l+c*c);a*=t,h*=t,l*=t,c*=t}}t[e]=a,t[e+1]=h,t[e+2]=l,t[e+3]=c}static multiplyQuaternionsFlat(t,e,s,i,r,n){const o=s[i],a=s[i+1],h=s[i+2],l=s[i+3],c=r[n],u=r[n+1],d=r[n+2],p=r[n+3];return t[e]=o*p+l*c+a*d-h*u,t[e+1]=a*p+l*u+h*c-o*d,t[e+2]=h*p+l*d+o*u-a*c,t[e+3]=l*p-o*c-a*u-h*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,s,i){return this._x=t,this._y=e,this._z=s,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 s=t._x,i=t._y,r=t._z,n=t._order,o=Math.cos,a=Math.sin,h=o(s/2),l=o(i/2),c=o(r/2),u=a(s/2),d=a(i/2),p=a(r/2);switch(n){case"XYZ":this._x=u*l*c+h*d*p,this._y=h*d*c-u*l*p,this._z=h*l*p+u*d*c,this._w=h*l*c-u*d*p;break;case"YXZ":this._x=u*l*c+h*d*p,this._y=h*d*c-u*l*p,this._z=h*l*p-u*d*c,this._w=h*l*c+u*d*p;break;case"ZXY":this._x=u*l*c-h*d*p,this._y=h*d*c+u*l*p,this._z=h*l*p+u*d*c,this._w=h*l*c-u*d*p;break;case"ZYX":this._x=u*l*c-h*d*p,this._y=h*d*c+u*l*p,this._z=h*l*p-u*d*c,this._w=h*l*c+u*d*p;break;case"YZX":this._x=u*l*c+h*d*p,this._y=h*d*c+u*l*p,this._z=h*l*p-u*d*c,this._w=h*l*c-u*d*p;break;case"XZY":this._x=u*l*c-h*d*p,this._y=h*d*c-u*l*p,this._z=h*l*p+u*d*c,this._w=h*l*c+u*d*p;break;default:console.warn("THREE.Quaternion: .setFromEuler() encountered an unknown order: "+n)}return!0===e&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const s=e/2,i=Math.sin(s);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(s),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,s=e[0],i=e[4],r=e[8],n=e[1],o=e[5],a=e[9],h=e[2],l=e[6],c=e[10],u=s+o+c;if(u>0){const t=.5/Math.sqrt(u+1);this._w=.25/t,this._x=(l-a)*t,this._y=(r-h)*t,this._z=(n-i)*t}else if(s>o&&s>c){const t=2*Math.sqrt(1+s-o-c);this._w=(l-a)/t,this._x=.25*t,this._y=(i+n)/t,this._z=(r+h)/t}else if(o>c){const t=2*Math.sqrt(1+o-s-c);this._w=(r-h)/t,this._x=(i+n)/t,this._y=.25*t,this._z=(a+l)/t}else{const t=2*Math.sqrt(1+c-s-o);this._w=(n-i)/t,this._x=(r+h)/t,this._y=(a+l)/t,this._z=.25*t}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let s=t.dot(e)+1;return sMath.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=s):(this._x=0,this._y=-t.z,this._z=t.y,this._w=s)):(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=s),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs(Ds(this.dot(t),-1,1)))}rotateTowards(t,e){const s=this.angleTo(t);if(0===s)return this;const i=Math.min(1,e/s);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 s=t._x,i=t._y,r=t._z,n=t._w,o=e._x,a=e._y,h=e._z,l=e._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(t,e){if(0===e)return this;if(1===e)return this.copy(t);const s=this._x,i=this._y,r=this._z,n=this._w;let o=n*t._w+s*t._x+i*t._y+r*t._z;if(o<0?(this._w=-t._w,this._x=-t._x,this._y=-t._y,this._z=-t._z,o=-o):this.copy(t),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 t=1-e;return this._w=t*n+e*this._w,this._x=t*s+e*this._x,this._y=t*i+e*this._y,this._z=t*r+e*this._z,this.normalize(),this}const h=Math.sqrt(a),l=Math.atan2(h,o),c=Math.sin((1-e)*l)/h,u=Math.sin(e*l)/h;return this._w=n*c+this._w*u,this._x=s*c+this._x*u,this._y=i*c+this._y*u,this._z=r*c+this._z*u,this._onChangeCallback(),this}slerpQuaternions(t,e,s){return this.copy(t).slerp(e,s)}random(){const t=2*Math.PI*Math.random(),e=2*Math.PI*Math.random(),s=Math.random(),i=Math.sqrt(1-s),r=Math.sqrt(s);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 Ii{constructor(t=0,e=0,s=0){Ii.prototype.isVector3=!0,this.x=t,this.y=e,this.z=s}set(t,e,s){return void 0===s&&(s=this.z),this.x=t,this.y=e,this.z=s,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(ki.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(ki.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,s=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*s+r[6]*i,this.y=r[1]*e+r[4]*s+r[7]*i,this.z=r[2]*e+r[5]*s+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,s=this.y,i=this.z,r=t.elements,n=1/(r[3]*e+r[7]*s+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*s+r[8]*i+r[12])*n,this.y=(r[1]*e+r[5]*s+r[9]*i+r[13])*n,this.z=(r[2]*e+r[6]*s+r[10]*i+r[14])*n,this}applyQuaternion(t){const e=this.x,s=this.y,i=this.z,r=t.x,n=t.y,o=t.z,a=t.w,h=2*(n*i-o*s),l=2*(o*e-r*i),c=2*(r*s-n*e);return this.x=e+a*h+n*c-o*l,this.y=s+a*l+o*h-r*c,this.z=i+a*c+r*l-n*h,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,s=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*s+r[8]*i,this.y=r[1]*e+r[5]*s+r[9]*i,this.z=r[2]*e+r[6]*s+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=Ds(this.x,t.x,e.x),this.y=Ds(this.y,t.y,e.y),this.z=Ds(this.z,t.z,e.z),this}clampScalar(t,e){return this.x=Ds(this.x,t,e),this.y=Ds(this.y,t,e),this.z=Ds(this.z,t,e),this}clampLength(t,e){const s=this.length();return this.divideScalar(s||1).multiplyScalar(Ds(s,t,e))}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,s){return this.x=t.x+(e.x-t.x)*s,this.y=t.y+(e.y-t.y)*s,this.z=t.z+(e.z-t.z)*s,this}cross(t){return this.crossVectors(this,t)}crossVectors(t,e){const s=t.x,i=t.y,r=t.z,n=e.x,o=e.y,a=e.z;return this.x=i*a-r*o,this.y=r*n-s*a,this.z=s*o-i*n,this}projectOnVector(t){const e=t.lengthSq();if(0===e)return this.set(0,0,0);const s=t.dot(this)/e;return this.copy(t).multiplyScalar(s)}projectOnPlane(t){return Bi.copy(this).projectOnVector(t),this.sub(Bi)}reflect(t){return this.sub(Bi.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 s=this.dot(t)/e;return Math.acos(Ds(s,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,s=this.y-t.y,i=this.z-t.z;return e*e+s*s+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,s){const i=Math.sin(e)*t;return this.x=i*Math.sin(s),this.y=Math.cos(e)*t,this.z=i*Math.cos(s),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,s){return this.x=t*Math.sin(e),this.y=s,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(),s=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=s,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,s=Math.sqrt(1-e*e);return this.x=s*Math.cos(t),this.y=e,this.z=s*Math.sin(t),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const Bi=new Ii,ki=new Ci;class Ri{constructor(t=new Ii(1/0,1/0,1/0),e=new Ii(-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,s=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,Ei),Ei.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,s;return t.normal.x>0?(e=t.normal.x*this.min.x,s=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,s=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,s+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,s+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,s+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,s+=t.normal.z*this.min.z),e<=-t.constant&&s>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(Ui),Di.subVectors(this.max,Ui),Fi.subVectors(t.a,Ui),Ni.subVectors(t.b,Ui),Li.subVectors(t.c,Ui),Vi.subVectors(Ni,Fi),Wi.subVectors(Li,Ni),ji.subVectors(Fi,Li);let e=[0,-Vi.z,Vi.y,0,-Wi.z,Wi.y,0,-ji.z,ji.y,Vi.z,0,-Vi.x,Wi.z,0,-Wi.x,ji.z,0,-ji.x,-Vi.y,Vi.x,0,-Wi.y,Wi.x,0,-ji.y,ji.x,0];return!!Ji(e,Fi,Ni,Li,Di)&&(e=[1,0,0,0,1,0,0,0,1],!!Ji(e,Fi,Ni,Li,Di)&&(Hi.crossVectors(Vi,Wi),e=[Hi.x,Hi.y,Hi.z],Ji(e,Fi,Ni,Li,Di)))}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,Ei).distanceTo(t)}getBoundingSphere(t){return this.isEmpty()?t.makeEmpty():(this.getCenter(t.center),t.radius=.5*this.getSize(Ei).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()||(Pi[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),Pi[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),Pi[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),Pi[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),Pi[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),Pi[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),Pi[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),Pi[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(Pi)),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 Pi=[new Ii,new Ii,new Ii,new Ii,new Ii,new Ii,new Ii,new Ii],Ei=new Ii,Oi=new Ri,Fi=new Ii,Ni=new Ii,Li=new Ii,Vi=new Ii,Wi=new Ii,ji=new Ii,Ui=new Ii,Di=new Ii,Hi=new Ii,qi=new Ii;function Ji(t,e,s,i,r){for(let n=0,o=t.length-3;n<=o;n+=3){qi.fromArray(t,n);const o=r.x*Math.abs(qi.x)+r.y*Math.abs(qi.y)+r.z*Math.abs(qi.z),a=e.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 Ri,Yi=new Ii,Zi=new Ii;class Gi{constructor(t=new Ii,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 s=this.center;void 0!==e?s.copy(e):Xi.setFromPoints(t).getCenter(s);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;Yi.subVectors(t,this.center);const e=Yi.lengthSq();if(e>this.radius*this.radius){const t=Math.sqrt(e),s=.5*(t-this.radius);this.center.addScaledVector(Yi,s/t),this.radius+=s}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):(Zi.subVectors(t.center,this.center).setLength(t.radius),this.expandByPoint(Yi.copy(t.center).add(Zi)),this.expandByPoint(Yi.copy(t.center).sub(Zi))),this)}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return(new this.constructor).copy(this)}}const $i=new Ii,Qi=new Ii,Ki=new Ii,tr=new Ii,er=new Ii,sr=new Ii,ir=new Ii;class rr{constructor(t=new Ii,e=new Ii(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,$i)),this}closestPointToPoint(t,e){e.subVectors(t,this.origin);const s=e.dot(this.direction);return s<0?e.copy(this.origin):e.copy(this.origin).addScaledVector(this.direction,s)}distanceToPoint(t){return Math.sqrt(this.distanceSqToPoint(t))}distanceSqToPoint(t){const e=$i.subVectors(t,this.origin).dot(this.direction);return e<0?this.origin.distanceToSquared(t):($i.copy(this.origin).addScaledVector(this.direction,e),$i.distanceToSquared(t))}distanceSqToSegment(t,e,s,i){Qi.copy(t).add(e).multiplyScalar(.5),Ki.copy(e).sub(t).normalize(),tr.copy(this.origin).sub(Qi);const r=.5*t.distanceTo(e),n=-this.direction.dot(Ki),o=tr.dot(this.direction),a=-tr.dot(Ki),h=tr.lengthSq(),l=Math.abs(1-n*n);let c,u,d,p;if(l>0)if(c=n*a-o,u=n*o-a,p=r*l,c>=0)if(u>=-p)if(u<=p){const t=1/l;c*=t,u*=t,d=c*(c+n*u+2*o)+u*(n*c+u+2*a)+h}else u=r,c=Math.max(0,-(n*u+o)),d=-c*c+u*(u+2*a)+h;else u=-r,c=Math.max(0,-(n*u+o)),d=-c*c+u*(u+2*a)+h;else u<=-p?(c=Math.max(0,-(-n*r+o)),u=c>0?-r:Math.min(Math.max(-r,-a),r),d=-c*c+u*(u+2*a)+h):u<=p?(c=0,u=Math.min(Math.max(-r,-a),r),d=u*(u+2*a)+h):(c=Math.max(0,-(n*r+o)),u=c>0?r:Math.min(Math.max(-r,-a),r),d=-c*c+u*(u+2*a)+h);else u=n>0?-r:r,c=Math.max(0,-(n*u+o)),d=-c*c+u*(u+2*a)+h;return s&&s.copy(this.origin).addScaledVector(this.direction,c),i&&i.copy(Qi).addScaledVector(Ki,u),d}intersectSphere(t,e){$i.subVectors(t.center,this.origin);const s=$i.dot(this.direction),i=$i.dot($i)-s*s,r=t.radius*t.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,e):this.at(o,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 s=-(this.origin.dot(t.normal)+t.constant)/e;return s>=0?s:null}intersectPlane(t,e){const s=this.distanceToPlane(t);return null===s?null:this.at(s,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 s,i,r,n,o,a;const h=1/this.direction.x,l=1/this.direction.y,c=1/this.direction.z,u=this.origin;return h>=0?(s=(t.min.x-u.x)*h,i=(t.max.x-u.x)*h):(s=(t.max.x-u.x)*h,i=(t.min.x-u.x)*h),l>=0?(r=(t.min.y-u.y)*l,n=(t.max.y-u.y)*l):(r=(t.max.y-u.y)*l,n=(t.min.y-u.y)*l),s>n||r>i?null:((r>s||isNaN(s))&&(s=r),(n=0?(o=(t.min.z-u.z)*c,a=(t.max.z-u.z)*c):(o=(t.max.z-u.z)*c,a=(t.min.z-u.z)*c),s>a||o>i?null:((o>s||s!=s)&&(s=o),(a=0?s:i,e)))}intersectsBox(t){return null!==this.intersectBox(t,$i)}intersectTriangle(t,e,s,i,r){er.subVectors(e,t),sr.subVectors(s,t),ir.crossVectors(er,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}tr.subVectors(this.origin,t);const a=n*this.direction.dot(sr.crossVectors(tr,sr));if(a<0)return null;const h=n*this.direction.dot(er.cross(tr));if(h<0)return null;if(a+h>o)return null;const l=-n*tr.dot(ir);return l<0?null:this.at(l/o,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 nr{constructor(t,e,s,i,r,n,o,a,h,l,c,u,d,p,m,y){nr.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,s,i,r,n,o,a,h,l,c,u,d,p,m,y)}set(t,e,s,i,r,n,o,a,h,l,c,u,d,p,m,y){const f=this.elements;return f[0]=t,f[4]=e,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]=c,f[14]=u,f[3]=d,f[7]=p,f[11]=m,f[15]=y,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(t){const e=this.elements,s=t.elements;return e[0]=s[0],e[1]=s[1],e[2]=s[2],e[3]=s[3],e[4]=s[4],e[5]=s[5],e[6]=s[6],e[7]=s[7],e[8]=s[8],e[9]=s[9],e[10]=s[10],e[11]=s[11],e[12]=s[12],e[13]=s[13],e[14]=s[14],e[15]=s[15],this}copyPosition(t){const e=this.elements,s=t.elements;return e[12]=s[12],e[13]=s[13],e[14]=s[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,s){return t.setFromMatrixColumn(this,0),e.setFromMatrixColumn(this,1),s.setFromMatrixColumn(this,2),this}makeBasis(t,e,s){return this.set(t.x,e.x,s.x,0,t.y,e.y,s.y,0,t.z,e.z,s.z,0,0,0,0,1),this}extractRotation(t){const e=this.elements,s=t.elements,i=1/or.setFromMatrixColumn(t,0).length(),r=1/or.setFromMatrixColumn(t,1).length(),n=1/or.setFromMatrixColumn(t,2).length();return e[0]=s[0]*i,e[1]=s[1]*i,e[2]=s[2]*i,e[3]=0,e[4]=s[4]*r,e[5]=s[5]*r,e[6]=s[6]*r,e[7]=0,e[8]=s[8]*n,e[9]=s[9]*n,e[10]=s[10]*n,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,this}makeRotationFromEuler(t){const e=this.elements,s=t.x,i=t.y,r=t.z,n=Math.cos(s),o=Math.sin(s),a=Math.cos(i),h=Math.sin(i),l=Math.cos(r),c=Math.sin(r);if("XYZ"===t.order){const t=n*l,s=n*c,i=o*l,r=o*c;e[0]=a*l,e[4]=-a*c,e[8]=h,e[1]=s+i*h,e[5]=t-r*h,e[9]=-o*a,e[2]=r-t*h,e[6]=i+s*h,e[10]=n*a}else if("YXZ"===t.order){const t=a*l,s=a*c,i=h*l,r=h*c;e[0]=t+r*o,e[4]=i*o-s,e[8]=n*h,e[1]=n*c,e[5]=n*l,e[9]=-o,e[2]=s*o-i,e[6]=r+t*o,e[10]=n*a}else if("ZXY"===t.order){const t=a*l,s=a*c,i=h*l,r=h*c;e[0]=t-r*o,e[4]=-n*c,e[8]=i+s*o,e[1]=s+i*o,e[5]=n*l,e[9]=r-t*o,e[2]=-n*h,e[6]=o,e[10]=n*a}else if("ZYX"===t.order){const t=n*l,s=n*c,i=o*l,r=o*c;e[0]=a*l,e[4]=i*h-s,e[8]=t*h+r,e[1]=a*c,e[5]=r*h+t,e[9]=s*h-i,e[2]=-h,e[6]=o*a,e[10]=n*a}else if("YZX"===t.order){const t=n*a,s=n*h,i=o*a,r=o*h;e[0]=a*l,e[4]=r-t*c,e[8]=i*c+s,e[1]=c,e[5]=n*l,e[9]=-o*l,e[2]=-h*l,e[6]=s*c+i,e[10]=t-r*c}else if("XZY"===t.order){const t=n*a,s=n*h,i=o*a,r=o*h;e[0]=a*l,e[4]=-c,e[8]=h*l,e[1]=t*c+r,e[5]=n*l,e[9]=s*c-i,e[2]=i*c-s,e[6]=o*l,e[10]=r*c+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(hr,t,lr)}lookAt(t,e,s){const i=this.elements;return dr.subVectors(t,e),0===dr.lengthSq()&&(dr.z=1),dr.normalize(),cr.crossVectors(s,dr),0===cr.lengthSq()&&(1===Math.abs(s.z)?dr.x+=1e-4:dr.z+=1e-4,dr.normalize(),cr.crossVectors(s,dr)),cr.normalize(),ur.crossVectors(dr,cr),i[0]=cr.x,i[4]=ur.x,i[8]=dr.x,i[1]=cr.y,i[5]=ur.y,i[9]=dr.y,i[2]=cr.z,i[6]=ur.z,i[10]=dr.z,this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const s=t.elements,i=e.elements,r=this.elements,n=s[0],o=s[4],a=s[8],h=s[12],l=s[1],c=s[5],u=s[9],d=s[13],p=s[2],m=s[6],y=s[10],f=s[14],g=s[3],x=s[7],b=s[11],v=s[15],w=i[0],M=i[4],S=i[8],_=i[12],A=i[1],T=i[5],z=i[9],C=i[13],I=i[2],B=i[6],k=i[10],R=i[14],P=i[3],E=i[7],O=i[11],F=i[15];return r[0]=n*w+o*A+a*I+h*P,r[4]=n*M+o*T+a*B+h*E,r[8]=n*S+o*z+a*k+h*O,r[12]=n*_+o*C+a*R+h*F,r[1]=l*w+c*A+u*I+d*P,r[5]=l*M+c*T+u*B+d*E,r[9]=l*S+c*z+u*k+d*O,r[13]=l*_+c*C+u*R+d*F,r[2]=p*w+m*A+y*I+f*P,r[6]=p*M+m*T+y*B+f*E,r[10]=p*S+m*z+y*k+f*O,r[14]=p*_+m*C+y*R+f*F,r[3]=g*w+x*A+b*I+v*P,r[7]=g*M+x*T+b*B+v*E,r[11]=g*S+x*z+b*k+v*O,r[15]=g*_+x*C+b*R+v*F,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],s=t[4],i=t[8],r=t[12],n=t[1],o=t[5],a=t[9],h=t[13],l=t[2],c=t[6],u=t[10],d=t[14];return t[3]*(+r*a*c-i*h*c-r*o*u+s*h*u+i*o*d-s*a*d)+t[7]*(+e*a*d-e*h*u+r*n*u-i*n*d+i*h*l-r*a*l)+t[11]*(+e*h*c-e*o*d-r*n*c+s*n*d+r*o*l-s*h*l)+t[15]*(-i*o*l-e*a*c+e*o*u+i*n*c-s*n*u+s*a*l)}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,s){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]=s),this}invert(){const t=this.elements,e=t[0],s=t[1],i=t[2],r=t[3],n=t[4],o=t[5],a=t[6],h=t[7],l=t[8],c=t[9],u=t[10],d=t[11],p=t[12],m=t[13],y=t[14],f=t[15],g=c*y*h-m*u*h+m*a*d-o*y*d-c*a*f+o*u*f,x=p*u*h-l*y*h-p*a*d+n*y*d+l*a*f-n*u*f,b=l*m*h-p*c*h+p*o*d-n*m*d-l*o*f+n*c*f,v=p*c*a-l*m*a-p*o*u+n*m*u+l*o*y-n*c*y,w=e*g+s*x+i*b+r*v;if(0===w)return this.set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);const M=1/w;return t[0]=g*M,t[1]=(m*u*r-c*y*r-m*i*d+s*y*d+c*i*f-s*u*f)*M,t[2]=(o*y*r-m*a*r+m*i*h-s*y*h-o*i*f+s*a*f)*M,t[3]=(c*a*r-o*u*r-c*i*h+s*u*h+o*i*d-s*a*d)*M,t[4]=x*M,t[5]=(l*y*r-p*u*r+p*i*d-e*y*d-l*i*f+e*u*f)*M,t[6]=(p*a*r-n*y*r-p*i*h+e*y*h+n*i*f-e*a*f)*M,t[7]=(n*u*r-l*a*r+l*i*h-e*u*h-n*i*d+e*a*d)*M,t[8]=b*M,t[9]=(p*c*r-l*m*r-p*s*d+e*m*d+l*s*f-e*c*f)*M,t[10]=(n*m*r-p*o*r+p*s*h-e*m*h-n*s*f+e*o*f)*M,t[11]=(l*o*r-n*c*r-l*s*h+e*c*h+n*s*d-e*o*d)*M,t[12]=v*M,t[13]=(l*m*i-p*c*i+p*s*u-e*m*u-l*s*y+e*c*y)*M,t[14]=(p*o*i-n*m*i-p*s*a+e*m*a+n*s*y-e*o*y)*M,t[15]=(n*c*i-l*o*i+l*s*a-e*c*a-n*s*u+e*o*u)*M,this}scale(t){const e=this.elements,s=t.x,i=t.y,r=t.z;return e[0]*=s,e[4]*=i,e[8]*=r,e[1]*=s,e[5]*=i,e[9]*=r,e[2]*=s,e[6]*=i,e[10]*=r,e[3]*=s,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],s=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,s,i))}makeTranslation(t,e,s){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,s,0,0,0,1),this}makeRotationX(t){const e=Math.cos(t),s=Math.sin(t);return this.set(1,0,0,0,0,e,-s,0,0,s,e,0,0,0,0,1),this}makeRotationY(t){const e=Math.cos(t),s=Math.sin(t);return this.set(e,0,s,0,0,1,0,0,-s,0,e,0,0,0,0,1),this}makeRotationZ(t){const e=Math.cos(t),s=Math.sin(t);return this.set(e,-s,0,0,s,e,0,0,0,0,1,0,0,0,0,1),this}makeRotationAxis(t,e){const s=Math.cos(e),i=Math.sin(e),r=1-s,n=t.x,o=t.y,a=t.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(t,e,s){return this.set(t,0,0,0,0,e,0,0,0,0,s,0,0,0,0,1),this}makeShear(t,e,s,i,r,n){return this.set(1,s,r,0,t,1,n,0,e,i,1,0,0,0,0,1),this}compose(t,e,s){const i=this.elements,r=e._x,n=e._y,o=e._z,a=e._w,h=r+r,l=n+n,c=o+o,u=r*h,d=r*l,p=r*c,m=n*l,y=n*c,f=o*c,g=a*h,x=a*l,b=a*c,v=s.x,w=s.y,M=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)*w,i[5]=(1-(u+f))*w,i[6]=(y+g)*w,i[7]=0,i[8]=(p+x)*M,i[9]=(y-g)*M,i[10]=(1-(u+m))*M,i[11]=0,i[12]=t.x,i[13]=t.y,i[14]=t.z,i[15]=1,this}decompose(t,e,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),t.x=i[12],t.y=i[13],t.z=i[14],ar.copy(this);const a=1/r,h=1/n,l=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]*=l,ar.elements[9]*=l,ar.elements[10]*=l,e.setFromRotationMatrix(ar),s.x=r,s.y=n,s.z=o,this}makePerspective(t,e,s,i,r,n,o=2e3){const a=this.elements,h=2*r/(e-t),l=2*r/(s-i),c=(e+t)/(e-t),u=(s+i)/(s-i);let d,p;if(o===Os)d=-(n+r)/(n-r),p=-2*n*r/(n-r);else{if(o!==Fs)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]=c,a[12]=0,a[1]=0,a[5]=l,a[9]=u,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(t,e,s,i,r,n,o=2e3){const a=this.elements,h=1/(e-t),l=1/(s-i),c=1/(n-r),u=(e+t)*h,d=(s+i)*l;let p,m;if(o===Os)p=(n+r)*c,m=-2*c;else{if(o!==Fs)throw new Error("THREE.Matrix4.makeOrthographic(): Invalid coordinate system: "+o);p=r*c,m=-1*c}return a[0]=2*h,a[4]=0,a[8]=0,a[12]=-u,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(t){const e=this.elements,s=t.elements;for(let t=0;t<16;t++)if(e[t]!==s[t])return!1;return!0}fromArray(t,e=0){for(let s=0;s<16;s++)this.elements[s]=t[s+e];return this}toArray(t=[],e=0){const s=this.elements;return t[e]=s[0],t[e+1]=s[1],t[e+2]=s[2],t[e+3]=s[3],t[e+4]=s[4],t[e+5]=s[5],t[e+6]=s[6],t[e+7]=s[7],t[e+8]=s[8],t[e+9]=s[9],t[e+10]=s[10],t[e+11]=s[11],t[e+12]=s[12],t[e+13]=s[13],t[e+14]=s[14],t[e+15]=s[15],t}}const or=new Ii,ar=new nr,hr=new Ii(0,0,0),lr=new Ii(1,1,1),cr=new Ii,ur=new Ii,dr=new Ii,pr=new nr,mr=new Ci;class yr{constructor(t=0,e=0,s=0,i=yr.DEFAULT_ORDER){this.isEuler=!0,this._x=t,this._y=e,this._z=s,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,s,i=this._order){return this._x=t,this._y=e,this._z=s,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,s=!0){const i=t.elements,r=i[0],n=i[4],o=i[8],a=i[1],h=i[5],l=i[9],c=i[2],u=i[6],d=i[10];switch(e){case"XYZ":this._y=Math.asin(Ds(o,-1,1)),Math.abs(o)<.9999999?(this._x=Math.atan2(-l,d),this._z=Math.atan2(-n,r)):(this._x=Math.atan2(u,h),this._z=0);break;case"YXZ":this._x=Math.asin(-Ds(l,-1,1)),Math.abs(l)<.9999999?(this._y=Math.atan2(o,d),this._z=Math.atan2(a,h)):(this._y=Math.atan2(-c,r),this._z=0);break;case"ZXY":this._x=Math.asin(Ds(u,-1,1)),Math.abs(u)<.9999999?(this._y=Math.atan2(-c,d),this._z=Math.atan2(-n,h)):(this._y=0,this._z=Math.atan2(a,r));break;case"ZYX":this._y=Math.asin(-Ds(c,-1,1)),Math.abs(c)<.9999999?(this._x=Math.atan2(u,d),this._z=Math.atan2(a,r)):(this._x=0,this._z=Math.atan2(-n,h));break;case"YZX":this._z=Math.asin(Ds(a,-1,1)),Math.abs(a)<.9999999?(this._x=Math.atan2(-l,h),this._y=Math.atan2(-c,r)):(this._x=0,this._y=Math.atan2(o,d));break;case"XZY":this._z=Math.asin(-Ds(n,-1,1)),Math.abs(n)<.9999999?(this._x=Math.atan2(u,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: "+e)}return this._order=e,!0===s&&this._onChangeCallback(),this}setFromQuaternion(t,e,s){return pr.makeRotationFromQuaternion(t),this.setFromRotationMatrix(pr,e,s)}setFromVector3(t,e=this._order){return this.set(t.x,t.y,t.z,e)}reorder(t){return mr.setFromEuler(this),this.setFromQuaternion(mr,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}}yr.DEFAULT_ORDER="XYZ";class fr{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 s=e.shapes;if(Array.isArray(s))for(let e=0,i=s.length;e0){i.children=[];for(let e=0;e0){i.animations=[];for(let e=0;e0&&(s.geometries=e),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),c.length>0&&(s.nodes=c)}return s.object=i,s;function n(t){const e=[];for(const s in t){const i=t[s];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,s,i,r){Pr.subVectors(i,e),Er.subVectors(s,e),Or.subVectors(t,e);const n=Pr.dot(Pr),o=Pr.dot(Er),a=Pr.dot(Or),h=Er.dot(Er),l=Er.dot(Or),c=n*h-o*o;if(0===c)return r.set(0,0,0),null;const u=1/c,d=(h*a-o*l)*u,p=(n*l-o*a)*u;return r.set(1-d-p,p,d)}static containsPoint(t,e,s,i){return null!==this.getBarycoord(t,e,s,i,Fr)&&(Fr.x>=0&&Fr.y>=0&&Fr.x+Fr.y<=1)}static getInterpolation(t,e,s,i,r,n,o,a){return null===this.getBarycoord(t,e,s,i,Fr)?(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,Fr.x),a.addScaledVector(n,Fr.y),a.addScaledVector(o,Fr.z),a)}static getInterpolatedAttribute(t,e,s,i,r,n){return Dr.setScalar(0),Hr.setScalar(0),qr.setScalar(0),Dr.fromBufferAttribute(t,e),Hr.fromBufferAttribute(t,s),qr.fromBufferAttribute(t,i),n.setScalar(0),n.addScaledVector(Dr,r.x),n.addScaledVector(Hr,r.y),n.addScaledVector(qr,r.z),n}static isFrontFacing(t,e,s,i){return Pr.subVectors(s,e),Er.subVectors(t,e),Pr.cross(Er).dot(i)<0}set(t,e,s){return this.a.copy(t),this.b.copy(e),this.c.copy(s),this}setFromPointsAndIndices(t,e,s,i){return this.a.copy(t[e]),this.b.copy(t[s]),this.c.copy(t[i]),this}setFromAttributeAndIndices(t,e,s,i){return this.a.fromBufferAttribute(t,e),this.b.fromBufferAttribute(t,s),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 Pr.subVectors(this.c,this.b),Er.subVectors(this.a,this.b),.5*Pr.cross(Er).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,s,i,r){return Jr.getInterpolation(t,this.a,this.b,this.c,e,s,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 s=this.a,i=this.b,r=this.c;let n,o;Nr.subVectors(i,s),Lr.subVectors(r,s),Wr.subVectors(t,s);const a=Nr.dot(Wr),h=Lr.dot(Wr);if(a<=0&&h<=0)return e.copy(s);jr.subVectors(t,i);const l=Nr.dot(jr),c=Lr.dot(jr);if(l>=0&&c<=l)return e.copy(i);const u=a*c-l*h;if(u<=0&&a>=0&&l<=0)return n=a/(a-l),e.copy(s).addScaledVector(Nr,n);Ur.subVectors(t,r);const d=Nr.dot(Ur),p=Lr.dot(Ur);if(p>=0&&d<=p)return e.copy(r);const m=d*h-a*p;if(m<=0&&h>=0&&p<=0)return o=h/(h-p),e.copy(s).addScaledVector(Lr,o);const y=l*p-d*c;if(y<=0&&c-l>=0&&d-p>=0)return Vr.subVectors(r,i),o=(c-l)/(c-l+(d-p)),e.copy(i).addScaledVector(Vr,o);const f=1/(y+m+u);return n=m*f,o=u*f,e.copy(s).addScaledVector(Nr,n).addScaledVector(Lr,o)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}const Xr={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 Gr(t,e,s){return s<0&&(s+=1),s>1&&(s-=1),s<1/6?t+6*(e-t)*s:s<.5?e:s<2/3?t+6*(e-t)*(2/3-s):t}class $r{constructor(t,e,s){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(t,e,s)}set(t,e,s){if(void 0===e&&void 0===s){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,s);return this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t,e=Ge){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(255&t)/255,ui.toWorkingColorSpace(this,e),this}setRGB(t,e,s,i=ui.workingColorSpace){return this.r=t,this.g=e,this.b=s,ui.toWorkingColorSpace(this,i),this}setHSL(t,e,s,i=ui.workingColorSpace){if(t=Hs(t,1),e=Ds(e,0,1),s=Ds(s,0,1),0===e)this.r=this.g=this.b=s;else{const i=s<=.5?s*(1+e):s+e-s*e,r=2*s-i;this.r=Gr(r,i,t+1/3),this.g=Gr(r,i,t),this.b=Gr(r,i,t-1/3)}return ui.toWorkingColorSpace(this,i),this}setStyle(t,e=Ge){function s(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 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,e);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,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(o))return s(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 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,e);if(6===r)return this.setHex(parseInt(s,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=Ge){const s=Xr[t.toLowerCase()];return void 0!==s?this.setHex(s,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=di(t.r),this.g=di(t.g),this.b=di(t.b),this}copyLinearToSRGB(t){return this.r=pi(t.r),this.g=pi(t.g),this.b=pi(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(t=Ge){return ui.fromWorkingColorSpace(Qr.copy(this),t),65536*Math.round(Ds(255*Qr.r,0,255))+256*Math.round(Ds(255*Qr.g,0,255))+Math.round(Ds(255*Qr.b,0,255))}getHexString(t=Ge){return("000000"+this.getHex(t).toString(16)).slice(-6)}getHSL(t,e=ui.workingColorSpace){ui.fromWorkingColorSpace(Qr.copy(this),e);const s=Qr.r,i=Qr.g,r=Qr.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 t=n-o;switch(h=l<=.5?t/(n+o):t/(2-n-o),n){case s:a=(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 s=t[e];if(void 0===s){console.warn(`THREE.Material: parameter '${e}' has value of undefined.`);continue}const i=this[e];void 0!==i?i&&i.isColor?i.set(s):i&&i.isVector3&&s&&s.isVector3?i.copy(s):this[e]=s: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 s={metadata:{version:4.6,type:"Material",generator:"Material.toJSON"}};function i(t){const e=[];for(const s in t){const i=t[s];delete i.metadata,e.push(i)}return e}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(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(s.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(s.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).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(t).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(s.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(t).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(t).uuid),this.map&&this.map.isTexture&&(s.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(s.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(s.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(s.lightMap=this.lightMap.toJSON(t).uuid,s.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(s.aoMap=this.aoMap.toJSON(t).uuid,s.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(s.bumpMap=this.bumpMap.toJSON(t).uuid,s.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(s.normalMap=this.normalMap.toJSON(t).uuid,s.normalMapType=this.normalMapType,s.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(s.displacementMap=this.displacementMap.toJSON(t).uuid,s.displacementScale=this.displacementScale,s.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(s.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(s.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(s.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(s.specularMap=this.specularMap.toJSON(t).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(s.specularIntensityMap=this.specularIntensityMap.toJSON(t).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(s.specularColorMap=this.specularColorMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(s.envMap=this.envMap.toJSON(t).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(t).uuid),void 0!==this.transmission&&(s.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(s.transmissionMap=this.transmissionMap.toJSON(t).uuid),void 0!==this.thickness&&(s.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(s.thicknessMap=this.thicknessMap.toJSON(t).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),0!==this.side&&(s.side=this.side),!0===this.vertexColors&&(s.vertexColors=!0),this.opacity<1&&(s.opacity=this.opacity),!0===this.transparent&&(s.transparent=!0),204!==this.blendSrc&&(s.blendSrc=this.blendSrc),205!==this.blendDst&&(s.blendDst=this.blendDst),100!==this.blendEquation&&(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),519!==this.stencilFunc&&(s.stencilFunc=this.stencilFunc),0!==this.stencilRef&&(s.stencilRef=this.stencilRef),255!==this.stencilFuncMask&&(s.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==es&&(s.stencilFail=this.stencilFail),this.stencilZFail!==es&&(s.stencilZFail=this.stencilZFail),this.stencilZPass!==es&&(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),e){const e=i(t.textures),r=i(t.images);e.length>0&&(s.textures=e),r.length>0&&(s.images=r)}return s}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 s=null;if(null!==e){const t=e.length;s=new Array(t);for(let i=0;i!==t;++i)s[i]=e[i].clone()}return this.clippingPlanes=s,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 en extends tn{constructor(t){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new $r(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 yr,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(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 sn=rn();function rn(){const t=new ArrayBuffer(4),e=new Float32Array(t),s=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 n=new Uint32Array(2048),o=new Uint32Array(64),a=new Uint32Array(64);for(let t=1;t<1024;++t){let e=t<<13,s=0;for(;!(8388608&e);)e<<=1,s-=8388608;e&=-8388609,s+=947912704,n[t]=e|s}for(let t=1024;t<2048;++t)n[t]=939524096+(t-1024<<13);for(let t=1;t<31;++t)o[t]=t<<23;o[31]=1199570944,o[32]=2147483648;for(let t=33;t<63;++t)o[t]=2147483648+(t-32<<23);o[63]=3347054592;for(let t=1;t<64;++t)32!==t&&(a[t]=1024);return{floatView:e,uint32View:s,baseTable:i,shiftTable:r,mantissaTable:n,exponentTable:o,offsetTable:a}}function nn(t){Math.abs(t)>65504&&console.warn("THREE.DataUtils.toHalfFloat(): Value out of range."),t=Ds(t,-65504,65504),sn.floatView[0]=t;const e=sn.uint32View[0],s=e>>23&511;return sn.baseTable[s]+((8388607&e)>>sn.shiftTable[s])}function on(t){const e=t>>10;return sn.uint32View[0]=sn.mantissaTable[sn.offsetTable[e]+(1023&t)]+sn.exponentTable[e],sn.floatView[0]}const an={toHalfFloat:nn,fromHalfFloat:on},hn=new Ii,ln=new Zs;let cn=0;class un{constructor(t,e,s=!1){if(Array.isArray(t))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,Object.defineProperty(this,"id",{value:cn++}),this.name="",this.array=t,this.itemSize=e,this.count=void 0!==t?t.length/e:0,this.normalized=s,this.usage=_s,this.updateRanges=[],this.gpuType=Rt,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,s){t*=this.itemSize,s*=e.itemSize;for(let i=0,r=this.itemSize;ie.count&&console.warn("THREE.BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry."),e.needsUpdate=!0}return this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Ri);const t=this.attributes.position,e=this.morphAttributes.position;if(t&&t.isGLBufferAttribute)return console.error("THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.",this),void this.boundingBox.set(new Ii(-1/0,-1/0,-1/0),new Ii(1/0,1/0,1/0));if(void 0!==t){if(this.boundingBox.setFromBufferAttribute(t),e)for(let t=0,s=e.length;t0&&(t.userData=this.userData),void 0!==this.parameters){const e=this.parameters;for(const s in e)void 0!==e[s]&&(t[s]=e[s]);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 s=this.attributes;for(const e in s){const i=s[e];t.data.attributes[e]=i.toJSON(t.data)}const i={};let r=!1;for(const e in this.morphAttributes){const s=this.morphAttributes[e],n=[];for(let e=0,i=s.length;e0&&(i[e]=n,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const n=this.groups;n.length>0&&(t.data.groups=JSON.parse(JSON.stringify(n)));const o=this.boundingSphere;return null!==o&&(t.data.boundingSphere={center:o.center.toArray(),radius:o.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 s=t.index;null!==s&&this.setIndex(s.clone(e));const i=t.attributes;for(const t in i){const s=i[t];this.setAttribute(t,s.clone(e))}const r=t.morphAttributes;for(const t in r){const s=[],i=r[t];for(let t=0,r=i.length;t0){const s=t[e[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=s.length;t(t.far-t.near)**2)return}In.copy(r).invert(),Bn.copy(t.ray).applyMatrix4(In),null!==s.boundingBox&&!1===Bn.intersectsBox(s.boundingBox)||this._computeIntersections(t,e,Bn)}}_computeIntersections(t,e,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,c=r.attributes.normal,u=r.groups,d=r.drawRange;if(null!==o)if(Array.isArray(n))for(let r=0,a=u.length;rs.far?null:{distance:l,point:Vn.clone(),object:t}}(t,e,s,i,Pn,En,On,Ln);if(c){const t=new Ii;Jr.getBarycoord(Ln,Pn,En,On,t),r&&(c.uv=Jr.getInterpolatedAttribute(r,a,h,l,t,new Zs)),n&&(c.uv1=Jr.getInterpolatedAttribute(n,a,h,l,t,new Zs)),o&&(c.normal=Jr.getInterpolatedAttribute(o,a,h,l,t,new Ii),c.normal.dot(i.direction)>0&&c.normal.multiplyScalar(-1));const e={a:a,b:h,c:l,normal:new Ii,materialIndex:0};Jr.getNormal(Pn,En,On,e.normal),c.face=e,c.barycoord=t}return c}class Un extends Cn{constructor(t=1,e=1,s=1,i=1,r=1,n=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,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=[],c=[];let u=0,d=0;function p(t,e,s,i,r,n,p,m,y,f,g){const x=n/y,b=p/f,v=n/2,w=p/2,M=m/2,S=y+1,_=f+1;let A=0,T=0;const z=new Ii;for(let n=0;n<_;n++){const o=n*b-w;for(let a=0;a0?1:-1,l.push(z.x,z.y,z.z),c.push(a/y),c.push(1-n/f),A+=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 s={};for(const t in this.extensions)!0===this.extensions[t]&&(s[t]=!0);return Object.keys(s).length>0&&(e.extensions=s),e}}class Yn extends Rr{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new nr,this.projectionMatrix=new nr,this.projectionMatrixInverse=new nr,this.coordinateSystem=Os}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 Zn=new Ii,Gn=new Zs,$n=new Zs;class Qn extends Yn{constructor(t=50,e=1,s=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=t,this.zoom=1,this.near=s,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*js*Math.atan(e),this.updateProjectionMatrix()}getFocalLength(){const t=Math.tan(.5*Ws*this.fov);return.5*this.getFilmHeight()/t}getEffectiveFOV(){return 2*js*Math.atan(Math.tan(.5*Ws*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,s){Zn.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),e.set(Zn.x,Zn.y).multiplyScalar(-t/Zn.z),Zn.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),s.set(Zn.x,Zn.y).multiplyScalar(-t/Zn.z)}getViewSize(t,e){return this.getViewBounds(t,Gn,$n),e.subVectors($n,Gn)}setViewOffset(t,e,s,i,r,n){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=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 t=this.near;let e=t*Math.tan(.5*Ws*this.fov)/this.zoom,s=2*e,i=this.aspect*s,r=-.5*i;const n=this.view;if(null!==this.view&&this.view.enabled){const t=n.fullWidth,o=n.fullHeight;r+=n.offsetX*i/t,e-=n.offsetY*s/o,i*=n.width/t,s*=n.height/o}const o=this.filmOffset;0!==o&&(r+=t*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,e,e-s,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 Kn=-90;class to extends Rr{constructor(t,e,s){super(),this.type="CubeCamera",this.renderTarget=s,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new Qn(Kn,1,t,e);i.layers=this.layers,this.add(i);const r=new Qn(Kn,1,t,e);r.layers=this.layers,this.add(r);const n=new Qn(Kn,1,t,e);n.layers=this.layers,this.add(n);const o=new Qn(Kn,1,t,e);o.layers=this.layers,this.add(o);const a=new Qn(Kn,1,t,e);a.layers=this.layers,this.add(a);const h=new Qn(Kn,1,t,e);h.layers=this.layers,this.add(h)}updateCoordinateSystem(){const t=this.coordinateSystem,e=this.children.concat(),[s,i,r,n,o,a]=e;for(const t of e)this.remove(t);if(t===Os)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(t!==Fs)throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+t);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 t of e)this.add(t),t.updateMatrixWorld()}update(t,e){null===this.parent&&this.updateMatrixWorld();const{renderTarget:s,activeMipmapLevel:i}=this;this.coordinateSystem!==t.coordinateSystem&&(this.coordinateSystem=t.coordinateSystem,this.updateCoordinateSystem());const[r,n,o,a,h,l]=this.children,c=t.getRenderTarget(),u=t.getActiveCubeFace(),d=t.getActiveMipmapLevel(),p=t.xr.enabled;t.xr.enabled=!1;const m=s.texture.generateMipmaps;s.texture.generateMipmaps=!1,t.setRenderTarget(s,0,i),t.render(e,r),t.setRenderTarget(s,1,i),t.render(e,n),t.setRenderTarget(s,2,i),t.render(e,o),t.setRenderTarget(s,3,i),t.render(e,a),t.setRenderTarget(s,4,i),t.render(e,h),s.texture.generateMipmaps=m,t.setRenderTarget(s,5,i),t.render(e,l),t.setRenderTarget(c,u,d),t.xr.enabled=p,s.texture.needsPMREMUpdate=!0}}class eo extends vi{constructor(t,e,s,i,r,n,o,a,h,l){super(t=void 0!==t?t:[],e=void 0!==e?e:ht,s,i,r,n,o,a,h,l),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}class so extends Si{constructor(t=1,e={}){super(t,t,e),this.isWebGLCubeRenderTarget=!0;const s={width:t,height:t,depth:1},i=[s,s,s,s,s,s];this.texture=new eo(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:wt}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 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 Un(5,5,5),r=new Xn({name:"CubemapFromEquirect",uniforms:Dn(s.uniforms),vertexShader:s.vertexShader,fragmentShader:s.fragmentShader,side:1,blending:0});r.uniforms.tEquirect.value=e;const n=new Wn(i,r),o=e.minFilter;e.minFilter===_t&&(e.minFilter=wt);return new to(1,10,this).update(t,n),e.minFilter=o,n.geometry.dispose(),n.material.dispose(),this}clear(t,e,s,i){const r=t.getRenderTarget();for(let r=0;r<6;r++)t.setRenderTarget(this,r),t.clear(e,s,i);t.setRenderTarget(r)}}class io{constructor(t,e=25e-5){this.isFogExp2=!0,this.name="",this.color=new $r(t),this.density=e}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(t,e=1,s=1e3){this.isFog=!0,this.name="",this.color=new $r(t),this.near=e,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 Rr{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 yr,this.environmentIntensity=1,this.environmentRotation=new yr,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 oo{constructor(t,e){this.isInterleavedBuffer=!0,this.array=t,this.stride=e,this.count=void 0!==t?t.length/e:0,this.usage=_s,this.updateRanges=[],this.version=0,this.uuid=Us()}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,s){t*=this.stride,s*=e.stride;for(let i=0,r=this.stride;it.far||e.push({distance:a,point:uo.clone(),uv:Jr.getInterpolation(uo,xo,bo,vo,wo,Mo,So,new Zs),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 Ao(t,e,s,i,r,n){yo.subVectors(t,s).addScalar(.5).multiply(i),void 0!==r?(fo.x=n*yo.x-r*yo.y,fo.y=r*yo.x+n*yo.y):fo.copy(yo),t.copy(e),t.x+=fo.x,t.y+=fo.y,t.applyMatrix4(go)}const To=new Ii,zo=new Ii;class Co extends Rr{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,s=e.length;t0){let s,i;for(s=1,i=e.length;s0){To.setFromMatrixPosition(this.matrixWorld);const s=t.ray.origin.distanceTo(To);this.getObjectForDistance(s).raycast(t,e)}}update(t){const e=this.levels;if(e.length>1){To.setFromMatrixPosition(t.matrixWorld),zo.setFromMatrixPosition(this.matrixWorld);const s=To.distanceTo(zo)/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;i1?null:e.copy(t.start).addScaledVector(s,r)}intersectsLine(t){const e=this.distanceToPoint(t.start),s=this.distanceToPoint(t.end);return e<0&&s>0||s<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 s=e||ea.getNormalMatrix(t),i=this.coplanarPoint(Ko).applyMatrix4(t),r=this.normal.applyMatrix3(s).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 ia=new Gi,ra=new Ii;class na{constructor(t=new sa,e=new sa,s=new sa,i=new sa,r=new sa,n=new sa){this.planes=[t,e,s,i,r,n]}set(t,e,s,i,r,n){const o=this.planes;return o[0].copy(t),o[1].copy(e),o[2].copy(s),o[3].copy(i),o[4].copy(r),o[5].copy(n),this}copy(t){const e=this.planes;for(let s=0;s<6;s++)e[s].copy(t.planes[s]);return this}setFromProjectionMatrix(t,e=2e3){const s=this.planes,i=t.elements,r=i[0],n=i[1],o=i[2],a=i[3],h=i[4],l=i[5],c=i[6],u=i[7],d=i[8],p=i[9],m=i[10],y=i[11],f=i[12],g=i[13],x=i[14],b=i[15];if(s[0].setComponents(a-r,u-h,y-d,b-f).normalize(),s[1].setComponents(a+r,u+h,y+d,b+f).normalize(),s[2].setComponents(a+n,u+l,y+p,b+g).normalize(),s[3].setComponents(a-n,u-l,y-p,b-g).normalize(),s[4].setComponents(a-o,u-c,y-m,b-x).normalize(),e===Os)s[5].setComponents(a+o,u+c,y+m,b+x).normalize();else{if(e!==Fs)throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+e);s[5].setComponents(o,c,m,x).normalize()}return this}intersectsObject(t){if(void 0!==t.boundingSphere)null===t.boundingSphere&&t.computeBoundingSphere(),ia.copy(t.boundingSphere).applyMatrix4(t.matrixWorld);else{const e=t.geometry;null===e.boundingSphere&&e.computeBoundingSphere(),ia.copy(e.boundingSphere).applyMatrix4(t.matrixWorld)}return this.intersectsSphere(ia)}intersectsSprite(t){return ia.center.set(0,0,0),ia.radius=.7071067811865476,ia.applyMatrix4(t.matrixWorld),this.intersectsSphere(ia)}intersectsSphere(t){const e=this.planes,s=t.center,i=-t.radius;for(let t=0;t<6;t++){if(e[t].distanceToPoint(s)0?t.max.x:t.min.x,ra.y=i.normal.y>0?t.max.y:t.min.y,ra.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(ra)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let s=0;s<6;s++)if(e[s].distanceToPoint(t)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}function oa(t,e){return t-e}function aa(t,e){return t.z-e.z}function ha(t,e){return e.z-t.z}class la{constructor(){this.index=0,this.pool=[],this.list=[]}push(t,e,s,i){const r=this.pool,n=this.list;this.index>=r.length&&r.push({start:-1,count:-1,z:-1,index:-1});const o=r[this.index];n.push(o),this.index++,o.start=t,o.count=e,o.z=s,o.index=i}reset(){this.list.length=0,this.index=0}}const ca=new nr,ua=new $r(1,1,1),da=new na,pa=new Ri,ma=new Gi,ya=new Ii,fa=new Ii,ga=new Ii,xa=new la,ba=new Wn,va=[];function wa(t,e,s=0){const i=e.itemSize;if(t.isInterleavedBufferAttribute||t.array.constructor!==e.array.constructor){const r=t.count;for(let n=0;n65535?new Uint32Array(i):new Uint16Array(i);e.setIndex(new un(t,1))}this._geometryInitialized=!0}}_validateGeometry(t){const e=this.geometry;if(Boolean(t.getIndex())!==Boolean(e.getIndex()))throw new Error('THREE.BatchedMesh: All geometries must consistently have "index".');for(const s in e.attributes){if(!t.hasAttribute(s))throw new Error(`THREE.BatchedMesh: Added geometry missing "${s}". All geometries must have consistent attributes.`);const i=t.getAttribute(s),r=e.getAttribute(s);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("THREE.BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}validateInstanceId(t){const e=this._instanceInfo;if(t<0||t>=e.length||!1===e[t].active)throw new Error(`THREE.BatchedMesh: Invalid instanceId ${t}. Instance is either out of range or has been deleted.`)}validateGeometryId(t){const e=this._geometryInfo;if(t<0||t>=e.length||!1===e[t].active)throw new Error(`THREE.BatchedMesh: Invalid geometryId ${t}. Geometry is either out of range or has been deleted.`)}setCustomSort(t){return this.customSort=t,this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Ri);const t=this.boundingBox,e=this._instanceInfo;t.makeEmpty();for(let s=0,i=e.length;s=this.maxInstanceCount&&0===this._availableInstanceIds.length)throw new Error("THREE.BatchedMesh: Maximum item count reached.");const e={visible:!0,active:!0,geometryIndex:t};let s=null;this._availableInstanceIds.length>0?(this._availableInstanceIds.sort(oa),s=this._availableInstanceIds.shift(),this._instanceInfo[s]=e):(s=this._instanceInfo.length,this._instanceInfo.push(e));const i=this._matricesTexture;ca.identity().toArray(i.image.data,16*s),i.needsUpdate=!0;const r=this._colorsTexture;return r&&(ua.toArray(r.image.data,4*s),r.needsUpdate=!0),this._visibilityChanged=!0,s}addGeometry(t,e=-1,s=-1){this._initializeGeometry(t),this._validateGeometry(t);const i={vertexStart:-1,vertexCount:-1,reservedVertexCount:-1,indexStart:-1,indexCount:-1,reservedIndexCount:-1,start:-1,count:-1,boundingBox:null,boundingSphere:null,active:!0},r=this._geometryInfo;i.vertexStart=this._nextVertexStart,i.reservedVertexCount=-1===e?t.getAttribute("position").count:e;const n=t.getIndex();if(null!==n&&(i.indexStart=this._nextIndexStart,i.reservedIndexCount=-1===s?n.count:s),-1!==i.indexStart&&i.indexStart+i.reservedIndexCount>this._maxIndexCount||i.vertexStart+i.reservedVertexCount>this._maxVertexCount)throw new Error("THREE.BatchedMesh: Reserved space request exceeds the maximum buffer size.");let o;return this._availableGeometryIds.length>0?(this._availableGeometryIds.sort(oa),o=this._availableGeometryIds.shift(),r[o]=i):(o=this._geometryCount,this._geometryCount++,r.push(i)),this.setGeometryAt(o,t),this._nextIndexStart=i.indexStart+i.reservedIndexCount,this._nextVertexStart=i.vertexStart+i.reservedVertexCount,o}setGeometryAt(t,e){if(t>=this._geometryCount)throw new Error("THREE.BatchedMesh: Maximum geometry count reached.");this._validateGeometry(e);const s=this.geometry,i=null!==s.getIndex(),r=s.getIndex(),n=e.getIndex(),o=this._geometryInfo[t];if(i&&n.count>o.reservedIndexCount||e.attributes.position.count>o.reservedVertexCount)throw new Error("THREE.BatchedMesh: Reserved space not large enough for provided geometry.");const a=o.vertexStart,h=o.reservedVertexCount;o.vertexCount=e.getAttribute("position").count;for(const t in s.attributes){const i=e.getAttribute(t),r=s.getAttribute(t);wa(i,r,a);const n=i.itemSize;for(let t=i.count,e=h;t=e.length||!1===e[t].active)return this;const s=this._instanceInfo;for(let e=0,i=s.length;ee)).sort(((t,e)=>s[t].vertexStart-s[e].vertexStart)),r=this.geometry;for(let n=0,o=s.length;n=this._geometryCount)return null;const s=this.geometry,i=this._geometryInfo[t];if(null===i.boundingBox){const t=new Ri,e=s.index,r=s.attributes.position;for(let s=i.start,n=i.start+i.count;s=this._geometryCount)return null;const s=this.geometry,i=this._geometryInfo[t];if(null===i.boundingSphere){const e=new Gi;this.getBoundingBoxAt(t,pa),pa.getCenter(e.center);const r=s.index,n=s.attributes.position;let o=0;for(let t=i.start,s=i.start+i.count;tt.active));if(Math.max(...s.map((t=>t.vertexStart+t.reservedVertexCount)))>t)throw new Error(`BatchedMesh: Geometry vertex values are being used outside the range ${e}. Cannot shrink further.`);if(this.geometry.index){if(Math.max(...s.map((t=>t.indexStart+t.reservedIndexCount)))>e)throw new Error(`BatchedMesh: Geometry index values are being used outside the range ${e}. Cannot shrink further.`)}const i=this.geometry;i.dispose(),this._maxVertexCount=t,this._maxIndexCount=e,this._geometryInitialized&&(this._geometryInitialized=!1,this.geometry=new Cn,this._initializeGeometry(i));const r=this.geometry;i.index&&Ma(i.index.array,r.index.array);for(const t in i.attributes)Ma(i.attributes[t].array,r.attributes[t].array)}raycast(t,e){const s=this._instanceInfo,i=this._geometryInfo,r=this.matrixWorld,n=this.geometry;ba.material=this.material,ba.geometry.index=n.index,ba.geometry.attributes=n.attributes,null===ba.geometry.boundingBox&&(ba.geometry.boundingBox=new Ri),null===ba.geometry.boundingSphere&&(ba.geometry.boundingSphere=new Gi);for(let n=0,o=s.length;n({...t,boundingBox:null!==t.boundingBox?t.boundingBox.clone():null,boundingSphere:null!==t.boundingSphere?t.boundingSphere.clone():null}))),this._instanceInfo=t._instanceInfo.map((t=>({...t}))),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,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._instanceInfo,h=this._multiDrawStarts,l=this._multiDrawCounts,c=this._geometryInfo,u=this.perObjectFrustumCulled,d=this._indirectTexture,p=d.image.data;u&&(ca.multiplyMatrices(s.projectionMatrix,s.matrixWorldInverse).multiply(this.matrixWorld),da.setFromProjectionMatrix(ca,t.coordinateSystem));let m=0;if(this.sortObjects){ca.copy(this.matrixWorld).invert(),ya.setFromMatrixPosition(s.matrixWorld).applyMatrix4(ca),fa.set(0,0,-1).transformDirection(s.matrixWorld).transformDirection(ca);for(let t=0,e=a.length;t0){const s=t[e[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=s.length;ti)return;Ba.applyMatrix4(t.matrixWorld);const a=e.ray.origin.distanceTo(Ba);return ae.far?void 0:{distance:a,point:ka.clone().applyMatrix4(t.matrixWorld),index:r,face:null,faceIndex:null,barycoord:null,object:t}}const Ea=new Ii,Oa=new Ii;class Fa extends Ra{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,s=[];for(let t=0,i=e.count;t0){const s=t[e[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=s.length;tr.far)return;n.push({distance:h,distanceToRay:Math.sqrt(a),point:s,index:e,face:null,faceIndex:null,barycoord:null,object:o})}}class qa extends Rr{constructor(){super(),this.isGroup=!0,this.type="Group"}}class Ja extends vi{constructor(t,e,s,i,r,n,o,a,h){super(t,e,s,i,r,n,o,a,h),this.isVideoTexture=!0,this.minFilter=void 0!==n?n:wt,this.magFilter=void 0!==r?r:wt,this.generateMipmaps=!1;const l=this;"requestVideoFrameCallback"in t&&t.requestVideoFrameCallback((function e(){l.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 Xa extends Ja{constructor(t,e,s,i,r,n,o,a){super({},t,e,s,i,r,n,o,a)}update(){}clone(){return(new this.constructor).copy(this)}setFrame(t){this.image=t,this.needsUpdate=!0}}class Ya extends vi{constructor(t,e){super({width:t,height:e}),this.isFramebufferTexture=!0,this.magFilter=ft,this.minFilter=ft,this.generateMipmaps=!1,this.needsUpdate=!0}}class Za extends vi{constructor(t,e,s,i,r,n,o,a,h,l,c,u){super(null,n,o,a,h,l,i,r,c,u),this.isCompressedTexture=!0,this.image={width:e,height:s},this.mipmaps=t,this.flipY=!1,this.generateMipmaps=!1}}class Ga extends Za{constructor(t,e,s,i,r,n){super(t,e,s,r,n),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 $a extends Za{constructor(t,e,s){super(void 0,t[0].width,t[0].height,e,s,ht),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=t}}class Qa extends vi{constructor(t,e,s,i,r,n,o,a,h){super(t,e,s,i,r,n,o,a,h),this.isCanvasTexture=!0,this.needsUpdate=!0}}class Ka extends vi{constructor(t,e,s,i,r,n,o,a,h,l=1026){if(l!==Dt&&l!==Ht)throw new Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===s&&l===Dt&&(s=kt),void 0===s&&l===Ht&&(s=1020),super(null,i,r,n,o,a,l,s,h),this.isDepthTexture=!0,this.image={width:t,height:e},this.magFilter=void 0!==o?o:ft,this.minFilter=void 0!==a?a:ft,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(t){return super.copy(t),this.compareFunction=t.compareFunction,this}toJSON(t){const e=super.toJSON(t);return null!==this.compareFunction&&(e.compareFunction=this.compareFunction),e}}class th{constructor(){this.type="Curve",this.arcLengthDivisions=200}getPoint(){return console.warn("THREE.Curve: .getPoint() not implemented."),null}getPointAt(t,e){const s=this.getUtoTmapping(t);return this.getPoint(s,e)}getPoints(t=5){const e=[];for(let s=0;s<=t;s++)e.push(this.getPoint(s/t));return e}getSpacedPoints(t=5){const e=[];for(let s=0;s<=t;s++)e.push(this.getPointAt(s/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 s,i=this.getPoint(0),r=0;e.push(0);for(let n=1;n<=t;n++)s=this.getPoint(n/t),r+=s.distanceTo(i),e.push(r),i=s;return this.cacheArcLengths=e,e}updateArcLengths(){this.needsUpdate=!0,this.getLengths()}getUtoTmapping(t,e){const s=this.getLengths();let i=0;const r=s.length;let n;n=e||t*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(t,e){const s=1e-4;let i=t-s,r=t+s;i<0&&(i=0),r>1&&(r=1);const n=this.getPoint(i),o=this.getPoint(r),a=e||(n.isVector2?new Zs:new Ii);return a.copy(o).sub(n).normalize(),a}getTangentAt(t,e){const s=this.getUtoTmapping(t);return this.getTangent(s,e)}computeFrenetFrames(t,e){const s=new Ii,i=[],r=[],n=[],o=new Ii,a=new nr;for(let e=0;e<=t;e++){const s=e/t;i[e]=this.getTangentAt(s,new Ii)}r[0]=new Ii,n[0]=new Ii;let h=Number.MAX_VALUE;const l=Math.abs(i[0].x),c=Math.abs(i[0].y),u=Math.abs(i[0].z);l<=h&&(h=l,s.set(1,0,0)),c<=h&&(h=c,s.set(0,1,0)),u<=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 e=1;e<=t;e++){if(r[e]=r[e-1].clone(),n[e]=n[e-1].clone(),o.crossVectors(i[e-1],i[e]),o.length()>Number.EPSILON){o.normalize();const t=Math.acos(Ds(i[e-1].dot(i[e]),-1,1));r[e].applyMatrix4(a.makeRotationAxis(o,t))}n[e].crossVectors(i[e],r[e])}if(!0===e){let e=Math.acos(Ds(r[0].dot(r[t]),-1,1));e/=t,i[0].dot(o.crossVectors(r[0],r[t]))>0&&(e=-e);for(let s=1;s<=t;s++)r[s].applyMatrix4(a.makeRotationAxis(i[s],e*s)),n[s].crossVectors(i[s],r[s])}return{tangents:i,normals:r,binormals:n}}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 eh extends th{constructor(t=0,e=0,s=1,i=1,r=0,n=2*Math.PI,o=!1,a=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=s,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=n,this.aClockwise=o,this.aRotation=a}getPoint(t,e=new Zs){const s=e,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 c=i[h%r],u=i[(h+1)%r];if(this.closed||h+2i.length-2?i.length-1:n+1],c=i[n>i.length-3?i.length-1:n+2];return s.set(lh(o,a.x,h.x,l.x,c.x),lh(o,a.y,h.y,l.y,c.y)),s}copy(t){super.copy(t),this.points=[];for(let e=0,s=t.points.length;e=s){const t=i[r]-s,n=this.curves[r],o=n.getLength(),a=0===o?0:1-t/o;return n.getPointAt(a,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 s=0,i=this.curves.length;s1&&!e[e.length-1].equals(e[0])&&e.push(e[0]),e}copy(t){super.copy(t),this.curves=[];for(let e=0,s=t.curves.length;e0){const t=h.getPoint(0);t.equals(this.currentPoint)||this.lineTo(t.x,t.y)}this.curves.push(h);const l=h.getPoint(1);return this.currentPoint.copy(l),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 Mh extends Cn{constructor(t=[new Zs(0,-.5),new Zs(.5,0),new Zs(0,.5)],e=12,s=0,i=2*Math.PI){super(),this.type="LatheGeometry",this.parameters={points:t,segments:e,phiStart:s,phiLength:i},e=Math.floor(e),i=Ds(i,0,2*Math.PI);const r=[],n=[],o=[],a=[],h=[],l=1/e,c=new Ii,u=new Zs,d=new Ii,p=new Ii,m=new Ii;let y=0,f=0;for(let e=0;e<=t.length-1;e++)switch(e){case 0:y=t[e+1].x-t[e].x,f=t[e+1].y-t[e].y,d.x=1*f,d.y=-y,d.z=0*f,m.copy(d),d.normalize(),a.push(d.x,d.y,d.z);break;case t.length-1:a.push(m.x,m.y,m.z);break;default:y=t[e+1].x-t[e].x,f=t[e+1].y-t[e].y,d.x=1*f,d.y=-y,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<=e;r++){const d=s+r*l*i,p=Math.sin(d),m=Math.cos(d);for(let s=0;s<=t.length-1;s++){c.x=t[s].x*p,c.y=t[s].y,c.z=t[s].x*m,n.push(c.x,c.y,c.z),u.x=r/e,u.y=s/(t.length-1),o.push(u.x,u.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||0!==i)&&(l.push(n,o,h),x+=3),(e>0||i!==r-1)&&(l.push(o,a,h),x+=3)}h.addGroup(f,x,0),f+=x}(),!1===n&&(t>0&&g(!0),e>0&&g(!1)),this.setIndex(l),this.setAttribute("position",new vn(c,3)),this.setAttribute("normal",new vn(u,3)),this.setAttribute("uv",new vn(d,2))}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new Ah(t.radiusTop,t.radiusBottom,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class Th extends Ah{constructor(t=1,e=1,s=32,i=1,r=!1,n=0,o=2*Math.PI){super(0,t,e,s,i,r,n,o),this.type="ConeGeometry",this.parameters={radius:t,height:e,radialSegments:s,heightSegments:i,openEnded:r,thetaStart:n,thetaLength:o}}static fromJSON(t){return new Th(t.radius,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class zh extends Cn{constructor(t=[],e=[],s=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:t,indices:e,radius:s,detail:i};const r=[],n=[];function o(t,e,s,i){const r=i+1,n=[];for(let i=0;i<=r;i++){n[i]=[];const o=t.clone().lerp(s,i/r),a=e.clone().lerp(s,i/r),h=r-i;for(let t=0;t<=h;t++)n[i][t]=0===t&&i===r?o:o.clone().lerp(a,t/h)}for(let t=0;t.9&&o<.1&&(e<.2&&(n[t+0]+=1),s<.2&&(n[t+2]+=1),i<.2&&(n[t+4]+=1))}}()}(),this.setAttribute("position",new vn(r,3)),this.setAttribute("normal",new vn(r.slice(),3)),this.setAttribute("uv",new vn(n,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 zh(t.vertices,t.indices,t.radius,t.details)}}class Ch extends zh{constructor(t=1,e=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],t,e),this.type="DodecahedronGeometry",this.parameters={radius:t,detail:e}}static fromJSON(t){return new Ch(t.radius,t.detail)}}const Ih=new Ii,Bh=new Ii,kh=new Ii,Rh=new Jr;class Ph extends Cn{constructor(t=null,e=1){if(super(),this.type="EdgesGeometry",this.parameters={geometry:t,thresholdAngle:e},null!==t){const s=4,i=Math.pow(10,s),r=Math.cos(Ws*e),n=t.getIndex(),o=t.getAttribute("position"),a=n?n.count:o.count,h=[0,0,0],l=["a","b","c"],c=new Array(3),u={},d=[];for(let t=0;t80*s){a=l=t[0],h=c=t[1];for(let e=s;el&&(l=u),d>c&&(c=d);p=Math.max(l-a,c-h),p=0!==p?32767/p:0}return Lh(n,o,s,a,h,p,0),o};function Fh(t,e,s,i,r){let n,o;if(r===function(t,e,s,i){let r=0;for(let n=e,o=s-i;n0)for(n=e;n=e;n-=i)o=il(n,t[n],t[n+1],o);return o&&$h(o,o.next)&&(rl(o),o=o.next),o}function Nh(t,e){if(!t)return t;e||(e=t);let s,i=t;do{if(s=!1,i.steiner||!$h(i,i.next)&&0!==Gh(i.prev,i,i.next))i=i.next;else{if(rl(i),i=e=i.prev,i===i.next)break;s=!0}}while(s||i!==e);return e}function Lh(t,e,s,i,r,n,o){if(!t)return;!o&&n&&function(t,e,s,i){let r=t;do{0===r.z&&(r.z=Jh(r.x,r.y,e,s,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,s,i,r,n,o,a,h,l=1;do{for(s=t,t=null,n=null,o=0;s;){for(o++,i=s,a=0,e=0;e0||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:t=r,r.prevZ=n,n=r;s=i}n.nextZ=null,l*=2}while(o>1)}(r)}(t,i,r,n);let a,h,l=t;for(;t.prev!==t.next;)if(a=t.prev,h=t.next,n?Wh(t,i,r,n):Vh(t))e.push(a.i/s|0),e.push(t.i/s|0),e.push(h.i/s|0),rl(t),t=h.next,l=h.next;else if((t=h)===l){o?1===o?Lh(t=jh(Nh(t),e,s),e,s,i,r,n,2):2===o&&Uh(t,e,s,i,r,n):Lh(Nh(t),e,s,i,r,n,1);break}}function Vh(t){const e=t.prev,s=t,i=t.next;if(Gh(e,s,i)>=0)return!1;const r=e.x,n=s.x,o=i.x,a=e.y,h=s.y,l=i.y,c=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!==e;){if(m.x>=c&&m.x<=d&&m.y>=u&&m.y<=p&&Yh(r,a,n,h,o,l,m.x,m.y)&&Gh(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function Wh(t,e,s,i){const r=t.prev,n=t,o=t.next;if(Gh(r,n,o)>=0)return!1;const a=r.x,h=n.x,l=o.x,c=r.y,u=n.y,d=o.y,p=ah?a>l?a:l:h>l?h:l,f=c>u?c>d?c:d:u>d?u:d,g=Jh(p,m,e,s,i),x=Jh(y,f,e,s,i);let b=t.prevZ,v=t.nextZ;for(;b&&b.z>=g&&v&&v.z<=x;){if(b.x>=p&&b.x<=y&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&Yh(a,c,h,u,l,d,b.x,b.y)&&Gh(b.prev,b,b.next)>=0)return!1;if(b=b.prevZ,v.x>=p&&v.x<=y&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&Yh(a,c,h,u,l,d,v.x,v.y)&&Gh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}for(;b&&b.z>=g;){if(b.x>=p&&b.x<=y&&b.y>=m&&b.y<=f&&b!==r&&b!==o&&Yh(a,c,h,u,l,d,b.x,b.y)&&Gh(b.prev,b,b.next)>=0)return!1;b=b.prevZ}for(;v&&v.z<=x;){if(v.x>=p&&v.x<=y&&v.y>=m&&v.y<=f&&v!==r&&v!==o&&Yh(a,c,h,u,l,d,v.x,v.y)&&Gh(v.prev,v,v.next)>=0)return!1;v=v.nextZ}return!0}function jh(t,e,s){let i=t;do{const r=i.prev,n=i.next.next;!$h(r,n)&&Qh(r,i,i.next,n)&&el(r,n)&&el(n,r)&&(e.push(r.i/s|0),e.push(i.i/s|0),e.push(n.i/s|0),rl(i),rl(i.next),i=t=n),i=i.next}while(i!==t);return Nh(i)}function Uh(t,e,s,i,r,n){let o=t;do{let t=o.next.next;for(;t!==o.prev;){if(o.i!==t.i&&Zh(o,t)){let a=sl(o,t);return o=Nh(o,o.next),a=Nh(a,a.next),Lh(o,e,s,i,r,n,0),void Lh(a,e,s,i,r,n,0)}t=t.next}o=o.next}while(o!==t)}function Dh(t,e){return t.x-e.x}function Hh(t,e){const s=function(t,e){let s,i=e,r=-1/0;const n=t.x,o=t.y;do{if(o<=i.y&&o>=i.next.y&&i.next.y!==i.y){const t=i.x+(o-i.y)*(i.next.x-i.x)/(i.next.y-i.y);if(t<=n&&t>r&&(r=t,s=i.x=i.x&&i.x>=h&&n!==i.x&&Yh(os.x||i.x===s.x&&qh(s,i)))&&(s=i,u=c)),i=i.next}while(i!==a);return s}(t,e);if(!s)return e;const i=sl(s,t);return Nh(i,i.next),Nh(s,s.next)}function qh(t,e){return Gh(t.prev,t,e.prev)<0&&Gh(e.next,t,t.next)<0}function Jh(t,e,s,i,r){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-s)*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 Xh(t){let e=t,s=t;do{(e.x=(t-o)*(n-a)&&(t-o)*(i-a)>=(s-o)*(e-a)&&(s-o)*(n-a)>=(r-o)*(i-a)}function Zh(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let s=t;do{if(s.i!==t.i&&s.next.i!==t.i&&s.i!==e.i&&s.next.i!==e.i&&Qh(s,s.next,t,e))return!0;s=s.next}while(s!==t);return!1}(t,e)&&(el(t,e)&&el(e,t)&&function(t,e){let s=t,i=!1;const r=(t.x+e.x)/2,n=(t.y+e.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!==t);return i}(t,e)&&(Gh(t.prev,t,e.prev)||Gh(t,e.prev,e))||$h(t,e)&&Gh(t.prev,t,t.next)>0&&Gh(e.prev,e,e.next)>0)}function Gh(t,e,s){return(e.y-t.y)*(s.x-e.x)-(e.x-t.x)*(s.y-e.y)}function $h(t,e){return t.x===e.x&&t.y===e.y}function Qh(t,e,s,i){const r=tl(Gh(t,e,s)),n=tl(Gh(t,e,i)),o=tl(Gh(s,i,t)),a=tl(Gh(s,i,e));return r!==n&&o!==a||(!(0!==r||!Kh(t,s,e))||(!(0!==n||!Kh(t,i,e))||(!(0!==o||!Kh(s,t,i))||!(0!==a||!Kh(s,e,i)))))}function Kh(t,e,s){return e.x<=Math.max(t.x,s.x)&&e.x>=Math.min(t.x,s.x)&&e.y<=Math.max(t.y,s.y)&&e.y>=Math.min(t.y,s.y)}function tl(t){return t>0?1:t<0?-1:0}function el(t,e){return Gh(t.prev,t,t.next)<0?Gh(t,e,t.next)>=0&&Gh(t,t.prev,e)>=0:Gh(t,e,t.prev)<0||Gh(t,t.next,e)<0}function sl(t,e){const s=new nl(t.i,t.x,t.y),i=new nl(e.i,e.x,e.y),r=t.next,n=e.prev;return t.next=e,e.prev=t,s.next=r,r.prev=s,i.next=s,s.prev=i,n.next=i,i.prev=n,i}function il(t,e,s,i){const r=new nl(t,e,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(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 nl(t,e,s){this.i=t,this.x=e,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(t){const e=t.length;let s=0;for(let i=e-1,r=0;r2&&t[e-1].equals(t[0])&&t.pop()}function hl(t,e){for(let s=0;sNumber.EPSILON){const u=Math.sqrt(c),d=Math.sqrt(h*h+l*l),p=e.x-a/u,m=e.y+o/u,y=((s.x-l/d-p)*l-(s.y+h/d-m)*h)/(o*l-a*h);i=p+o*y-t.x,r=m+a*y-t.y;const f=i*i+r*r;if(f<=2)return new Zs(i,r);n=Math.sqrt(f/2)}else{let t=!1;o>Number.EPSILON?h>Number.EPSILON&&(t=!0):o<-Number.EPSILON?h<-Number.EPSILON&&(t=!0):Math.sign(a)===Math.sign(l)&&(t=!0),t?(i=-a,r=o,n=Math.sqrt(c)):(i=o,r=a,n=Math.sqrt(c/2))}return new Zs(i/n,r/n)}const k=[];for(let t=0,e=T.length,s=e-1,i=t+1;t=0;t--){const e=t/p,s=c*Math.cos(e*Math.PI/2),i=u*Math.sin(e*Math.PI/2)+d;for(let t=0,e=T.length;t=0;){const i=s;let r=s-1;r<0&&(r=t.length-1);for(let t=0,s=a+2*p;t0)&&d.push(e,r,h),(t!==s-1||a0!=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 Cl extends tn{constructor(t){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new $r(16777215),this.specular=new $r(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new $r(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new yr,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(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 Il extends tn{constructor(t){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new $r(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new $r(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(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 Bl extends tn{constructor(t){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(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 kl extends tn{constructor(t){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new $r(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new $r(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new yr,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(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 Rl extends tn{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 Pl extends tn{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}}class El extends tn{constructor(t){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new $r(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new Zs(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 Ol extends _a{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 Fl(t,e,s){return!t||!s&&t.constructor===e?t:"number"==typeof e.BYTES_PER_ELEMENT?new e(t):Array.prototype.slice.call(t)}function Nl(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function Ll(t){const e=t.length,s=new Array(e);for(let t=0;t!==e;++t)s[t]=t;return s.sort((function(e,s){return t[e]-t[s]})),s}function Vl(t,e,s){const i=t.length,r=new t.constructor(i);for(let n=0,o=0;o!==i;++n){const i=s[n]*e;for(let s=0;s!==e;++s)r[o++]=t[i+s]}return r}function Wl(t,e,s,i){let r=1,n=t[0];for(;void 0!==n&&void 0===n[i];)n=t[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&&(e.push(n.time),s.push.apply(s,o)),n=t[r++]}while(void 0!==n);else if(void 0!==o.toArray)do{o=n[i],void 0!==o&&(e.push(n.time),o.toArray(s,s.length)),n=t[r++]}while(void 0!==n);else do{o=n[i],void 0!==o&&(e.push(n.time),s.push(o)),n=t[r++]}while(void 0!==n)}const jl={convertArray:Fl,isTypedArray:Nl,getKeyframeOrder:Ll,sortedArray:Vl,flattenJSON:Wl,subclip:function(t,e,s,i,r=30){const n=t.clone();n.name=e;const o=[];for(let t=0;t=i)){h.push(e.times[t]);for(let s=0;sn.tracks[t].times[0]&&(a=n.tracks[t].times[0]);for(let t=0;t=i.times[u]){const t=u*h+a,e=t+h-a;d=i.values.slice(t,e)}else{const t=i.createInterpolant(),e=a,s=h-a;t.evaluate(n),d=t.resultBuffer.slice(e,s)}if("quaternion"===r){(new Ci).fromArray(d).normalize().conjugate().toArray(d)}const p=o.times.length;for(let t=0;t=r)break t;{const o=e[1];t=r)break e}n=s,s=0}}for(;s>>1;te;)--n;if(++n,0!==r||n!==i){r>=n&&(n=Math.max(n,1),r=n-1);const t=this.getValueSize();this.times=s.slice(r,n),this.values=this.values.slice(r*t,n*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 s=this.times,i=this.values,r=s.length;0===r&&(console.error("THREE.KeyframeTrack: Track is empty.",this),t=!1);let n=null;for(let e=0;e!==r;e++){const i=s[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!==n&&n>i){console.error("THREE.KeyframeTrack: Out of order keys.",this,e,i,n),t=!1;break}n=i}if(void 0!==i&&Nl(i))for(let e=0,s=i.length;e!==s;++e){const s=i[e];if(isNaN(s)){console.error("THREE.KeyframeTrack: Value is not a valid number.",this,e,s),t=!1;break}}return t}optimize(){const t=this.times.slice(),e=this.values.slice(),s=this.getValueSize(),i=this.getInterpolation()===Ee,r=t.length-1;let n=1;for(let o=1;o0){t[n]=t[r];for(let t=r*s,i=n*s,o=0;o!==s;++o)e[i+o]=e[t+o];++n}return n!==t.length?(this.times=t.slice(0,n),this.values=e.slice(0,n*s)):(this.times=t,this.values=e),this}clone(){const t=this.times.slice(),e=this.values.slice(),s=new(0,this.constructor)(this.name,t,e);return s.createInterpolant=this.createInterpolant,s}}Jl.prototype.TimeBufferType=Float32Array,Jl.prototype.ValueBufferType=Float32Array,Jl.prototype.DefaultInterpolation=Pe;class Xl extends Jl{constructor(t,e,s){super(t,e,s)}}Xl.prototype.ValueTypeName="bool",Xl.prototype.ValueBufferType=Array,Xl.prototype.DefaultInterpolation=Re,Xl.prototype.InterpolantFactoryMethodLinear=void 0,Xl.prototype.InterpolantFactoryMethodSmooth=void 0;class Yl extends Jl{}Yl.prototype.ValueTypeName="color";class Zl extends Jl{}Zl.prototype.ValueTypeName="number";class Gl extends Ul{constructor(t,e,s,i){super(t,e,s,i)}interpolate_(t,e,s,i){const r=this.resultBuffer,n=this.sampleValues,o=this.valueSize,a=(s-e)/(i-e);let h=t*o;for(let t=h+o;h!==t;h+=4)Ci.slerpFlat(r,0,n,h-o,n,h,a);return r}}class $l extends Jl{InterpolantFactoryMethodLinear(t){return new Gl(this.times,this.values,this.getValueSize(),t)}}$l.prototype.ValueTypeName="quaternion",$l.prototype.InterpolantFactoryMethodSmooth=void 0;class Ql extends Jl{constructor(t,e,s){super(t,e,s)}}Ql.prototype.ValueTypeName="string",Ql.prototype.ValueBufferType=Array,Ql.prototype.DefaultInterpolation=Re,Ql.prototype.InterpolantFactoryMethodLinear=void 0,Ql.prototype.InterpolantFactoryMethodSmooth=void 0;class Kl extends Jl{}Kl.prototype.ValueTypeName="vector";class tc{constructor(t="",e=-1,s=[],i=2500){this.name=t,this.tracks=s,this.duration=e,this.blendMode=i,this.uuid=Us(),this.duration<0&&this.resetDuration()}static parse(t){const e=[],s=t.tracks,i=1/(t.fps||1);for(let t=0,r=s.length;t!==r;++t)e.push(ec(s[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=[],s=t.tracks,i={name:t.name,duration:t.duration,tracks:e,uuid:t.uuid,blendMode:t.blendMode};for(let t=0,i=s.length;t!==i;++t)e.push(Jl.toJSON(s[t]));return i}static CreateFromMorphTargetSequence(t,e,s,i){const r=e.length,n=[];for(let t=0;t1){const t=n[1];let e=i[t];e||(i[t]=e=[]),e.push(s)}}const n=[];for(const t in i)n.push(this.CreateFromMorphTargetSequence(t,i[t],e,s));return n}static parseAnimation(t,e){if(!t)return console.error("THREE.AnimationClip: No animation in JSONLoader data."),null;const s=function(t,e,s,i,r){if(0!==s.length){const n=[],o=[];Wl(s,n,o,i),0!==n.length&&r.push(new t(e,n,o))}},i=[],r=t.name||"default",n=t.fps||30,o=t.blendMode;let a=t.length||-1;const h=t.hierarchy||[];for(let t=0;t{e&&e(r),this.manager.itemEnd(t)}),0),r;if(void 0!==oc[t])return void oc[t].push({onLoad:e,onProgress:s,onError:i});oc[t]=[],oc[t].push({onLoad:e,onProgress:s,onError:i});const n=new Request(t,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin"}),o=this.mimeType,a=this.responseType;fetch(n).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 s=oc[t],i=e.body.getReader(),r=e.headers.get("X-File-Size")||e.headers.get("Content-Length"),n=r?parseInt(r):0,o=0!==n;let a=0;const h=new ReadableStream({start(t){!function e(){i.read().then((({done:i,value:r})=>{if(i)t.close();else{a+=r.byteLength;const i=new ProgressEvent("progress",{lengthComputable:o,loaded:a,total:n});for(let t=0,e=s.length;t{t.error(e)}))}()}});return new Response(h)}throw new ac(`fetch for "${e.url}" responded with ${e.status}: ${e.statusText}`,e)})).then((t=>{switch(a){case"arraybuffer":return t.arrayBuffer();case"blob":return t.blob();case"document":return t.text().then((t=>(new DOMParser).parseFromString(t,o)));case"json":return t.json();default:if(void 0===o)return t.text();{const e=/charset="?([^;"\s]*)"?/i.exec(o),s=e&&e[1]?e[1].toLowerCase():void 0,i=new TextDecoder(s);return t.arrayBuffer().then((t=>i.decode(t)))}}})).then((e=>{sc.add(t,e);const s=oc[t];delete oc[t];for(let t=0,i=s.length;t{const s=oc[t];if(void 0===s)throw this.manager.itemError(t),e;delete oc[t];for(let t=0,i=s.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 lc extends nc{constructor(t){super(t)}load(t,e,s,i){const r=this,n=new hc(this.manager);n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(t,(function(s){try{e(r.parse(JSON.parse(s)))}catch(e){i?i(e):console.error(e),r.manager.itemError(t)}}),s,i)}parse(t){const e=[];for(let s=0;s0: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=s(r.value);break;case"c":i.uniforms[e].value=(new $r).setHex(r.value);break;case"v2":i.uniforms[e].value=(new Zs).fromArray(r.value);break;case"v3":i.uniforms[e].value=(new Ii).fromArray(r.value);break;case"v4":i.uniforms[e].value=(new wi).fromArray(r.value);break;case"m3":i.uniforms[e].value=(new Gs).fromArray(r.value);break;case"m4":i.uniforms[e].value=(new nr).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=s(t.map)),void 0!==t.matcap&&(i.matcap=s(t.matcap)),void 0!==t.alphaMap&&(i.alphaMap=s(t.alphaMap)),void 0!==t.bumpMap&&(i.bumpMap=s(t.bumpMap)),void 0!==t.bumpScale&&(i.bumpScale=t.bumpScale),void 0!==t.normalMap&&(i.normalMap=s(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 Zs).fromArray(e)}return void 0!==t.displacementMap&&(i.displacementMap=s(t.displacementMap)),void 0!==t.displacementScale&&(i.displacementScale=t.displacementScale),void 0!==t.displacementBias&&(i.displacementBias=t.displacementBias),void 0!==t.roughnessMap&&(i.roughnessMap=s(t.roughnessMap)),void 0!==t.metalnessMap&&(i.metalnessMap=s(t.metalnessMap)),void 0!==t.emissiveMap&&(i.emissiveMap=s(t.emissiveMap)),void 0!==t.emissiveIntensity&&(i.emissiveIntensity=t.emissiveIntensity),void 0!==t.specularMap&&(i.specularMap=s(t.specularMap)),void 0!==t.specularIntensityMap&&(i.specularIntensityMap=s(t.specularIntensityMap)),void 0!==t.specularColorMap&&(i.specularColorMap=s(t.specularColorMap)),void 0!==t.envMap&&(i.envMap=s(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=s(t.lightMap)),void 0!==t.lightMapIntensity&&(i.lightMapIntensity=t.lightMapIntensity),void 0!==t.aoMap&&(i.aoMap=s(t.aoMap)),void 0!==t.aoMapIntensity&&(i.aoMapIntensity=t.aoMapIntensity),void 0!==t.gradientMap&&(i.gradientMap=s(t.gradientMap)),void 0!==t.clearcoatMap&&(i.clearcoatMap=s(t.clearcoatMap)),void 0!==t.clearcoatRoughnessMap&&(i.clearcoatRoughnessMap=s(t.clearcoatRoughnessMap)),void 0!==t.clearcoatNormalMap&&(i.clearcoatNormalMap=s(t.clearcoatNormalMap)),void 0!==t.clearcoatNormalScale&&(i.clearcoatNormalScale=(new Zs).fromArray(t.clearcoatNormalScale)),void 0!==t.iridescenceMap&&(i.iridescenceMap=s(t.iridescenceMap)),void 0!==t.iridescenceThicknessMap&&(i.iridescenceThicknessMap=s(t.iridescenceThicknessMap)),void 0!==t.transmissionMap&&(i.transmissionMap=s(t.transmissionMap)),void 0!==t.thicknessMap&&(i.thicknessMap=s(t.thicknessMap)),void 0!==t.anisotropyMap&&(i.anisotropyMap=s(t.anisotropyMap)),void 0!==t.sheenColorMap&&(i.sheenColorMap=s(t.sheenColorMap)),void 0!==t.sheenRoughnessMap&&(i.sheenRoughnessMap=s(t.sheenRoughnessMap)),i}setTextures(t){return this.textures=t,this}createMaterialFromType(t){return Oc.createMaterialFromType(t)}static createMaterialFromType(t){return new{ShadowMaterial:_l,SpriteMaterial:lo,RawShaderMaterial:Al,ShaderMaterial:Xn,PointsMaterial:La,MeshPhysicalMaterial:zl,MeshStandardMaterial:Tl,MeshPhongMaterial:Cl,MeshToonMaterial:Il,MeshNormalMaterial:Bl,MeshLambertMaterial:kl,MeshDepthMaterial:Rl,MeshDistanceMaterial:Pl,MeshBasicMaterial:en,MeshMatcapMaterial:El,LineDashedMaterial:Ol,LineBasicMaterial:_a,Material:tn}[t]}}class Fc{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 s=0,i=t.length;s0){const s=new ic(e);r=new uc(s),r.setCrossOrigin(this.crossOrigin);for(let e=0,s=t.length;e0){i=new uc(this.manager),i.setCrossOrigin(this.crossOrigin);for(let e=0,i=t.length;e{const e=new Ri;e.min.fromArray(t.boxMin),e.max.fromArray(t.boxMax);const s=new Gi;return s.radius=t.sphereRadius,s.center.fromArray(t.sphereCenter),{boxInitialized:t.boxInitialized,box:e,sphereInitialized:t.sphereInitialized,sphere:s}})),n._maxInstanceCount=t.maxInstanceCount,n._maxVertexCount=t.maxVertexCount,n._maxIndexCount=t.maxIndexCount,n._geometryInitialized=t.geometryInitialized,n._geometryCount=t.geometryCount,n._matricesTexture=c(t.matricesTexture.uuid),void 0!==t.colorsTexture&&(n._colorsTexture=c(t.colorsTexture.uuid));break;case"LOD":n=new Co;break;case"Line":n=new Ra(h(t.geometry),l(t.material));break;case"LineLoop":n=new Na(h(t.geometry),l(t.material));break;case"LineSegments":n=new Fa(h(t.geometry),l(t.material));break;case"PointCloud":case"Points":n=new Da(h(t.geometry),l(t.material));break;case"Sprite":n=new _o(l(t.material));break;case"Group":n=new qa;break;case"Bone":n=new Vo;break;default:n=new Rr}if(n.uuid=t.uuid,void 0!==t.name&&(n.name=t.name),void 0!==t.matrix?(n.matrix.fromArray(t.matrix),void 0!==t.matrixAutoUpdate&&(n.matrixAutoUpdate=t.matrixAutoUpdate),n.matrixAutoUpdate&&n.matrix.decompose(n.position,n.quaternion,n.scale)):(void 0!==t.position&&n.position.fromArray(t.position),void 0!==t.rotation&&n.rotation.fromArray(t.rotation),void 0!==t.quaternion&&n.quaternion.fromArray(t.quaternion),void 0!==t.scale&&n.scale.fromArray(t.scale)),void 0!==t.up&&n.up.fromArray(t.up),void 0!==t.castShadow&&(n.castShadow=t.castShadow),void 0!==t.receiveShadow&&(n.receiveShadow=t.receiveShadow),t.shadow&&(void 0!==t.shadow.intensity&&(n.shadow.intensity=t.shadow.intensity),void 0!==t.shadow.bias&&(n.shadow.bias=t.shadow.bias),void 0!==t.shadow.normalBias&&(n.shadow.normalBias=t.shadow.normalBias),void 0!==t.shadow.radius&&(n.shadow.radius=t.shadow.radius),void 0!==t.shadow.mapSize&&n.shadow.mapSize.fromArray(t.shadow.mapSize),void 0!==t.shadow.camera&&(n.shadow.camera=this.parseObject(t.shadow.camera))),void 0!==t.visible&&(n.visible=t.visible),void 0!==t.frustumCulled&&(n.frustumCulled=t.frustumCulled),void 0!==t.renderOrder&&(n.renderOrder=t.renderOrder),void 0!==t.userData&&(n.userData=t.userData),void 0!==t.layers&&(n.layers.mask=t.layers),void 0!==t.children){const o=t.children;for(let t=0;t{e&&e(s),r.manager.itemEnd(t)})).catch((t=>{i&&i(t)})):(setTimeout((function(){e&&e(n),r.manager.itemEnd(t)}),0),n);const o={};o.credentials="anonymous"===this.crossOrigin?"same-origin":"include",o.headers=this.requestHeader;const a=fetch(t,o).then((function(t){return t.blob()})).then((function(t){return createImageBitmap(t,Object.assign(r.options,{colorSpaceConversion:"none"}))})).then((function(s){return sc.add(t,s),e&&e(s),r.manager.itemEnd(t),s})).catch((function(e){i&&i(e),sc.remove(t),r.manager.itemError(t),r.manager.itemEnd(t)}));sc.add(t,a),r.manager.itemStart(t)}}let Hc;class qc{static getContext(){return void 0===Hc&&(Hc=new(window.AudioContext||window.webkitAudioContext)),Hc}static setContext(t){Hc=t}}class Jc extends nc{constructor(t){super(t)}load(t,e,s,i){const r=this,n=new hc(this.manager);function o(e){i?i(e):console.error(e),r.manager.itemError(t)}n.setResponseType("arraybuffer"),n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(t,(function(t){try{const s=t.slice(0);qc.getContext().decodeAudioData(s,(function(t){e(t)})).catch(o)}catch(t){o(t)}}),s,i)}}const Xc=new nr,Yc=new nr,Zc=new nr;class Gc{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new Qn,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new Qn,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,Zc.copy(t.projectionMatrix);const s=e.eyeSep/2,i=s*e.near/e.focus,r=e.near*Math.tan(Ws*e.fov*.5)/e.zoom;let n,o;Yc.elements[12]=-s,Xc.elements[12]=s,n=-r*e.aspect+i,o=r*e.aspect+i,Zc.elements[0]=2*e.near/(o-n),Zc.elements[8]=(o+n)/(o-n),this.cameraL.projectionMatrix.copy(Zc),n=-r*e.aspect-i,o=r*e.aspect-i,Zc.elements[0]=2*e.near/(o-n),Zc.elements[8]=(o+n)/(o-n),this.cameraR.projectionMatrix.copy(Zc)}this.cameraL.matrixWorld.copy(t.matrixWorld).multiply(Yc),this.cameraR.matrixWorld.copy(t.matrixWorld).multiply(Xc)}}class $c extends Qn{constructor(t=[]){super(),this.isArrayCamera=!0,this.cameras=t}}class Qc{constructor(t=!0){this.autoStart=t,this.startTime=0,this.oldTime=0,this.elapsedTime=0,this.running=!1}start(){this.startTime=Kc(),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=Kc();t=(e-this.oldTime)/1e3,this.oldTime=e,this.elapsedTime+=t}return t}}function Kc(){return performance.now()}const tu=new Ii,eu=new Ci,su=new Ii,iu=new Ii;class ru extends Rr{constructor(){super(),this.type="AudioListener",this.context=qc.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._clock=new Qc}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,s=this.up;if(this.timeDelta=this._clock.getDelta(),this.matrixWorld.decompose(tu,eu,su),iu.set(0,0,-1).applyQuaternion(eu),e.positionX){const t=this.context.currentTime+this.timeDelta;e.positionX.linearRampToValueAtTime(tu.x,t),e.positionY.linearRampToValueAtTime(tu.y,t),e.positionZ.linearRampToValueAtTime(tu.z,t),e.forwardX.linearRampToValueAtTime(iu.x,t),e.forwardY.linearRampToValueAtTime(iu.y,t),e.forwardZ.linearRampToValueAtTime(iu.z,t),e.upX.linearRampToValueAtTime(s.x,t),e.upY.linearRampToValueAtTime(s.y,t),e.upZ.linearRampToValueAtTime(s.z,t)}else e.setPosition(tu.x,tu.y,tu.z),e.setOrientation(iu.x,iu.y,iu.z,s.x,s.y,s.z)}}class nu extends Rr{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(s,i,this._addIndex*e,1,e);for(let t=e,r=e+e;t!==r;++t)if(s[t]!==s[t+e]){o.setValue(s,i);break}}saveOriginalState(){const t=this.binding,e=this.buffer,s=this.valueSize,i=s*this._origIndex;t.getValue(e,i);for(let t=s,r=i;t!==r;++t)e[t]=e[i+t%s];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 s=t;s=.5)for(let i=0;i!==r;++i)t[e+i]=t[s+i]}_slerp(t,e,s,i){Ci.slerpFlat(t,e,t,e,t,s,i)}_slerpAdditive(t,e,s,i,r){const n=this._workIndex*r;Ci.multiplyQuaternionsFlat(t,n,t,e,t,s),Ci.slerpFlat(t,e,t,e,t,n,i)}_lerp(t,e,s,i,r){const n=1-i;for(let o=0;o!==r;++o){const r=e+o;t[r]=t[r]*n+t[s+o]*i}}_lerpAdditive(t,e,s,i,r){for(let n=0;n!==r;++n){const r=e+n;t[r]=t[r]+t[s+n]*i}}}const pu="\\[\\]\\.:\\/",mu=new RegExp("["+pu+"]","g"),yu="[^"+pu+"]",fu="[^"+pu.replace("\\.","")+"]",gu=new RegExp("^"+/((?:WC+[\/:])*)/.source.replace("WC",yu)+/(WCOD+)?/.source.replace("WCOD",fu)+/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",yu)+/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",yu)+"$"),xu=["material","materials","bones","map"];class bu{constructor(t,e,s){this.path=e,this.parsedPath=s||bu.parseTrackName(e),this.node=bu.findNode(t,this.parsedPath.nodeName),this.rootNode=t,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(t,e,s){return t&&t.isAnimationObjectGroup?new bu.Composite(t,e,s):new bu(t,e,s)}static sanitizeNodeName(t){return t.replace(/\s/g,"_").replace(mu,"")}static parseTrackName(t){const e=gu.exec(t);if(null===e)throw new Error("PropertyBinding: Cannot parse trackName: "+t);const s={nodeName:e[2],objectName:e[3],objectIndex:e[4],propertyName:e[5],propertyIndex:e[6]},i=s.nodeName&&s.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const t=s.nodeName.substring(i+1);-1!==xu.indexOf(t)&&(s.nodeName=s.nodeName.substring(0,i),s.objectName=t)}if(null===s.propertyName||0===s.propertyName.length)throw new Error("PropertyBinding: can not parse propertyName from trackName: "+t);return s}static findNode(t,e){if(void 0===e||""===e||"."===e||-1===e||e===t.name||e===t.uuid)return t;if(t.skeleton){const s=t.skeleton.getBoneByName(e);if(void 0!==s)return s}if(t.children){const s=function(t){for(let i=0;i=r){const n=r++,l=t[n];e[l.uuid]=h,t[h]=l,e[a]=n,t[n]=o;for(let t=0,e=i;t!==e;++t){const e=s[t],i=e[n],r=e[h];e[h]=i,e[n]=r}}}this.nCachedObjects_=r}uncache(){const t=this._objects,e=this._indicesByUUID,s=this._bindings,i=s.length;let r=this.nCachedObjects_,n=t.length;for(let o=0,a=arguments.length;o!==a;++o){const a=arguments[o].uuid,h=e[a];if(void 0!==h)if(delete e[a],h0&&(e[o.uuid]=h),t[h]=o,t.pop();for(let t=0,e=i;t!==e;++t){const e=s[t];e[h]=e[r],e.pop()}}}this.nCachedObjects_=r}subscribe_(t,e){const s=this._bindingsIndicesByPath;let i=s[t];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_,c=new Array(h);i=r.length,s[t]=i,n.push(t),o.push(e),r.push(c);for(let s=l,i=a.length;s!==i;++s){const i=a[s];c[s]=new bu(i,t,e)}return c}unsubscribe_(t){const e=this._bindingsIndicesByPath,s=e[t];if(void 0!==s){const i=this._paths,r=this._parsedPaths,n=this._bindings,o=n.length-1,a=n[o];e[t[o]]=s,n[s]=a,n.pop(),r[s]=r[o],r.pop(),i[s]=i[o],i.pop()}}}class wu{constructor(t,e,s=null,i=e.blendMode){this._mixer=t,this._clip=e,this._localRoot=s,this.blendMode=i;const r=e.tracks,n=r.length,o=new Array(n),a={endingStart:Oe,endingEnd:Oe};for(let t=0;t!==n;++t){const e=r[t].createInterpolant(null);o[t]=e,e.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(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,s){if(t.fadeOut(e),this.fadeIn(e),s){const s=this._clip.duration,i=t._clip.duration,r=i/s,n=s/i;t.warp(1,r,e),this.warp(n,1,e)}return this}crossFadeTo(t,e,s){return t.crossFadeFrom(this,e,s)}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,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]=t/n,h[1]=e/n,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,s,i){if(!this.enabled)return void this._updateWeight(t);const r=this._startTime;if(null!==r){const i=(t-r)*s;i<0||0===s?e=0:(this._startTime=null,e=s*i)}e*=this._updateTimeScale(t);const n=this._updateTime(e),o=this._updateWeight(t);if(o>0){const t=this._interpolants,e=this._propertyBindings;if(this.blendMode===Ve)for(let s=0,i=t.length;s!==i;++s)t[s].evaluate(n),e[s].accumulateAdditive(o);else for(let s=0,r=t.length;s!==r;++s)t[s].evaluate(n),e[s].accumulate(i,o)}}_updateWeight(t){let e=0;if(this.enabled){e=this.weight;const s=this._weightInterpolant;if(null!==s){const i=s.evaluate(t)[0];e*=i,t>s.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 s=this._timeScaleInterpolant;if(null!==s){e*=s.evaluate(t)[0],t>s.parameterPositions[1]&&(this.stopWarping(),0===e?this.paused=!0:this.timeScale=e)}}return this._effectiveTimeScale=e,e}_updateTime(t){const e=this._clip.duration,s=this.loop;let i=this.time+t,r=this._loopCount;const n=2202===s;if(0===t)return-1===r||!n||1&~r?i:e-i;if(2200===s){-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,n)):this._setEndings(0===this.repetitions,!0,n)),i>=e||i<0){const s=Math.floor(i/e);i-=e*s,r+=Math.abs(s);const o=this.repetitions-r;if(o<=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===o){const e=t<0;this._setEndings(e,!e,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&~r))return e-i}return i}_setEndings(t,e,s){const i=this._interpolantSettings;s?(i.endingStart=Fe,i.endingEnd=Fe):(i.endingStart=t?this.zeroSlopeAtStart?Fe:Oe:Ne,i.endingEnd=e?this.zeroSlopeAtEnd?Fe:Oe:Ne)}_scheduleFading(t,e,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]=e,o[1]=r+t,a[1]=s,this}}const Mu=new Float32Array(1);class Su extends Ns{constructor(t){super(),this._root=t,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1}_bindAction(t,e){const s=t._localRoot||this._root,i=t._clip.tracks,r=i.length,n=t._propertyBindings,o=t._interpolants,a=s.uuid,h=this._bindingsByRootAndName;let l=h[a];void 0===l&&(l={},h[a]=l);for(let t=0;t!==r;++t){const r=i[t],h=r.name;let c=l[h];if(void 0!==c)++c.referenceCount,n[t]=c;else{if(c=n[t],void 0!==c){null===c._cacheIndex&&(++c.referenceCount,this._addInactiveBinding(c,a,h));continue}const i=e&&e._propertyBindings[t].binding.parsedPath;c=new du(bu.create(s,h,i),r.ValueTypeName,r.getValueSize()),++c.referenceCount,this._addInactiveBinding(c,a,h),n[t]=c}o[t].resultBuffer=c.buffer}}_activateAction(t){if(!this._isActiveAction(t)){if(null===t._cacheIndex){const e=(t._localRoot||this._root).uuid,s=t._clip.uuid,i=this._actionsByClip[s];this._bindAction(t,i&&i.knownActions[0]),this._addInactiveAction(t,s,e)}const e=t._propertyBindings;for(let t=0,s=e.length;t!==s;++t){const s=e[t];0==s.useCount++&&(this._lendBinding(s),s.saveOriginalState())}this._lendAction(t)}}_deactivateAction(t){if(this._isActiveAction(t)){const e=t._propertyBindings;for(let t=0,s=e.length;t!==s;++t){const s=e[t];0==--s.useCount&&(s.restoreOriginalState(),this._takeBackBinding(s))}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,s=this._nActiveActions,i=this.time+=t,r=Math.sign(t),n=this._accuIndex^=1;for(let o=0;o!==s;++o){e[o]._update(i,t,r,n)}const o=this._bindings,a=this._nActiveBindings;for(let t=0;t!==a;++t)o[t].apply(n);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,Lu).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 Wu=new Ii,ju=new Ii;class Uu{constructor(t=new Ii,e=new Ii){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){Wu.subVectors(t,this.start),ju.subVectors(this.end,this.start);const s=ju.dot(ju);let i=ju.dot(Wu)/s;return e&&(i=Ds(i,0,1)),i}closestPointToPoint(t,e,s){const i=this.closestPointToPointParameter(t,e);return this.delta(s).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 Du=new Ii;class Hu extends Rr{constructor(t,e){super(),this.light=t,this.matrixAutoUpdate=!1,this.color=e,this.type="SpotLightHelper";const s=new Cn,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,s=32;t1)for(let s=0;s.99999)this.quaternion.set(0,0,0,1);else if(t.y<-.99999)this.quaternion.set(1,0,0,0);else{yd.set(t.z,0,-t.x).normalize();const e=Math.acos(t.y);this.quaternion.setFromAxisAngle(yd,e)}}setLength(t,e=.2*t,s=.2*e){this.line.scale.set(1,Math.max(1e-4,t-e),1),this.line.updateMatrix(),this.cone.scale.set(s,e,s),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 bd extends Fa{constructor(t=1){const e=[0,0,0,t,0,0,0,0,0,0,t,0,0,0,0,0,0,t],s=new Cn;s.setAttribute("position",new vn(e,3)),s.setAttribute("color",new vn([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],3));super(s,new _a({vertexColors:!0,toneMapped:!1})),this.type="AxesHelper"}setColors(t,e,s){const i=new $r,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(s),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class vd{constructor(){this.type="ShapePath",this.color=new $r,this.subPaths=[],this.currentPath=null}moveTo(t,e){return this.currentPath=new wh,this.subPaths.push(this.currentPath),this.currentPath.moveTo(t,e),this}lineTo(t,e){return this.currentPath.lineTo(t,e),this}quadraticCurveTo(t,e,s,i){return this.currentPath.quadraticCurveTo(t,e,s,i),this}bezierCurveTo(t,e,s,i,r,n){return this.currentPath.bezierCurveTo(t,e,s,i,r,n),this}splineThru(t){return this.currentPath.splineThru(t),this}toShapes(t){function e(t,e){const s=e.length;let i=!1;for(let r=s-1,n=0;nNumber.EPSILON){if(h<0&&(s=e[n],a=-a,o=e[r],h=-h),t.yo.y)continue;if(t.y===s.y){if(t.x===s.x)return!0}else{const e=h*(t.x-s.x)-a*(t.y-s.y);if(0===e)return!0;if(e<0)continue;i=!i}}else{if(t.y!==s.y)continue;if(o.x<=t.x&&t.x<=s.x||s.x<=t.x&&t.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 Eh,o.curves=n.curves,a.push(o),a;let h=!s(i[0].getPoints());h=t?!h:h;const l=[],c=[];let u,d,p=[],m=0;c[m]=void 0,p[m]=[];for(let e=0,o=i.length;e1){let t=!1,s=0;for(let t=0,e=c.length;t0&&!1===t&&(p=l)}for(let t=0,e=c.length;te?(t.repeat.x=1,t.repeat.y=s/e,t.offset.x=0,t.offset.y=(1-t.repeat.y)/2):(t.repeat.x=e/s,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0),t},cover:function(t,e){const s=t.image&&t.image.width?t.image.width/t.image.height:1;return s>e?(t.repeat.x=e/s,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0):(t.repeat.x=1,t.repeat.y=s/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:Md};"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("register",{detail:{revision:t}})),"undefined"!=typeof window&&(window.__THREE__?console.warn("WARNING: Multiple instances of Three.js being imported."):window.__THREE__=t);export{et as ACESFilmicToneMapping,v as AddEquation,G as AddOperation,Ve as AdditiveAnimationBlendMode,f as AdditiveBlending,it as AgXToneMapping,Lt as AlphaFormat,Ss as AlwaysCompare,j as AlwaysDepth,ys as AlwaysStencilFunc,kc as AmbientLight,wu as AnimationAction,tc as AnimationClip,lc as AnimationLoader,Su as AnimationMixer,vu as AnimationObjectGroup,jl as AnimationUtils,sh as ArcCurve,$c as ArrayCamera,xd as ArrowHelper,nt as AttachedBindMode,nu as Audio,uu as AudioAnalyser,qc as AudioContext,ru as AudioListener,Jc as AudioLoader,bd as AxesHelper,d as BackSide,De as BasicDepthPacking,a as BasicShadowMap,Sa as BatchedMesh,Vo as Bone,Xl as BooleanKeyframeTrack,Vu as Box2,Ri as Box3,pd as Box3Helper,Un as BoxGeometry,dd as BoxHelper,un as BufferAttribute,Cn as BufferGeometry,Lc as BufferGeometryLoader,zt as ByteType,sc as Cache,Yn as Camera,ld as CameraHelper,Qa as CanvasTexture,Sh as CapsuleGeometry,hh as CatmullRomCurve3,tt as CineonToneMapping,_h as CircleGeometry,mt as ClampToEdgeWrapping,Qc as Clock,$r as Color,Yl as ColorKeyframeTrack,ui as ColorManagement,Ga as CompressedArrayTexture,$a as CompressedCubeTexture,Za as CompressedTexture,cc as CompressedTextureLoader,Th as ConeGeometry,L as ConstantAlphaFactor,F as ConstantColorFactor,wd as Controls,to as CubeCamera,ht as CubeReflectionMapping,lt as CubeRefractionMapping,eo as CubeTexture,dc as CubeTextureLoader,dt as CubeUVReflectionMapping,dh as CubicBezierCurve,ph as CubicBezierCurve3,Dl as CubicInterpolant,r as CullFaceBack,n as CullFaceFront,o as CullFaceFrontBack,i as CullFaceNone,th as Curve,vh as CurvePath,b as CustomBlending,st as CustomToneMapping,Ah as CylinderGeometry,Fu as Cylindrical,Ti as Data3DTexture,_i as DataArrayTexture,Wo as DataTexture,pc as DataTextureLoader,an as DataUtils,rs as DecrementStencilOp,os as DecrementWrapStencilOp,rc as DefaultLoadingManager,Dt as DepthFormat,Ht as DepthStencilFormat,Ka as DepthTexture,ot as DetachedBindMode,Bc as DirectionalLight,od as DirectionalLightHelper,ql as DiscreteInterpolant,Ch as DodecahedronGeometry,p as DoubleSide,k as DstAlphaFactor,P as DstColorFactor,ks as DynamicCopyUsage,As as DynamicDrawUsage,Cs as DynamicReadUsage,Ph as EdgesGeometry,eh as EllipseCurve,xs as EqualCompare,H as EqualDepth,cs as EqualStencilFunc,ct as EquirectangularReflectionMapping,ut as EquirectangularRefractionMapping,yr as Euler,Ns as EventDispatcher,ll as ExtrudeGeometry,hc as FileLoader,bn as Float16BufferAttribute,vn as Float32BufferAttribute,Rt as FloatType,ro as Fog,io as FogExp2,Ya as FramebufferTexture,u as FrontSide,na as Frustum,Bu as GLBufferAttribute,Ps as GLSL1,Es as GLSL3,vs as GreaterCompare,J as GreaterDepth,Ms as GreaterEqualCompare,q as GreaterEqualDepth,ms as GreaterEqualStencilFunc,ds as GreaterStencilFunc,ed as GridHelper,qa as Group,Pt as HalfFloatType,fc as HemisphereLight,td as HemisphereLightHelper,ul as IcosahedronGeometry,Dc as ImageBitmapLoader,uc as ImageLoader,yi as ImageUtils,is as IncrementStencilOp,ns as IncrementWrapStencilOp,Ho as InstancedBufferAttribute,Nc as InstancedBufferGeometry,Iu as InstancedInterleavedBuffer,Qo as InstancedMesh,yn as Int16BufferAttribute,gn as Int32BufferAttribute,dn as Int8BufferAttribute,Bt as IntType,oo as InterleavedBuffer,ho as InterleavedBufferAttribute,Ul as Interpolant,Re as InterpolateDiscrete,Pe as InterpolateLinear,Ee as InterpolateSmooth,as as InvertStencilOp,es as KeepStencilOp,Jl as KeyframeTrack,Co as LOD,Mh as LatheGeometry,fr as Layers,gs as LessCompare,U as LessDepth,bs as LessEqualCompare,D as LessEqualDepth,us as LessEqualStencilFunc,ls as LessStencilFunc,yc as Light,Ec as LightProbe,Ra as Line,Uu as Line3,_a as LineBasicMaterial,mh as LineCurve,yh as LineCurve3,Ol as LineDashedMaterial,Na as LineLoop,Fa as LineSegments,wt as LinearFilter,Hl as LinearInterpolant,At as LinearMipMapLinearFilter,St as LinearMipMapNearestFilter,_t as LinearMipmapLinearFilter,Mt as LinearMipmapNearestFilter,$e as LinearSRGBColorSpace,Q as LinearToneMapping,Qe as LinearTransfer,nc as Loader,Fc as LoaderUtils,ic as LoadingManager,Ie as LoopOnce,ke as LoopPingPong,Be as LoopRepeat,Ut as LuminanceAlphaFormat,jt as LuminanceFormat,e as MOUSE,tn as Material,Oc as MaterialLoader,Ys as MathUtils,Nu as Matrix2,Gs as Matrix3,nr as Matrix4,_ as MaxEquation,Wn as Mesh,en as MeshBasicMaterial,Rl as MeshDepthMaterial,Pl as MeshDistanceMaterial,kl as MeshLambertMaterial,El as MeshMatcapMaterial,Bl as MeshNormalMaterial,Cl as MeshPhongMaterial,zl as MeshPhysicalMaterial,Tl as MeshStandardMaterial,Il as MeshToonMaterial,S as MinEquation,yt as MirroredRepeatWrapping,Z as MixOperation,x as MultiplyBlending,Y as MultiplyOperation,ft as NearestFilter,vt as NearestMipMapLinearFilter,xt as NearestMipMapNearestFilter,bt as NearestMipmapLinearFilter,gt as NearestMipmapNearestFilter,rt as NeutralToneMapping,fs as NeverCompare,W as NeverDepth,hs as NeverStencilFunc,m as NoBlending,Ze as NoColorSpace,$ as NoToneMapping,Le as NormalAnimationBlendMode,y as NormalBlending,ws as NotEqualCompare,X as NotEqualDepth,ps as NotEqualStencilFunc,Zl as NumberKeyframeTrack,Rr as Object3D,Vc as ObjectLoader,Ye as ObjectSpaceNormalMap,dl as OctahedronGeometry,T as OneFactor,V as OneMinusConstantAlphaFactor,N as OneMinusConstantColorFactor,R as OneMinusDstAlphaFactor,E as OneMinusDstColorFactor,B as OneMinusSrcAlphaFactor,C as OneMinusSrcColorFactor,Cc as OrthographicCamera,h as PCFShadowMap,l as PCFSoftShadowMap,wh as Path,Qn as PerspectiveCamera,sa as Plane,pl as PlaneGeometry,md as PlaneHelper,zc as PointLight,Gu as PointLightHelper,Da as Points,La as PointsMaterial,sd as PolarGridHelper,zh as PolyhedronGeometry,cu as PositionalAudio,bu as PropertyBinding,du as PropertyMixer,fh as QuadraticBezierCurve,gh as QuadraticBezierCurve3,Ci as Quaternion,$l as QuaternionKeyframeTrack,Gl as QuaternionLinearInterpolant,js as RAD2DEG,ze as RED_GREEN_RGTC2_Format,Ae as RED_RGTC1_Format,t as REVISION,He as RGBADepthPacking,Wt as RGBAFormat,Gt as RGBAIntegerFormat,be as RGBA_ASTC_10x10_Format,fe as RGBA_ASTC_10x5_Format,ge as RGBA_ASTC_10x6_Format,xe as RGBA_ASTC_10x8_Format,ve as RGBA_ASTC_12x10_Format,we as RGBA_ASTC_12x12_Format,he as RGBA_ASTC_4x4_Format,le as RGBA_ASTC_5x4_Format,ce as RGBA_ASTC_5x5_Format,ue as RGBA_ASTC_6x5_Format,de as RGBA_ASTC_6x6_Format,pe as RGBA_ASTC_8x5_Format,me as RGBA_ASTC_8x6_Format,ye as RGBA_ASTC_8x8_Format,Me as RGBA_BPTC_Format,ae as RGBA_ETC2_EAC_Format,re as RGBA_PVRTC_2BPPV1_Format,ie as RGBA_PVRTC_4BPPV1_Format,Qt as RGBA_S3TC_DXT1_Format,Kt as RGBA_S3TC_DXT3_Format,te as RGBA_S3TC_DXT5_Format,qe as RGBDepthPacking,Vt as RGBFormat,Zt as RGBIntegerFormat,Se as RGB_BPTC_SIGNED_Format,_e as RGB_BPTC_UNSIGNED_Format,ne as RGB_ETC1_Format,oe as RGB_ETC2_Format,se as RGB_PVRTC_2BPPV1_Format,ee as RGB_PVRTC_4BPPV1_Format,$t as RGB_S3TC_DXT1_Format,Je as RGDepthPacking,Xt as RGFormat,Yt as RGIntegerFormat,Al as RawShaderMaterial,rr as Ray,Ru as Raycaster,Rc as RectAreaLight,qt as RedFormat,Jt as RedIntegerFormat,K as ReinhardToneMapping,Mi as RenderTarget,_u as RenderTarget3D,Au as RenderTargetArray,pt as RepeatWrapping,ss as ReplaceStencilOp,M as ReverseSubtractEquation,ml as RingGeometry,Ce as SIGNED_RED_GREEN_RGTC2_Format,Te as SIGNED_RED_RGTC1_Format,Ge as SRGBColorSpace,Ke as SRGBTransfer,no as Scene,Xn as ShaderMaterial,_l as ShadowMaterial,Eh as Shape,yl as ShapeGeometry,vd as ShapePath,ol as ShapeUtils,Ct as ShortType,Do as Skeleton,Yu as SkeletonHelper,Lo as SkinnedMesh,gi as Source,Gi as Sphere,fl as SphereGeometry,Ou as Spherical,Pc as SphericalHarmonics3,xh as SplineCurve,Mc as SpotLight,Hu as SpotLightHelper,_o as Sprite,lo as SpriteMaterial,I as SrcAlphaFactor,O as SrcAlphaSaturateFactor,z as SrcColorFactor,Bs as StaticCopyUsage,_s as StaticDrawUsage,zs as StaticReadUsage,Gc as StereoCamera,Rs as StreamCopyUsage,Ts as StreamDrawUsage,Is as StreamReadUsage,Ql as StringKeyframeTrack,w as SubtractEquation,g as SubtractiveBlending,s as TOUCH,Xe as TangentSpaceNormalMap,gl as TetrahedronGeometry,vi as Texture,mc as TextureLoader,Sd as TextureUtils,xl as TorusGeometry,bl as TorusKnotGeometry,Jr as Triangle,Ue as TriangleFanDrawMode,je as TriangleStripDrawMode,We as TrianglesDrawMode,vl as TubeGeometry,at as UVMapping,fn as Uint16BufferAttribute,xn as Uint32BufferAttribute,pn as Uint8BufferAttribute,mn as Uint8ClampedBufferAttribute,Tu as Uniform,Cu as UniformsGroup,Jn as UniformsUtils,Tt as UnsignedByteType,Ft as UnsignedInt248Type,Nt as UnsignedInt5999Type,kt as UnsignedIntType,Et as UnsignedShort4444Type,Ot as UnsignedShort5551Type,It as UnsignedShortType,c as VSMShadowMap,Zs as Vector2,Ii as Vector3,wi as Vector4,Kl as VectorKeyframeTrack,Xa as VideoFrameTexture,Ja as VideoTexture,zi as WebGL3DRenderTarget,Ai as WebGLArrayRenderTarget,Os as WebGLCoordinateSystem,so as WebGLCubeRenderTarget,Si as WebGLRenderTarget,Fs as WebGPUCoordinateSystem,wl as WireframeGeometry,Ne as WrapAroundEnding,Oe as ZeroCurvatureEnding,A as ZeroFactor,Fe as ZeroSlopeEnding,ts as ZeroStencilOp,Qs as arrayNeedsUint32,Dn as cloneUniforms,si as createCanvasElement,ei as createElementNS,Md as getByteLength,qn as getUnlitUniformColorSpace,Hn as mergeUniforms,ni as probeAsync,oi as toNormalizedProjectionMatrix,ai as toReversedProjectionMatrix,ri as warnOnce}; diff --git a/build/three.module.js b/build/three.module.js index f18b5a62c292f3..64b3c789f7816c 100644 --- a/build/three.module.js +++ b/build/three.module.js @@ -1,10 +1,10 @@ /** * @license - * Copyright 2010-2024 Three.js Authors + * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */ import { Color, Matrix3, Vector2, mergeUniforms, Vector3, CubeUVReflectionMapping, Mesh, BoxGeometry, ShaderMaterial, cloneUniforms, BackSide, ColorManagement, SRGBTransfer, PlaneGeometry, FrontSide, getUnlitUniformColorSpace, Euler, Matrix4, IntType, RGBAFormat, HalfFloatType, UnsignedByteType, FloatType, Plane, EquirectangularReflectionMapping, EquirectangularRefractionMapping, WebGLCubeRenderTarget, CubeReflectionMapping, CubeRefractionMapping, PerspectiveCamera, NoToneMapping, MeshBasicMaterial, BufferGeometry, BufferAttribute, WebGLRenderTarget, NoBlending, OrthographicCamera, LinearFilter, LinearSRGBColorSpace, warnOnce, arrayNeedsUint32, Uint32BufferAttribute, Uint16BufferAttribute, Vector4, DataArrayTexture, LessEqualCompare, Texture, DepthTexture, Data3DTexture, CubeTexture, GLSL3, CustomToneMapping, NeutralToneMapping, AgXToneMapping, ACESFilmicToneMapping, CineonToneMapping, ReinhardToneMapping, LinearToneMapping, PCFShadowMap, PCFSoftShadowMap, VSMShadowMap, LinearTransfer, AddOperation, MixOperation, MultiplyOperation, ObjectSpaceNormalMap, TangentSpaceNormalMap, NormalBlending, DoubleSide, UniformsUtils, Layers, Frustum, MeshDepthMaterial, RGBADepthPacking, MeshDistanceMaterial, NearestFilter, LessEqualDepth, AddEquation, SubtractEquation, ReverseSubtractEquation, ZeroFactor, OneFactor, SrcColorFactor, SrcAlphaFactor, SrcAlphaSaturateFactor, DstColorFactor, DstAlphaFactor, OneMinusSrcColorFactor, OneMinusSrcAlphaFactor, OneMinusDstColorFactor, OneMinusDstAlphaFactor, ConstantColorFactor, OneMinusConstantColorFactor, ConstantAlphaFactor, OneMinusConstantAlphaFactor, CustomBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, CullFaceNone, CullFaceBack, CullFaceFront, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessDepth, AlwaysDepth, NeverDepth, MinEquation, MaxEquation, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearMipmapNearestFilter, LinearMipmapLinearFilter, NeverCompare, AlwaysCompare, LessCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare, NoColorSpace, DepthStencilFormat, getByteLength, UnsignedIntType, UnsignedInt248Type, UnsignedShortType, DepthFormat, createElementNS, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt5999Type, ByteType, ShortType, AlphaFormat, RGBFormat, LuminanceFormat, LuminanceAlphaFormat, RedFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBAIntegerFormat, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_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_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, RED_GREEN_RGTC2_Format, SIGNED_RED_GREEN_RGTC2_Format, Group, EventDispatcher, ArrayCamera, RAD2DEG, createCanvasElement, SRGBColorSpace, REVISION, toNormalizedProjectionMatrix, toReversedProjectionMatrix, probeAsync, WebGLCoordinateSystem } from './three.core.js'; -export { AdditiveAnimationBlendMode, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, Controls, CubeCamera, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CylinderGeometry, Cylindrical, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualStencilFunc, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, Fog, FogExp2, FramebufferTexture, GLBufferAttribute, GLSL1, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, Material, MaterialLoader, MathUtils, Matrix2, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NeverStencilFunc, NormalAnimationBlendMode, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, OctahedronGeometry, Path, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBDepthPacking, RGBIntegerFormat, RGDepthPacking, RawShaderMaterial, Ray, Raycaster, RectAreaLight, RenderTarget, ReplaceStencilOp, RingGeometry, Scene, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, TOUCH, TetrahedronGeometry, TextureLoader, TextureUtils, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, ZeroStencilOp } from './three.core.js'; +export { AdditiveAnimationBlendMode, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, Controls, CubeCamera, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CylinderGeometry, Cylindrical, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualStencilFunc, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, Fog, FogExp2, FramebufferTexture, GLBufferAttribute, GLSL1, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, Material, MaterialLoader, MathUtils, Matrix2, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NeverStencilFunc, NormalAnimationBlendMode, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, OctahedronGeometry, Path, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBDepthPacking, RGBIntegerFormat, RGDepthPacking, RawShaderMaterial, Ray, Raycaster, RectAreaLight, RenderTarget, RenderTarget3D, RenderTargetArray, ReplaceStencilOp, RingGeometry, Scene, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, TOUCH, TetrahedronGeometry, TextureLoader, TextureUtils, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, ZeroStencilOp } from './three.core.js'; function WebGLAnimation() { @@ -493,7 +493,7 @@ var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( var 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"; -var 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"; +var 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\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\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#else\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#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"; var 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"; @@ -1535,6 +1535,8 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, boxMesh.geometry.dispose(); boxMesh.material.dispose(); + boxMesh = undefined; + } if ( planeMesh !== undefined ) { @@ -1542,6 +1544,8 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, planeMesh.geometry.dispose(); planeMesh.material.dispose(); + planeMesh = undefined; + } } @@ -13185,7 +13189,11 @@ class WebXRManager extends EventDispatcher { currentPixelRatio = renderer.getPixelRatio(); renderer.getSize( currentSize ); - if ( session.renderState.layers === undefined ) { + // Check that the browser implements the necessary APIs to use an + // XRProjectionLayer rather than an XRWebGLLayer + const useLayers = typeof XRWebGLBinding !== 'undefined' && 'createProjectionLayer' in XRWebGLBinding.prototype; + + if ( ! useLayers ) { const layerInit = { antialias: attributes.antialias, @@ -13692,8 +13700,11 @@ class WebXRManager extends EventDispatcher { // const enabledFeatures = session.enabledFeatures; + const gpuDepthSensingEnabled = enabledFeatures && + enabledFeatures.includes( 'depth-sensing' ) && + session.depthUsage == 'gpu-optimized'; - if ( enabledFeatures && enabledFeatures.includes( 'depth-sensing' ) ) { + if ( gpuDepthSensingEnabled && glBinding ) { const depthData = glBinding.getDepthInformation( views[ 0 ] ); @@ -15942,7 +15953,7 @@ class WebGLRenderer { // - if ( _currentRenderTarget !== null ) { + if ( _currentRenderTarget !== null && _currentActiveMipmapLevel === 0 ) { // resolve multisample renderbuffers to a single-sample texture if necessary @@ -16937,6 +16948,7 @@ class WebGLRenderer { }; + const _scratchFrameBuffer = _gl.createFramebuffer(); this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { _currentRenderTarget = renderTarget; @@ -17045,6 +17057,14 @@ class WebGLRenderer { } + // Use a scratch frame buffer if rendering to a mip level to avoid depth buffers + // being bound that are different sizes. + if ( activeMipmapLevel !== 0 ) { + + framebuffer = _scratchFrameBuffer; + + } + const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); if ( framebufferBound && useDefaultFramebuffer ) { @@ -17065,8 +17085,15 @@ class WebGLRenderer { } else if ( isRenderTarget3D ) { const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); + const layer = activeCubeFace; + _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel, layer ); + + } else if ( renderTarget !== null && activeMipmapLevel !== 0 ) { + + // Only bind the frame buffer if we are using a scratch frame buffer to render to a mipmap. + // If we rebind the texture when using a multi sample buffer then an error about inconsistent samples will be thrown. + const textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, textureProperties.__webglTexture, activeMipmapLevel ); } diff --git a/build/three.module.min.js b/build/three.module.min.js index 5aeafbc63f5fe3..4d566de532f88a 100644 --- a/build/three.module.min.js +++ b/build/three.module.min.js @@ -1,6 +1,6 @@ /** * @license - * Copyright 2010-2024 Three.js Authors + * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */ -import{Color as e,Matrix3 as t,Vector2 as n,mergeUniforms as i,Vector3 as r,CubeUVReflectionMapping as a,Mesh as o,BoxGeometry as s,ShaderMaterial as l,cloneUniforms as c,BackSide as d,ColorManagement as u,SRGBTransfer as f,PlaneGeometry as p,FrontSide as m,getUnlitUniformColorSpace as h,Euler as _,Matrix4 as g,IntType as v,RGBAFormat as E,HalfFloatType as S,UnsignedByteType as T,FloatType as M,Plane as x,EquirectangularReflectionMapping as R,EquirectangularRefractionMapping as A,WebGLCubeRenderTarget as b,CubeReflectionMapping as C,CubeRefractionMapping as L,PerspectiveCamera as P,NoToneMapping as U,MeshBasicMaterial as w,BufferGeometry as D,BufferAttribute as y,WebGLRenderTarget as I,NoBlending as N,OrthographicCamera as O,LinearFilter as F,LinearSRGBColorSpace as B,warnOnce as H,arrayNeedsUint32 as G,Uint32BufferAttribute as V,Uint16BufferAttribute as z,Vector4 as k,DataArrayTexture as W,LessEqualCompare as X,Texture as Y,DepthTexture as j,Data3DTexture as K,CubeTexture as q,GLSL3 as Z,CustomToneMapping as $,NeutralToneMapping as Q,AgXToneMapping as J,ACESFilmicToneMapping as ee,CineonToneMapping as te,ReinhardToneMapping as ne,LinearToneMapping as ie,PCFShadowMap as re,PCFSoftShadowMap as ae,VSMShadowMap as oe,LinearTransfer as se,AddOperation as le,MixOperation as ce,MultiplyOperation as de,ObjectSpaceNormalMap as ue,TangentSpaceNormalMap as fe,NormalBlending as pe,DoubleSide as me,UniformsUtils as he,Layers as _e,Frustum as ge,MeshDepthMaterial as ve,RGBADepthPacking as Ee,MeshDistanceMaterial as Se,NearestFilter as Te,LessEqualDepth as Me,AddEquation as xe,SubtractEquation as Re,ReverseSubtractEquation as Ae,ZeroFactor as be,OneFactor as Ce,SrcColorFactor as Le,SrcAlphaFactor as Pe,SrcAlphaSaturateFactor as Ue,DstColorFactor as we,DstAlphaFactor as De,OneMinusSrcColorFactor as ye,OneMinusSrcAlphaFactor as Ie,OneMinusDstColorFactor as Ne,OneMinusDstAlphaFactor as Oe,ConstantColorFactor as Fe,OneMinusConstantColorFactor as Be,ConstantAlphaFactor as He,OneMinusConstantAlphaFactor as Ge,CustomBlending as Ve,MultiplyBlending as ze,SubtractiveBlending as ke,AdditiveBlending as We,CullFaceNone as Xe,CullFaceBack as Ye,CullFaceFront as je,NotEqualDepth as Ke,GreaterDepth as qe,GreaterEqualDepth as Ze,EqualDepth as $e,LessDepth as Qe,AlwaysDepth as Je,NeverDepth as et,MinEquation as tt,MaxEquation as nt,RepeatWrapping as it,ClampToEdgeWrapping as rt,MirroredRepeatWrapping as at,NearestMipmapNearestFilter as ot,NearestMipmapLinearFilter as st,LinearMipmapNearestFilter as lt,LinearMipmapLinearFilter as ct,NeverCompare as dt,AlwaysCompare as ut,LessCompare as ft,EqualCompare as pt,GreaterEqualCompare as mt,GreaterCompare as ht,NotEqualCompare as _t,NoColorSpace as gt,DepthStencilFormat as vt,getByteLength as Et,UnsignedIntType as St,UnsignedInt248Type as Tt,UnsignedShortType as Mt,DepthFormat as xt,createElementNS as Rt,UnsignedShort4444Type as At,UnsignedShort5551Type as bt,UnsignedInt5999Type as Ct,ByteType as Lt,ShortType as Pt,AlphaFormat as Ut,RGBFormat as wt,LuminanceFormat as Dt,LuminanceAlphaFormat as yt,RedFormat as It,RedIntegerFormat as Nt,RGFormat as Ot,RGIntegerFormat as Ft,RGBAIntegerFormat as Bt,RGB_S3TC_DXT1_Format as Ht,RGBA_S3TC_DXT1_Format as Gt,RGBA_S3TC_DXT3_Format as Vt,RGBA_S3TC_DXT5_Format as zt,RGB_PVRTC_4BPPV1_Format as kt,RGB_PVRTC_2BPPV1_Format as Wt,RGBA_PVRTC_4BPPV1_Format as Xt,RGBA_PVRTC_2BPPV1_Format as Yt,RGB_ETC1_Format as jt,RGB_ETC2_Format as Kt,RGBA_ETC2_EAC_Format as qt,RGBA_ASTC_4x4_Format as Zt,RGBA_ASTC_5x4_Format as $t,RGBA_ASTC_5x5_Format as Qt,RGBA_ASTC_6x5_Format as Jt,RGBA_ASTC_6x6_Format as en,RGBA_ASTC_8x5_Format as tn,RGBA_ASTC_8x6_Format as nn,RGBA_ASTC_8x8_Format as rn,RGBA_ASTC_10x5_Format as an,RGBA_ASTC_10x6_Format as on,RGBA_ASTC_10x8_Format as sn,RGBA_ASTC_10x10_Format as ln,RGBA_ASTC_12x10_Format as cn,RGBA_ASTC_12x12_Format as dn,RGBA_BPTC_Format as un,RGB_BPTC_SIGNED_Format as fn,RGB_BPTC_UNSIGNED_Format as pn,RED_RGTC1_Format as mn,SIGNED_RED_RGTC1_Format as hn,RED_GREEN_RGTC2_Format as _n,SIGNED_RED_GREEN_RGTC2_Format as gn,Group as vn,EventDispatcher as En,ArrayCamera as Sn,RAD2DEG as Tn,createCanvasElement as Mn,SRGBColorSpace as xn,REVISION as Rn,toNormalizedProjectionMatrix as An,toReversedProjectionMatrix as bn,probeAsync as Cn,WebGLCoordinateSystem as Ln}from"./three.core.min.js";export{AdditiveAnimationBlendMode,AlwaysStencilFunc,AmbientLight,AnimationAction,AnimationClip,AnimationLoader,AnimationMixer,AnimationObjectGroup,AnimationUtils,ArcCurve,ArrowHelper,AttachedBindMode,Audio,AudioAnalyser,AudioContext,AudioListener,AudioLoader,AxesHelper,BasicDepthPacking,BasicShadowMap,BatchedMesh,Bone,BooleanKeyframeTrack,Box2,Box3,Box3Helper,BoxHelper,BufferGeometryLoader,Cache,Camera,CameraHelper,CanvasTexture,CapsuleGeometry,CatmullRomCurve3,CircleGeometry,Clock,ColorKeyframeTrack,CompressedArrayTexture,CompressedCubeTexture,CompressedTexture,CompressedTextureLoader,ConeGeometry,Controls,CubeCamera,CubeTextureLoader,CubicBezierCurve,CubicBezierCurve3,CubicInterpolant,CullFaceFrontBack,Curve,CurvePath,CylinderGeometry,Cylindrical,DataTexture,DataTextureLoader,DataUtils,DecrementStencilOp,DecrementWrapStencilOp,DefaultLoadingManager,DetachedBindMode,DirectionalLight,DirectionalLightHelper,DiscreteInterpolant,DodecahedronGeometry,DynamicCopyUsage,DynamicDrawUsage,DynamicReadUsage,EdgesGeometry,EllipseCurve,EqualStencilFunc,ExtrudeGeometry,FileLoader,Float16BufferAttribute,Float32BufferAttribute,Fog,FogExp2,FramebufferTexture,GLBufferAttribute,GLSL1,GreaterEqualStencilFunc,GreaterStencilFunc,GridHelper,HemisphereLight,HemisphereLightHelper,IcosahedronGeometry,ImageBitmapLoader,ImageLoader,ImageUtils,IncrementStencilOp,IncrementWrapStencilOp,InstancedBufferAttribute,InstancedBufferGeometry,InstancedInterleavedBuffer,InstancedMesh,Int16BufferAttribute,Int32BufferAttribute,Int8BufferAttribute,InterleavedBuffer,InterleavedBufferAttribute,Interpolant,InterpolateDiscrete,InterpolateLinear,InterpolateSmooth,InvertStencilOp,KeepStencilOp,KeyframeTrack,LOD,LatheGeometry,LessEqualStencilFunc,LessStencilFunc,Light,LightProbe,Line,Line3,LineBasicMaterial,LineCurve,LineCurve3,LineDashedMaterial,LineLoop,LineSegments,LinearInterpolant,LinearMipMapLinearFilter,LinearMipMapNearestFilter,Loader,LoaderUtils,LoadingManager,LoopOnce,LoopPingPong,LoopRepeat,MOUSE,Material,MaterialLoader,MathUtils,Matrix2,MeshLambertMaterial,MeshMatcapMaterial,MeshNormalMaterial,MeshPhongMaterial,MeshPhysicalMaterial,MeshStandardMaterial,MeshToonMaterial,NearestMipMapLinearFilter,NearestMipMapNearestFilter,NeverStencilFunc,NormalAnimationBlendMode,NotEqualStencilFunc,NumberKeyframeTrack,Object3D,ObjectLoader,OctahedronGeometry,Path,PlaneHelper,PointLight,PointLightHelper,Points,PointsMaterial,PolarGridHelper,PolyhedronGeometry,PositionalAudio,PropertyBinding,PropertyMixer,QuadraticBezierCurve,QuadraticBezierCurve3,Quaternion,QuaternionKeyframeTrack,QuaternionLinearInterpolant,RGBDepthPacking,RGBIntegerFormat,RGDepthPacking,RawShaderMaterial,Ray,Raycaster,RectAreaLight,RenderTarget,ReplaceStencilOp,RingGeometry,Scene,ShadowMaterial,Shape,ShapeGeometry,ShapePath,ShapeUtils,Skeleton,SkeletonHelper,SkinnedMesh,Source,Sphere,SphereGeometry,Spherical,SphericalHarmonics3,SplineCurve,SpotLight,SpotLightHelper,Sprite,SpriteMaterial,StaticCopyUsage,StaticDrawUsage,StaticReadUsage,StereoCamera,StreamCopyUsage,StreamDrawUsage,StreamReadUsage,StringKeyframeTrack,TOUCH,TetrahedronGeometry,TextureLoader,TextureUtils,TorusGeometry,TorusKnotGeometry,Triangle,TriangleFanDrawMode,TriangleStripDrawMode,TrianglesDrawMode,TubeGeometry,UVMapping,Uint8BufferAttribute,Uint8ClampedBufferAttribute,Uniform,UniformsGroup,VectorKeyframeTrack,VideoTexture,WebGL3DRenderTarget,WebGLArrayRenderTarget,WebGPUCoordinateSystem,WireframeGeometry,WrapAroundEnding,ZeroCurvatureEnding,ZeroSlopeEnding,ZeroStencilOp}from"./three.core.min.js";function Pn(){let e=null,t=!1,n=null,i=null;function r(t,a){n(t,a),i=e.requestAnimationFrame(r)}return{start:function(){!0!==t&&null!==n&&(i=e.requestAnimationFrame(r),t=!0)},stop:function(){e.cancelAnimationFrame(i),t=!1},setAnimationLoop:function(e){n=e},setContext:function(t){e=t}}}function Un(e){const t=new WeakMap;return{get:function(e){return e.isInterleavedBufferAttribute&&(e=e.data),t.get(e)},remove:function(n){n.isInterleavedBufferAttribute&&(n=n.data);const i=t.get(n);i&&(e.deleteBuffer(i.buffer),t.delete(n))},update:function(n,i){if(n.isInterleavedBufferAttribute&&(n=n.data),n.isGLBufferAttribute){const e=t.get(n);return void((!e||e.versione.start-t.start));let t=0;for(let e=1;e 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\t#ifdef DECODE_VIDEO_TEXTURE_EMISSIVE\n\t\temissiveColor = sRGBTransferEOTF( emissiveColor );\n\t#endif\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:"vec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferEOTF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\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 = sRGBTransferEOTF( sampledDiffuseColor );\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}"},Dn={common:{diffuse:{value:new e(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new t},alphaMap:{value:null},alphaMapTransform:{value:new t},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new t}},envmap:{envMap:{value:null},envMapRotation:{value:new t},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new t}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new t}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new t},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new t},normalScale:{value:new n(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new t},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new t}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new t}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new t}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new e(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 e(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new t},alphaTest:{value:0},uvTransform:{value:new t}},sprite:{diffuse:{value:new e(16777215)},opacity:{value:1},center:{value:new n(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new t},alphaMap:{value:null},alphaMapTransform:{value:new t},alphaTest:{value:0}}},yn={basic:{uniforms:i([Dn.common,Dn.specularmap,Dn.envmap,Dn.aomap,Dn.lightmap,Dn.fog]),vertexShader:wn.meshbasic_vert,fragmentShader:wn.meshbasic_frag},lambert:{uniforms:i([Dn.common,Dn.specularmap,Dn.envmap,Dn.aomap,Dn.lightmap,Dn.emissivemap,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.fog,Dn.lights,{emissive:{value:new e(0)}}]),vertexShader:wn.meshlambert_vert,fragmentShader:wn.meshlambert_frag},phong:{uniforms:i([Dn.common,Dn.specularmap,Dn.envmap,Dn.aomap,Dn.lightmap,Dn.emissivemap,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.fog,Dn.lights,{emissive:{value:new e(0)},specular:{value:new e(1118481)},shininess:{value:30}}]),vertexShader:wn.meshphong_vert,fragmentShader:wn.meshphong_frag},standard:{uniforms:i([Dn.common,Dn.envmap,Dn.aomap,Dn.lightmap,Dn.emissivemap,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.roughnessmap,Dn.metalnessmap,Dn.fog,Dn.lights,{emissive:{value:new e(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:wn.meshphysical_vert,fragmentShader:wn.meshphysical_frag},toon:{uniforms:i([Dn.common,Dn.aomap,Dn.lightmap,Dn.emissivemap,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.gradientmap,Dn.fog,Dn.lights,{emissive:{value:new e(0)}}]),vertexShader:wn.meshtoon_vert,fragmentShader:wn.meshtoon_frag},matcap:{uniforms:i([Dn.common,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.fog,{matcap:{value:null}}]),vertexShader:wn.meshmatcap_vert,fragmentShader:wn.meshmatcap_frag},points:{uniforms:i([Dn.points,Dn.fog]),vertexShader:wn.points_vert,fragmentShader:wn.points_frag},dashed:{uniforms:i([Dn.common,Dn.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:wn.linedashed_vert,fragmentShader:wn.linedashed_frag},depth:{uniforms:i([Dn.common,Dn.displacementmap]),vertexShader:wn.depth_vert,fragmentShader:wn.depth_frag},normal:{uniforms:i([Dn.common,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,{opacity:{value:1}}]),vertexShader:wn.meshnormal_vert,fragmentShader:wn.meshnormal_frag},sprite:{uniforms:i([Dn.sprite,Dn.fog]),vertexShader:wn.sprite_vert,fragmentShader:wn.sprite_frag},background:{uniforms:{uvTransform:{value:new t},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:wn.background_vert,fragmentShader:wn.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new t}},vertexShader:wn.backgroundCube_vert,fragmentShader:wn.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:wn.cube_vert,fragmentShader:wn.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:wn.equirect_vert,fragmentShader:wn.equirect_frag},distanceRGBA:{uniforms:i([Dn.common,Dn.displacementmap,{referencePosition:{value:new r},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:wn.distanceRGBA_vert,fragmentShader:wn.distanceRGBA_frag},shadow:{uniforms:i([Dn.lights,Dn.fog,{color:{value:new e(0)},opacity:{value:1}}]),vertexShader:wn.shadow_vert,fragmentShader:wn.shadow_frag}};yn.physical={uniforms:i([yn.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new t},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new t},clearcoatNormalScale:{value:new n(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new t},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new t},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new t},sheen:{value:0},sheenColor:{value:new e(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new t},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new t},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new t},transmissionSamplerSize:{value:new n},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new t},attenuationDistance:{value:0},attenuationColor:{value:new e(0)},specularColor:{value:new e(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new t},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new t},anisotropyVector:{value:new n},anisotropyMap:{value:null},anisotropyMapTransform:{value:new t}}]),vertexShader:wn.meshphysical_vert,fragmentShader:wn.meshphysical_frag};const In={r:0,b:0,g:0},Nn=new _,On=new g;function Fn(t,n,i,r,_,g,v){const E=new e(0);let S,T,M=!0===g?0:1,x=null,R=0,A=null;function b(e){let t=!0===e.isScene?e.background:null;if(t&&t.isTexture){t=(e.backgroundBlurriness>0?i:n).get(t)}return t}function C(e,n){e.getRGB(In,h(t)),r.buffers.color.setClear(In.r,In.g,In.b,n,v)}return{getClearColor:function(){return E},setClearColor:function(e,t=1){E.set(e),M=t,C(E,M)},getClearAlpha:function(){return M},setClearAlpha:function(e){M=e,C(E,M)},render:function(e){let n=!1;const i=b(e);null===i?C(E,M):i&&i.isColor&&(C(i,1),n=!0);const a=t.xr.getEnvironmentBlendMode();"additive"===a?r.buffers.color.setClear(0,0,0,1,v):"alpha-blend"===a&&r.buffers.color.setClear(0,0,0,0,v),(t.autoClear||n)&&(r.buffers.depth.setTest(!0),r.buffers.depth.setMask(!0),r.buffers.color.setMask(!0),t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil))},addToRenderList:function(e,n){const i=b(n);i&&(i.isCubeTexture||i.mapping===a)?(void 0===T&&(T=new o(new s(1,1,1),new l({name:"BackgroundCubeMaterial",uniforms:c(yn.backgroundCube.uniforms),vertexShader:yn.backgroundCube.vertexShader,fragmentShader:yn.backgroundCube.fragmentShader,side:d,depthTest:!1,depthWrite:!1,fog:!1})),T.geometry.deleteAttribute("normal"),T.geometry.deleteAttribute("uv"),T.onBeforeRender=function(e,t,n){this.matrixWorld.copyPosition(n.matrixWorld)},Object.defineProperty(T.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),_.update(T)),Nn.copy(n.backgroundRotation),Nn.x*=-1,Nn.y*=-1,Nn.z*=-1,i.isCubeTexture&&!1===i.isRenderTargetTexture&&(Nn.y*=-1,Nn.z*=-1),T.material.uniforms.envMap.value=i,T.material.uniforms.flipEnvMap.value=i.isCubeTexture&&!1===i.isRenderTargetTexture?-1:1,T.material.uniforms.backgroundBlurriness.value=n.backgroundBlurriness,T.material.uniforms.backgroundIntensity.value=n.backgroundIntensity,T.material.uniforms.backgroundRotation.value.setFromMatrix4(On.makeRotationFromEuler(Nn)),T.material.toneMapped=u.getTransfer(i.colorSpace)!==f,x===i&&R===i.version&&A===t.toneMapping||(T.material.needsUpdate=!0,x=i,R=i.version,A=t.toneMapping),T.layers.enableAll(),e.unshift(T,T.geometry,T.material,0,0,null)):i&&i.isTexture&&(void 0===S&&(S=new o(new p(2,2),new l({name:"BackgroundMaterial",uniforms:c(yn.background.uniforms),vertexShader:yn.background.vertexShader,fragmentShader:yn.background.fragmentShader,side:m,depthTest:!1,depthWrite:!1,fog:!1})),S.geometry.deleteAttribute("normal"),Object.defineProperty(S.material,"map",{get:function(){return this.uniforms.t2D.value}}),_.update(S)),S.material.uniforms.t2D.value=i,S.material.uniforms.backgroundIntensity.value=n.backgroundIntensity,S.material.toneMapped=u.getTransfer(i.colorSpace)!==f,!0===i.matrixAutoUpdate&&i.updateMatrix(),S.material.uniforms.uvTransform.value.copy(i.matrix),x===i&&R===i.version&&A===t.toneMapping||(S.material.needsUpdate=!0,x=i,R=i.version,A=t.toneMapping),S.layers.enableAll(),e.unshift(S,S.geometry,S.material,0,0,null))},dispose:function(){void 0!==T&&(T.geometry.dispose(),T.material.dispose()),void 0!==S&&(S.geometry.dispose(),S.material.dispose())}}}function Bn(e,t){const n=e.getParameter(e.MAX_VERTEX_ATTRIBS),i={},r=c(null);let a=r,o=!1;function s(t){return e.bindVertexArray(t)}function l(t){return e.deleteVertexArray(t)}function c(e){const t=[],i=[],r=[];for(let e=0;e=0){const n=r[t];let i=o[t];if(void 0===i&&("instanceMatrix"===t&&e.instanceMatrix&&(i=e.instanceMatrix),"instanceColor"===t&&e.instanceColor&&(i=e.instanceColor)),void 0===n)return!0;if(n.attribute!==i)return!0;if(i&&n.data!==i.data)return!0;s++}}return a.attributesNum!==s||a.index!==i}(n,h,l,_),g&&function(e,t,n,i){const r={},o=t.attributes;let s=0;const l=n.getAttributes();for(const t in l){if(l[t].location>=0){let n=o[t];void 0===n&&("instanceMatrix"===t&&e.instanceMatrix&&(n=e.instanceMatrix),"instanceColor"===t&&e.instanceColor&&(n=e.instanceColor));const i={};i.attribute=n,n&&n.data&&(i.data=n.data),r[t]=i,s++}}a.attributes=r,a.attributesNum=s,a.index=i}(n,h,l,_),null!==_&&t.update(_,e.ELEMENT_ARRAY_BUFFER),(g||o)&&(o=!1,function(n,i,r,a){d();const o=a.attributes,s=r.getAttributes(),l=i.defaultAttributeValues;for(const i in s){const r=s[i];if(r.location>=0){let s=o[i];if(void 0===s&&("instanceMatrix"===i&&n.instanceMatrix&&(s=n.instanceMatrix),"instanceColor"===i&&n.instanceColor&&(s=n.instanceColor)),void 0!==s){const i=s.normalized,o=s.itemSize,l=t.get(s);if(void 0===l)continue;const c=l.buffer,d=l.type,p=l.bytesPerElement,h=d===e.INT||d===e.UNSIGNED_INT||s.gpuType===v;if(s.isInterleavedBufferAttribute){const t=s.data,l=t.stride,_=s.offset;if(t.isInstancedInterleavedBuffer){for(let e=0;e0&&e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT).precision>0)return"highp";t="mediump"}return"mediump"===t&&e.getShaderPrecisionFormat(e.VERTEX_SHADER,e.MEDIUM_FLOAT).precision>0&&e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let o=void 0!==n.precision?n.precision:"highp";const s=a(o);s!==o&&(console.warn("THREE.WebGLRenderer:",o,"not supported, using",s,"instead."),o=s);const l=!0===n.logarithmicDepthBuffer,c=!0===n.reverseDepthBuffer&&t.has("EXT_clip_control"),d=e.getParameter(e.MAX_TEXTURE_IMAGE_UNITS),u=e.getParameter(e.MAX_VERTEX_TEXTURE_IMAGE_UNITS);return{isWebGL2:!0,getMaxAnisotropy:function(){if(void 0!==r)return r;if(!0===t.has("EXT_texture_filter_anisotropic")){const n=t.get("EXT_texture_filter_anisotropic");r=e.getParameter(n.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else r=0;return r},getMaxPrecision:a,textureFormatReadable:function(t){return t===E||i.convert(t)===e.getParameter(e.IMPLEMENTATION_COLOR_READ_FORMAT)},textureTypeReadable:function(n){const r=n===S&&(t.has("EXT_color_buffer_half_float")||t.has("EXT_color_buffer_float"));return!(n!==T&&i.convert(n)!==e.getParameter(e.IMPLEMENTATION_COLOR_READ_TYPE)&&n!==M&&!r)},precision:o,logarithmicDepthBuffer:l,reverseDepthBuffer:c,maxTextures:d,maxVertexTextures:u,maxTextureSize:e.getParameter(e.MAX_TEXTURE_SIZE),maxCubemapSize:e.getParameter(e.MAX_CUBE_MAP_TEXTURE_SIZE),maxAttributes:e.getParameter(e.MAX_VERTEX_ATTRIBS),maxVertexUniforms:e.getParameter(e.MAX_VERTEX_UNIFORM_VECTORS),maxVaryings:e.getParameter(e.MAX_VARYING_VECTORS),maxFragmentUniforms:e.getParameter(e.MAX_FRAGMENT_UNIFORM_VECTORS),vertexTextures:u>0,maxSamples:e.getParameter(e.MAX_SAMPLES)}}function Vn(e){const n=this;let i=null,r=0,a=!1,o=!1;const s=new x,l=new t,c={value:null,needsUpdate:!1};function d(e,t,i,r){const a=null!==e?e.length:0;let o=null;if(0!==a){if(o=c.value,!0!==r||null===o){const n=i+4*a,r=t.matrixWorldInverse;l.getNormalMatrix(r),(null===o||o.length0);n.numPlanes=r,n.numIntersection=0}();else{const e=o?0:r,t=4*e;let n=m.clippingState||null;c.value=n,n=d(u,s,t,l);for(let e=0;e!==t;++e)n[e]=i[e];m.clippingState=n,this.numIntersection=f?this.numPlanes:0,this.numPlanes+=e}}}function zn(e){let t=new WeakMap;function n(e,t){return t===R?e.mapping=C:t===A&&(e.mapping=L),e}function i(e){const n=e.target;n.removeEventListener("dispose",i);const r=t.get(n);void 0!==r&&(t.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const a=r.mapping;if(a===R||a===A){if(t.has(r)){return n(t.get(r).texture,r.mapping)}{const a=r.image;if(a&&a.height>0){const o=new b(a.height);return o.fromEquirectangularTexture(e,r),t.set(r,o),r.addEventListener("dispose",i),n(o.texture,r.mapping)}return null}}}return r},dispose:function(){t=new WeakMap}}}const kn=[.125,.215,.35,.446,.526,.582],Wn=20,Xn=new O,Yn=new e;let jn=null,Kn=0,qn=0,Zn=!1;const $n=(1+Math.sqrt(5))/2,Qn=1/$n,Jn=[new r(-$n,Qn,0),new r($n,Qn,0),new r(-Qn,0,$n),new r(Qn,0,$n),new r(0,$n,-Qn),new r(0,$n,Qn),new r(-1,1,-1),new r(1,1,-1),new r(-1,1,1),new r(1,1,1)];class ei{constructor(e){this._renderer=e,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(e,t=0,n=.1,i=100){jn=this._renderer.getRenderTarget(),Kn=this._renderer.getActiveCubeFace(),qn=this._renderer.getActiveMipmapLevel(),Zn=this._renderer.xr.enabled,this._renderer.xr.enabled=!1,this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(e,n,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=ri(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=ii(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),null!==this._cubemapMaterial&&this._cubemapMaterial.dispose(),null!==this._equirectMaterial&&this._equirectMaterial.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?s=kn[o-e+4-1]:0===o&&(s=0),i.push(s);const l=1/(a-2),c=-l,d=1+l,u=[c,c,d,c,d,d,c,c,d,d,c,d],f=6,p=6,m=3,h=2,_=1,g=new Float32Array(m*p*f),v=new Float32Array(h*p*f),E=new Float32Array(_*p*f);for(let e=0;e2?0:-1,i=[t,n,0,t+2/3,n,0,t+2/3,n+1,0,t,n,0,t+2/3,n+1,0,t,n+1,0];g.set(i,m*p*e),v.set(u,h*p*e);const r=[e,e,e,e,e,e];E.set(r,_*p*e)}const S=new D;S.setAttribute("position",new y(g,m)),S.setAttribute("uv",new y(v,h)),S.setAttribute("faceIndex",new y(E,_)),t.push(S),r>4&&r--}return{lodPlanes:t,sizeLods:n,sigmas:i}}(i)),this._blurMaterial=function(e,t,n){const i=new Float32Array(Wn),a=new r(0,1,0),o=new l({name:"SphericalGaussianBlur",defines:{n:Wn,CUBEUV_TEXEL_WIDTH:1/t,CUBEUV_TEXEL_HEIGHT:1/n,CUBEUV_MAX_MIP:`${e}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:i},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:a}},vertexShader:ai(),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:N,depthTest:!1,depthWrite:!1});return o}(i,e,t)}return i}_compileMaterial(e){const t=new o(this._lodPlanes[0],e);this._renderer.compile(t,Xn)}_sceneToCubeUV(e,t,n,i){const r=new P(90,1,t,n),a=[1,-1,1,1,1,1],l=[1,1,1,-1,-1,-1],c=this._renderer,u=c.autoClear,f=c.toneMapping;c.getClearColor(Yn),c.toneMapping=U,c.autoClear=!1;const p=new w({name:"PMREM.Background",side:d,depthWrite:!1,depthTest:!1}),m=new o(new s,p);let h=!1;const _=e.background;_?_.isColor&&(p.color.copy(_),e.background=null,h=!0):(p.color.copy(Yn),h=!0);for(let t=0;t<6;t++){const n=t%3;0===n?(r.up.set(0,a[t],0),r.lookAt(l[t],0,0)):1===n?(r.up.set(0,0,a[t]),r.lookAt(0,l[t],0)):(r.up.set(0,a[t],0),r.lookAt(0,0,l[t]));const o=this._cubeSize;ni(i,n*o,t>2?o:0,o,o),c.setRenderTarget(i),h&&c.render(m,r),c.render(e,r)}m.geometry.dispose(),m.material.dispose(),c.toneMapping=f,c.autoClear=u,e.background=_}_textureToCubeUV(e,t){const n=this._renderer,i=e.mapping===C||e.mapping===L;i?(null===this._cubemapMaterial&&(this._cubemapMaterial=ri()),this._cubemapMaterial.uniforms.flipEnvMap.value=!1===e.isRenderTargetTexture?-1:1):null===this._equirectMaterial&&(this._equirectMaterial=ii());const r=i?this._cubemapMaterial:this._equirectMaterial,a=new o(this._lodPlanes[0],r);r.uniforms.envMap.value=e;const s=this._cubeSize;ni(t,0,0,3*s,2*s),n.setRenderTarget(t),n.render(a,Xn)}_applyPMREM(e){const t=this._renderer,n=t.autoClear;t.autoClear=!1;const i=this._lodPlanes.length;for(let t=1;tWn&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${h} samples when the maximum is set to 20`);const _=[];let g=0;for(let e=0;ev-4?i-v+4:0),4*(this._cubeSize-E),3*E,2*E),l.setRenderTarget(t),l.render(d,Xn)}}function ti(e,t,n){const i=new I(e,t,n);return i.texture.mapping=a,i.texture.name="PMREM.cubeUv",i.scissorTest=!0,i}function ni(e,t,n,i,r){e.viewport.set(t,n,i,r),e.scissor.set(t,n,i,r)}function ii(){return new l({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:ai(),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:N,depthTest:!1,depthWrite:!1})}function ri(){return new l({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:ai(),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:N,depthTest:!1,depthWrite:!1})}function ai(){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 oi(e){let t=new WeakMap,n=null;function i(e){const n=e.target;n.removeEventListener("dispose",i);const r=t.get(n);void 0!==r&&(t.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const a=r.mapping,o=a===R||a===A,s=a===C||a===L;if(o||s){let a=t.get(r);const l=void 0!==a?a.texture.pmremVersion:0;if(r.isRenderTargetTexture&&r.pmremVersion!==l)return null===n&&(n=new ei(e)),a=o?n.fromEquirectangular(r,a):n.fromCubemap(r,a),a.texture.pmremVersion=r.pmremVersion,t.set(r,a),a.texture;if(void 0!==a)return a.texture;{const l=r.image;return o&&l&&l.height>0||s&&l&&function(e){let t=0;const n=6;for(let i=0;it.maxTextureSize&&(T=Math.ceil(S/t.maxTextureSize),S=t.maxTextureSize);const x=new Float32Array(S*T*4*u),R=new W(x,S,T,u);R.type=M,R.needsUpdate=!0;const A=4*E;for(let C=0;C0)return e;const r=t*n;let a=vi[r];if(void 0===a&&(a=new Float32Array(r),vi[r]=a),0!==t){i.toArray(a,0);for(let i=1,r=0;i!==t;++i)r+=n,e[i].toArray(a,r)}return a}function Ri(e,t){if(e.length!==t.length)return!1;for(let n=0,i=e.length;n":" "} ${r}: ${n[e]}`)}return i.join("\n")}(e.getShaderSource(t),i)}return r}function Mr(e,t){const n=function(e){u._getMatrix(Sr,u.workingColorSpace,e);const t=`mat3( ${Sr.elements.map((e=>e.toFixed(4)))} )`;switch(u.getTransfer(e)){case se:return[t,"LinearTransferOETF"];case f:return[t,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space: ",e),[t,"LinearTransferOETF"]}}(t);return[`vec4 ${e}( vec4 value ) {`,`\treturn ${n[1]}( vec4( value.rgb * ${n[0]}, value.a ) );`,"}"].join("\n")}function xr(e,t){let n;switch(t){case ie:n="Linear";break;case ne:n="Reinhard";break;case te:n="Cineon";break;case ee:n="ACESFilmic";break;case J:n="AgX";break;case Q:n="Neutral";break;case $:n="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",t),n="Linear"}return"vec3 "+e+"( vec3 color ) { return "+n+"ToneMapping( color ); }"}const Rr=new r;function Ar(){u.getLuminanceCoefficients(Rr);return["float luminance( const in vec3 rgb ) {",`\tconst vec3 weights = vec3( ${Rr.x.toFixed(4)}, ${Rr.y.toFixed(4)}, ${Rr.z.toFixed(4)} );`,"\treturn dot( weights, rgb );","}"].join("\n")}function br(e){return""!==e}function Cr(e,t){const n=t.numSpotLightShadows+t.numSpotLightMaps-t.numSpotLightShadowsWithMaps;return e.replace(/NUM_DIR_LIGHTS/g,t.numDirLights).replace(/NUM_SPOT_LIGHTS/g,t.numSpotLights).replace(/NUM_SPOT_LIGHT_MAPS/g,t.numSpotLightMaps).replace(/NUM_SPOT_LIGHT_COORDS/g,n).replace(/NUM_RECT_AREA_LIGHTS/g,t.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g,t.numPointLights).replace(/NUM_HEMI_LIGHTS/g,t.numHemiLights).replace(/NUM_DIR_LIGHT_SHADOWS/g,t.numDirLightShadows).replace(/NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g,t.numSpotLightShadowsWithMaps).replace(/NUM_SPOT_LIGHT_SHADOWS/g,t.numSpotLightShadows).replace(/NUM_POINT_LIGHT_SHADOWS/g,t.numPointLightShadows)}function Lr(e,t){return e.replace(/NUM_CLIPPING_PLANES/g,t.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g,t.numClippingPlanes-t.numClipIntersection)}const Pr=/^[ \t]*#include +<([\w\d./]+)>/gm;function Ur(e){return e.replace(Pr,Dr)}const wr=new Map;function Dr(e,t){let n=wn[t];if(void 0===n){const e=wr.get(t);if(void 0===e)throw new Error("Can not resolve #include <"+t+">");n=wn[e],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',t,e)}return Ur(n)}const yr=/#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 Ir(e){return e.replace(yr,Nr)}function Nr(e,t,n,i){let r="";for(let e=parseInt(t);e0&&(g+="\n"),v=["#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,h].filter(br).join("\n"),v.length>0&&(v+="\n")):(g=[Or(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,h,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 "+u:"",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 "+c:"",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(br).join("\n"),v=[Or(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,h,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 "+u:"",n.envMap?"#define "+f:"",p?"#define CUBEUV_TEXEL_WIDTH "+p.texelWidth:"",p?"#define CUBEUV_TEXEL_HEIGHT "+p.texelHeight:"",p?"#define CUBEUV_MAX_MIP "+p.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 "+c:"",n.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",n.numLightProbes>0?"#define USE_LIGHT_PROBES":"",n.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",n.decodeVideoTextureEmissive?"#define DECODE_VIDEO_TEXTURE_EMISSIVE":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.reverseDepthBuffer?"#define USE_REVERSEDEPTHBUF":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",n.toneMapping!==U?"#define TONE_MAPPING":"",n.toneMapping!==U?wn.tonemapping_pars_fragment:"",n.toneMapping!==U?xr("toneMapping",n.toneMapping):"",n.dithering?"#define DITHERING":"",n.opaque?"#define OPAQUE":"",wn.colorspace_pars_fragment,Mr("linearToOutputTexel",n.outputColorSpace),Ar(),n.useDepthPacking?"#define DEPTH_PACKING "+n.depthPacking:"","\n"].filter(br).join("\n")),s=Ur(s),s=Cr(s,n),s=Lr(s,n),l=Ur(l),l=Cr(l,n),l=Lr(l,n),s=Ir(s),l=Ir(l),!0!==n.isRawShaderMaterial&&(E="#version 300 es\n",g=[m,"#define attribute in","#define varying out","#define texture2D texture"].join("\n")+"\n"+g,v=["#define varying in",n.glslVersion===Z?"":"layout(location = 0) out highp vec4 pc_fragColor;",n.glslVersion===Z?"":"#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"+v);const S=E+g+s,T=E+v+l,M=vr(r,r.VERTEX_SHADER,S),x=vr(r,r.FRAGMENT_SHADER,T);function R(t){if(e.debug.checkShaderErrors){const n=r.getProgramInfoLog(_).trim(),i=r.getShaderInfoLog(M).trim(),a=r.getShaderInfoLog(x).trim();let o=!0,s=!0;if(!1===r.getProgramParameter(_,r.LINK_STATUS))if(o=!1,"function"==typeof e.debug.onShaderError)e.debug.onShaderError(r,_,M,x);else{const e=Tr(r,M,"vertex"),i=Tr(r,x,"fragment");console.error("THREE.WebGLProgram: Shader Error "+r.getError()+" - VALIDATE_STATUS "+r.getProgramParameter(_,r.VALIDATE_STATUS)+"\n\nMaterial Name: "+t.name+"\nMaterial Type: "+t.type+"\n\nProgram Info Log: "+n+"\n"+e+"\n"+i)}else""!==n?console.warn("THREE.WebGLProgram: Program Info Log:",n):""!==i&&""!==a||(s=!1);s&&(t.diagnostics={runnable:o,programLog:n,vertexShader:{log:i,prefix:g},fragmentShader:{log:a,prefix:v}})}r.deleteShader(M),r.deleteShader(x),A=new gr(r,_),b=function(e,t){const n={},i=e.getProgramParameter(t,e.ACTIVE_ATTRIBUTES);for(let r=0;r0,J=o.clearcoat>0,ee=o.dispersion>0,te=o.iridescence>0,ne=o.sheen>0,ie=o.transmission>0,re=Q&&!!o.anisotropyMap,ae=J&&!!o.clearcoatMap,oe=J&&!!o.clearcoatNormalMap,se=J&&!!o.clearcoatRoughnessMap,le=te&&!!o.iridescenceMap,ce=te&&!!o.iridescenceThicknessMap,de=ne&&!!o.sheenColorMap,he=ne&&!!o.sheenRoughnessMap,_e=!!o.specularMap,ge=!!o.specularColorMap,ve=!!o.specularIntensityMap,Ee=ie&&!!o.transmissionMap,Se=ie&&!!o.thicknessMap,Te=!!o.gradientMap,Me=!!o.alphaMap,xe=o.alphaTest>0,Re=!!o.alphaHash,Ae=!!o.extensions;let be=U;o.toneMapped&&(null!==O&&!0!==O.isXRRenderTarget||(be=e.toneMapping));const Ce={shaderID:C,shaderType:o.type,shaderName:o.name,vertexShader:w,fragmentShader:D,defines:o.defines,customVertexShaderID:y,customFragmentShaderID:I,isRawShaderMaterial:!0===o.isRawShaderMaterial,glslVersion:o.glslVersion,precision:g,batching:G,batchingColor:G&&null!==T._colorsTexture,instancing:H,instancingColor:H&&null!==T.instanceColor,instancingMorph:H&&null!==T.morphTexture,supportsVertexTextures:_,outputColorSpace:null===O?e.outputColorSpace:!0===O.isXRRenderTarget?O.texture.colorSpace:B,alphaToCoverage:!!o.alphaToCoverage,map:V,matcap:z,envMap:k,envMapMode:k&&A.mapping,envMapCubeUVHeight:b,aoMap:W,lightMap:X,bumpMap:Y,normalMap:j,displacementMap:_&&K,emissiveMap:q,normalMapObjectSpace:j&&o.normalMapType===ue,normalMapTangentSpace:j&&o.normalMapType===fe,metalnessMap:Z,roughnessMap:$,anisotropy:Q,anisotropyMap:re,clearcoat:J,clearcoatMap:ae,clearcoatNormalMap:oe,clearcoatRoughnessMap:se,dispersion:ee,iridescence:te,iridescenceMap:le,iridescenceThicknessMap:ce,sheen:ne,sheenColorMap:de,sheenRoughnessMap:he,specularMap:_e,specularColorMap:ge,specularIntensityMap:ve,transmission:ie,transmissionMap:Ee,thicknessMap:Se,gradientMap:Te,opaque:!1===o.transparent&&o.blending===pe&&!1===o.alphaToCoverage,alphaMap:Me,alphaTest:xe,alphaHash:Re,combine:o.combine,mapUv:V&&E(o.map.channel),aoMapUv:W&&E(o.aoMap.channel),lightMapUv:X&&E(o.lightMap.channel),bumpMapUv:Y&&E(o.bumpMap.channel),normalMapUv:j&&E(o.normalMap.channel),displacementMapUv:K&&E(o.displacementMap.channel),emissiveMapUv:q&&E(o.emissiveMap.channel),metalnessMapUv:Z&&E(o.metalnessMap.channel),roughnessMapUv:$&&E(o.roughnessMap.channel),anisotropyMapUv:re&&E(o.anisotropyMap.channel),clearcoatMapUv:ae&&E(o.clearcoatMap.channel),clearcoatNormalMapUv:oe&&E(o.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:se&&E(o.clearcoatRoughnessMap.channel),iridescenceMapUv:le&&E(o.iridescenceMap.channel),iridescenceThicknessMapUv:ce&&E(o.iridescenceThicknessMap.channel),sheenColorMapUv:de&&E(o.sheenColorMap.channel),sheenRoughnessMapUv:he&&E(o.sheenRoughnessMap.channel),specularMapUv:_e&&E(o.specularMap.channel),specularColorMapUv:ge&&E(o.specularColorMap.channel),specularIntensityMapUv:ve&&E(o.specularIntensityMap.channel),transmissionMapUv:Ee&&E(o.transmissionMap.channel),thicknessMapUv:Se&&E(o.thicknessMap.channel),alphaMapUv:Me&&E(o.alphaMap.channel),vertexTangents:!!x.attributes.tangent&&(j||Q),vertexColors:o.vertexColors,vertexAlphas:!0===o.vertexColors&&!!x.attributes.color&&4===x.attributes.color.itemSize,pointsUvs:!0===T.isPoints&&!!x.attributes.uv&&(V||Me),fog:!!M,useFog:!0===o.fog,fogExp2:!!M&&M.isFogExp2,flatShading:!0===o.flatShading,sizeAttenuation:!0===o.sizeAttenuation,logarithmicDepthBuffer:h,reverseDepthBuffer:F,skinning:!0===T.isSkinnedMesh,morphTargets:void 0!==x.morphAttributes.position,morphNormals:void 0!==x.morphAttributes.normal,morphColors:void 0!==x.morphAttributes.color,morphTargetsCount:P,morphTextureStride:N,numDirLights:l.directional.length,numPointLights:l.point.length,numSpotLights:l.spot.length,numSpotLightMaps:l.spotLightMap.length,numRectAreaLights:l.rectArea.length,numHemiLights:l.hemi.length,numDirLightShadows:l.directionalShadowMap.length,numPointLightShadows:l.pointShadowMap.length,numSpotLightShadows:l.spotShadowMap.length,numSpotLightShadowsWithMaps:l.numSpotLightShadowsWithMaps,numLightProbes:l.numLightProbes,numClippingPlanes:s.numPlanes,numClipIntersection:s.numIntersection,dithering:o.dithering,shadowMapEnabled:e.shadowMap.enabled&&m.length>0,shadowMapType:e.shadowMap.type,toneMapping:be,decodeVideoTexture:V&&!0===o.map.isVideoTexture&&u.getTransfer(o.map.colorSpace)===f,decodeVideoTextureEmissive:q&&!0===o.emissiveMap.isVideoTexture&&u.getTransfer(o.emissiveMap.colorSpace)===f,premultipliedAlpha:o.premultipliedAlpha,doubleSided:o.side===me,flipSided:o.side===d,useDepthPacking:o.depthPacking>=0,depthPacking:o.depthPacking||0,index0AttributeName:o.index0AttributeName,extensionClipCullDistance:Ae&&!0===o.extensions.clipCullDistance&&i.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(Ae&&!0===o.extensions.multiDraw||G)&&i.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:i.has("KHR_parallel_shader_compile"),customProgramCacheKey:o.customProgramCacheKey()};return Ce.vertexUv1s=p.has(1),Ce.vertexUv2s=p.has(2),Ce.vertexUv3s=p.has(3),p.clear(),Ce},getProgramCacheKey:function(t){const n=[];if(t.shaderID?n.push(t.shaderID):(n.push(t.customVertexShaderID),n.push(t.customFragmentShaderID)),void 0!==t.defines)for(const e in t.defines)n.push(e),n.push(t.defines[e]);return!1===t.isRawShaderMaterial&&(!function(e,t){e.push(t.precision),e.push(t.outputColorSpace),e.push(t.envMapMode),e.push(t.envMapCubeUVHeight),e.push(t.mapUv),e.push(t.alphaMapUv),e.push(t.lightMapUv),e.push(t.aoMapUv),e.push(t.bumpMapUv),e.push(t.normalMapUv),e.push(t.displacementMapUv),e.push(t.emissiveMapUv),e.push(t.metalnessMapUv),e.push(t.roughnessMapUv),e.push(t.anisotropyMapUv),e.push(t.clearcoatMapUv),e.push(t.clearcoatNormalMapUv),e.push(t.clearcoatRoughnessMapUv),e.push(t.iridescenceMapUv),e.push(t.iridescenceThicknessMapUv),e.push(t.sheenColorMapUv),e.push(t.sheenRoughnessMapUv),e.push(t.specularMapUv),e.push(t.specularColorMapUv),e.push(t.specularIntensityMapUv),e.push(t.transmissionMapUv),e.push(t.thicknessMapUv),e.push(t.combine),e.push(t.fogExp2),e.push(t.sizeAttenuation),e.push(t.morphTargetsCount),e.push(t.morphAttributeCount),e.push(t.numDirLights),e.push(t.numPointLights),e.push(t.numSpotLights),e.push(t.numSpotLightMaps),e.push(t.numHemiLights),e.push(t.numRectAreaLights),e.push(t.numDirLightShadows),e.push(t.numPointLightShadows),e.push(t.numSpotLightShadows),e.push(t.numSpotLightShadowsWithMaps),e.push(t.numLightProbes),e.push(t.shadowMapType),e.push(t.toneMapping),e.push(t.numClippingPlanes),e.push(t.numClipIntersection),e.push(t.depthPacking)}(n,t),function(e,t){l.disableAll(),t.supportsVertexTextures&&l.enable(0);t.instancing&&l.enable(1);t.instancingColor&&l.enable(2);t.instancingMorph&&l.enable(3);t.matcap&&l.enable(4);t.envMap&&l.enable(5);t.normalMapObjectSpace&&l.enable(6);t.normalMapTangentSpace&&l.enable(7);t.clearcoat&&l.enable(8);t.iridescence&&l.enable(9);t.alphaTest&&l.enable(10);t.vertexColors&&l.enable(11);t.vertexAlphas&&l.enable(12);t.vertexUv1s&&l.enable(13);t.vertexUv2s&&l.enable(14);t.vertexUv3s&&l.enable(15);t.vertexTangents&&l.enable(16);t.anisotropy&&l.enable(17);t.alphaHash&&l.enable(18);t.batching&&l.enable(19);t.dispersion&&l.enable(20);t.batchingColor&&l.enable(21);e.push(l.mask),l.disableAll(),t.fog&&l.enable(0);t.useFog&&l.enable(1);t.flatShading&&l.enable(2);t.logarithmicDepthBuffer&&l.enable(3);t.reverseDepthBuffer&&l.enable(4);t.skinning&&l.enable(5);t.morphTargets&&l.enable(6);t.morphNormals&&l.enable(7);t.morphColors&&l.enable(8);t.premultipliedAlpha&&l.enable(9);t.shadowMapEnabled&&l.enable(10);t.doubleSided&&l.enable(11);t.flipSided&&l.enable(12);t.useDepthPacking&&l.enable(13);t.dithering&&l.enable(14);t.transmission&&l.enable(15);t.sheen&&l.enable(16);t.opaque&&l.enable(17);t.pointsUvs&&l.enable(18);t.decodeVideoTexture&&l.enable(19);t.decodeVideoTextureEmissive&&l.enable(20);t.alphaToCoverage&&l.enable(21);e.push(l.mask)}(n,t),n.push(e.outputColorSpace)),n.push(t.customProgramCacheKey),n.join()},getUniforms:function(e){const t=v[e.type];let n;if(t){const e=yn[t];n=he.clone(e.uniforms)}else n=e.uniforms;return n},acquireProgram:function(t,n){let i;for(let e=0,t=m.length;e0?i.push(d):!0===o.transparent?r.push(d):n.push(d)},unshift:function(e,t,o,s,l,c){const d=a(e,t,o,s,l,c);o.transmission>0?i.unshift(d):!0===o.transparent?r.unshift(d):n.unshift(d)},finish:function(){for(let n=t,i=e.length;n1&&n.sort(e||kr),i.length>1&&i.sort(t||Wr),r.length>1&&r.sort(t||Wr)}}}function Yr(){let e=new WeakMap;return{get:function(t,n){const i=e.get(t);let r;return void 0===i?(r=new Xr,e.set(t,[r])):n>=i.length?(r=new Xr,i.push(r)):r=i[n],r},dispose:function(){e=new WeakMap}}}function jr(){const t={};return{get:function(n){if(void 0!==t[n.id])return t[n.id];let i;switch(n.type){case"DirectionalLight":i={direction:new r,color:new e};break;case"SpotLight":i={position:new r,direction:new r,color:new e,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":i={position:new r,color:new e,distance:0,decay:0};break;case"HemisphereLight":i={direction:new r,skyColor:new e,groundColor:new e};break;case"RectAreaLight":i={color:new e,position:new r,halfWidth:new r,halfHeight:new r}}return t[n.id]=i,i}}}let Kr=0;function qr(e,t){return(t.castShadow?2:0)-(e.castShadow?2:0)+(t.map?1:0)-(e.map?1:0)}function Zr(e){const t=new jr,i=function(){const e={};return{get:function(t){if(void 0!==e[t.id])return e[t.id];let i;switch(t.type){case"DirectionalLight":case"SpotLight":i={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new n};break;case"PointLight":i={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new n,shadowCameraNear:1,shadowCameraFar:1e3}}return e[t.id]=i,i}}}(),a={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 e=0;e<9;e++)a.probe.push(new r);const o=new r,s=new g,l=new g;return{setup:function(n){let r=0,o=0,s=0;for(let e=0;e<9;e++)a.probe[e].set(0,0,0);let l=0,c=0,d=0,u=0,f=0,p=0,m=0,h=0,_=0,g=0,v=0;n.sort(qr);for(let e=0,E=n.length;e0&&(!0===e.has("OES_texture_float_linear")?(a.rectAreaLTC1=Dn.LTC_FLOAT_1,a.rectAreaLTC2=Dn.LTC_FLOAT_2):(a.rectAreaLTC1=Dn.LTC_HALF_1,a.rectAreaLTC2=Dn.LTC_HALF_2)),a.ambient[0]=r,a.ambient[1]=o,a.ambient[2]=s;const E=a.hash;E.directionalLength===l&&E.pointLength===c&&E.spotLength===d&&E.rectAreaLength===u&&E.hemiLength===f&&E.numDirectionalShadows===p&&E.numPointShadows===m&&E.numSpotShadows===h&&E.numSpotMaps===_&&E.numLightProbes===v||(a.directional.length=l,a.spot.length=d,a.rectArea.length=u,a.point.length=c,a.hemi.length=f,a.directionalShadow.length=p,a.directionalShadowMap.length=p,a.pointShadow.length=m,a.pointShadowMap.length=m,a.spotShadow.length=h,a.spotShadowMap.length=h,a.directionalShadowMatrix.length=p,a.pointShadowMatrix.length=m,a.spotLightMatrix.length=h+_-g,a.spotLightMap.length=_,a.numSpotLightShadowsWithMaps=g,a.numLightProbes=v,E.directionalLength=l,E.pointLength=c,E.spotLength=d,E.rectAreaLength=u,E.hemiLength=f,E.numDirectionalShadows=p,E.numPointShadows=m,E.numSpotShadows=h,E.numSpotMaps=_,E.numLightProbes=v,a.version=Kr++)},setupView:function(e,t){let n=0,i=0,r=0,c=0,d=0;const u=t.matrixWorldInverse;for(let t=0,f=e.length;t=r.length?(a=new $r(e),r.push(a)):a=r[i],a},dispose:function(){t=new WeakMap}}}function Jr(e,t,i){let r=new ge;const a=new n,s=new n,c=new k,u=new ve({depthPacking:Ee}),f=new Se,p={},h=i.maxTextureSize,_={[m]:d,[d]:m,[me]:me},g=new l({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new n},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 E=new D;E.setAttribute("position",new y(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const S=new o(E,g),T=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=re;let M=this.type;function x(n,i){const r=t.update(S);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 I(a.x,a.y)),g.uniforms.shadow_pass.value=n.map.texture,g.uniforms.resolution.value=n.mapSize,g.uniforms.radius.value=n.radius,e.setRenderTarget(n.mapPass),e.clear(),e.renderBufferDirect(i,null,r,g,S,null),v.uniforms.shadow_pass.value=n.mapPass.texture,v.uniforms.resolution.value=n.mapSize,v.uniforms.radius.value=n.radius,e.setRenderTarget(n.map),e.clear(),e.renderBufferDirect(i,null,r,v,S,null)}function R(t,n,i,r){let a=null;const o=!0===i.isPointLight?t.customDistanceMaterial:t.customDepthMaterial;if(void 0!==o)a=o;else if(a=!0===i.isPointLight?f:u,e.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 e=a.uuid,t=n.uuid;let i=p[e];void 0===i&&(i={},p[e]=i);let r=i[t];void 0===r&&(r=a.clone(),i[t]=r,n.addEventListener("dispose",b)),a=r}if(a.visible=n.visible,a.wireframe=n.wireframe,a.side=r===oe?null!==n.shadowSide?n.shadowSide:n.side:null!==n.shadowSide?n.shadowSide:_[n.side],a.alphaMap=n.alphaMap,a.alphaTest=n.alphaTest,a.map=n.map,a.clipShadows=n.clipShadows,a.clippingPlanes=n.clippingPlanes,a.clipIntersection=n.clipIntersection,a.displacementMap=n.displacementMap,a.displacementScale=n.displacementScale,a.displacementBias=n.displacementBias,a.wireframeLinewidth=n.wireframeLinewidth,a.linewidth=n.linewidth,!0===i.isPointLight&&!0===a.isMeshDistanceMaterial){e.properties.get(a).light=i}return a}function A(n,i,a,o,s){if(!1===n.visible)return;if(n.layers.test(i.layers)&&(n.isMesh||n.isLine||n.isPoints)&&(n.castShadow||n.receiveShadow&&s===oe)&&(!n.frustumCulled||r.intersectsObject(n))){n.modelViewMatrix.multiplyMatrices(a.matrixWorldInverse,n.matrixWorld);const r=t.update(n),l=n.material;if(Array.isArray(l)){const t=r.groups;for(let c=0,d=t.length;ch||a.y>h)&&(a.x>h&&(s.x=Math.floor(h/m.x),a.x=s.x*m.x,d.mapSize.x=s.x),a.y>h&&(s.y=Math.floor(h/m.y),a.y=s.y*m.y,d.mapSize.y=s.y)),null===d.map||!0===f||!0===p){const e=this.type!==oe?{minFilter:Te,magFilter:Te}:{};null!==d.map&&d.map.dispose(),d.map=new I(a.x,a.y,e),d.map.texture.name=l.name+".shadowMap",d.camera.updateProjectionMatrix()}e.setRenderTarget(d.map),e.clear();const _=d.getViewportCount();for(let e=0;e<_;e++){const t=d.getViewport(e);c.set(s.x*t.x,s.y*t.y,s.x*t.z,s.y*t.w),u.viewport(c),d.updateMatrices(l,e),r=d.getFrustum(),A(n,i,d.camera,l,this.type)}!0!==d.isPointLightShadow&&this.type===oe&&x(d,i),d.needsUpdate=!1}M=this.type,T.needsUpdate=!1,e.setRenderTarget(o,l,d)}}const ea={[et]:Je,[Qe]:qe,[$e]:Ke,[Me]:Ze,[Je]:et,[qe]:Qe,[Ke]:$e,[Ze]:Me};function ta(t,n){const i=new function(){let e=!1;const n=new k;let i=null;const r=new k(0,0,0,0);return{setMask:function(n){i===n||e||(t.colorMask(n,n,n,n),i=n)},setLocked:function(t){e=t},setClear:function(e,i,a,o,s){!0===s&&(e*=o,i*=o,a*=o),n.set(e,i,a,o),!1===r.equals(n)&&(t.clearColor(e,i,a,o),r.copy(n))},reset:function(){e=!1,i=null,r.set(-1,0,0,0)}}},r=new function(){let e=!1,i=!1,r=null,a=null,o=null;return{setReversed:function(e){if(i!==e){const e=n.get("EXT_clip_control");i?e.clipControlEXT(e.LOWER_LEFT_EXT,e.ZERO_TO_ONE_EXT):e.clipControlEXT(e.LOWER_LEFT_EXT,e.NEGATIVE_ONE_TO_ONE_EXT);const t=o;o=null,this.setClear(t)}i=e},getReversed:function(){return i},setTest:function(e){e?W(t.DEPTH_TEST):X(t.DEPTH_TEST)},setMask:function(n){r===n||e||(t.depthMask(n),r=n)},setFunc:function(e){if(i&&(e=ea[e]),a!==e){switch(e){case et:t.depthFunc(t.NEVER);break;case Je:t.depthFunc(t.ALWAYS);break;case Qe:t.depthFunc(t.LESS);break;case Me:t.depthFunc(t.LEQUAL);break;case $e:t.depthFunc(t.EQUAL);break;case Ze:t.depthFunc(t.GEQUAL);break;case qe:t.depthFunc(t.GREATER);break;case Ke:t.depthFunc(t.NOTEQUAL);break;default:t.depthFunc(t.LEQUAL)}a=e}},setLocked:function(t){e=t},setClear:function(e){o!==e&&(i&&(e=1-e),t.clearDepth(e),o=e)},reset:function(){e=!1,r=null,a=null,o=null,i=!1}}},a=new function(){let e=!1,n=null,i=null,r=null,a=null,o=null,s=null,l=null,c=null;return{setTest:function(n){e||(n?W(t.STENCIL_TEST):X(t.STENCIL_TEST))},setMask:function(i){n===i||e||(t.stencilMask(i),n=i)},setFunc:function(e,n,o){i===e&&r===n&&a===o||(t.stencilFunc(e,n,o),i=e,r=n,a=o)},setOp:function(e,n,i){o===e&&s===n&&l===i||(t.stencilOp(e,n,i),o=e,s=n,l=i)},setLocked:function(t){e=t},setClear:function(e){c!==e&&(t.clearStencil(e),c=e)},reset:function(){e=!1,n=null,i=null,r=null,a=null,o=null,s=null,l=null,c=null}}},o=new WeakMap,s=new WeakMap;let l={},c={},u=new WeakMap,f=[],p=null,m=!1,h=null,_=null,g=null,v=null,E=null,S=null,T=null,M=new e(0,0,0),x=0,R=!1,A=null,b=null,C=null,L=null,P=null;const U=t.getParameter(t.MAX_COMBINED_TEXTURE_IMAGE_UNITS);let w=!1,D=0;const y=t.getParameter(t.VERSION);-1!==y.indexOf("WebGL")?(D=parseFloat(/^WebGL (\d)/.exec(y)[1]),w=D>=1):-1!==y.indexOf("OpenGL ES")&&(D=parseFloat(/^OpenGL ES (\d)/.exec(y)[1]),w=D>=2);let I=null,O={};const F=t.getParameter(t.SCISSOR_BOX),B=t.getParameter(t.VIEWPORT),H=(new k).fromArray(F),G=(new k).fromArray(B);function V(e,n,i,r){const a=new Uint8Array(4),o=t.createTexture();t.bindTexture(e,o),t.texParameteri(e,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(e,t.TEXTURE_MAG_FILTER,t.NEAREST);for(let o=0;on||r.height>n)&&(i=n/Math.max(r.width,r.height)),i<1){if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!=typeof VideoFrame&&e instanceof VideoFrame){const n=Math.floor(i*r.width),a=Math.floor(i*r.height);void 0===m&&(m=g(n,a));const o=t?g(n,a):m;o.width=n,o.height=a;return o.getContext("2d").drawImage(e,0,0,n,a),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+r.width+"x"+r.height+") to ("+n+"x"+a+")."),o}return"data"in e&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+r.width+"x"+r.height+")."),e}return e}function S(e){return e.generateMipmaps}function x(t){e.generateMipmap(t)}function R(t){return t.isWebGLCubeRenderTarget?e.TEXTURE_CUBE_MAP:t.isWebGL3DRenderTarget?e.TEXTURE_3D:t.isWebGLArrayRenderTarget||t.isCompressedArrayTexture?e.TEXTURE_2D_ARRAY:e.TEXTURE_2D}function A(n,i,r,a,o=!1){if(null!==n){if(void 0!==e[n])return e[n];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+n+"'")}let s=i;if(i===e.RED&&(r===e.FLOAT&&(s=e.R32F),r===e.HALF_FLOAT&&(s=e.R16F),r===e.UNSIGNED_BYTE&&(s=e.R8)),i===e.RED_INTEGER&&(r===e.UNSIGNED_BYTE&&(s=e.R8UI),r===e.UNSIGNED_SHORT&&(s=e.R16UI),r===e.UNSIGNED_INT&&(s=e.R32UI),r===e.BYTE&&(s=e.R8I),r===e.SHORT&&(s=e.R16I),r===e.INT&&(s=e.R32I)),i===e.RG&&(r===e.FLOAT&&(s=e.RG32F),r===e.HALF_FLOAT&&(s=e.RG16F),r===e.UNSIGNED_BYTE&&(s=e.RG8)),i===e.RG_INTEGER&&(r===e.UNSIGNED_BYTE&&(s=e.RG8UI),r===e.UNSIGNED_SHORT&&(s=e.RG16UI),r===e.UNSIGNED_INT&&(s=e.RG32UI),r===e.BYTE&&(s=e.RG8I),r===e.SHORT&&(s=e.RG16I),r===e.INT&&(s=e.RG32I)),i===e.RGB_INTEGER&&(r===e.UNSIGNED_BYTE&&(s=e.RGB8UI),r===e.UNSIGNED_SHORT&&(s=e.RGB16UI),r===e.UNSIGNED_INT&&(s=e.RGB32UI),r===e.BYTE&&(s=e.RGB8I),r===e.SHORT&&(s=e.RGB16I),r===e.INT&&(s=e.RGB32I)),i===e.RGBA_INTEGER&&(r===e.UNSIGNED_BYTE&&(s=e.RGBA8UI),r===e.UNSIGNED_SHORT&&(s=e.RGBA16UI),r===e.UNSIGNED_INT&&(s=e.RGBA32UI),r===e.BYTE&&(s=e.RGBA8I),r===e.SHORT&&(s=e.RGBA16I),r===e.INT&&(s=e.RGBA32I)),i===e.RGB&&r===e.UNSIGNED_INT_5_9_9_9_REV&&(s=e.RGB9_E5),i===e.RGBA){const t=o?se:u.getTransfer(a);r===e.FLOAT&&(s=e.RGBA32F),r===e.HALF_FLOAT&&(s=e.RGBA16F),r===e.UNSIGNED_BYTE&&(s=t===f?e.SRGB8_ALPHA8:e.RGBA8),r===e.UNSIGNED_SHORT_4_4_4_4&&(s=e.RGBA4),r===e.UNSIGNED_SHORT_5_5_5_1&&(s=e.RGB5_A1)}return s!==e.R16F&&s!==e.R32F&&s!==e.RG16F&&s!==e.RG32F&&s!==e.RGBA16F&&s!==e.RGBA32F||t.get("EXT_color_buffer_float"),s}function b(t,n){let i;return t?null===n||n===St||n===Tt?i=e.DEPTH24_STENCIL8:n===M?i=e.DEPTH32F_STENCIL8:n===Mt&&(i=e.DEPTH24_STENCIL8,console.warn("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):null===n||n===St||n===Tt?i=e.DEPTH_COMPONENT24:n===M?i=e.DEPTH_COMPONENT32F:n===Mt&&(i=e.DEPTH_COMPONENT16),i}function C(e,t){return!0===S(e)||e.isFramebufferTexture&&e.minFilter!==Te&&e.minFilter!==F?Math.log2(Math.max(t.width,t.height))+1:void 0!==e.mipmaps&&e.mipmaps.length>0?e.mipmaps.length:e.isCompressedTexture&&Array.isArray(e.image)?t.mipmaps.length:1}function L(e){const t=e.target;t.removeEventListener("dispose",L),function(e){const t=r.get(e);if(void 0===t.__webglInit)return;const n=e.source,i=h.get(n);if(i){const r=i[t.__cacheKey];r.usedTimes--,0===r.usedTimes&&U(e),0===Object.keys(i).length&&h.delete(n)}r.remove(e)}(t),t.isVideoTexture&&p.delete(t)}function P(t){const n=t.target;n.removeEventListener("dispose",P),function(t){const n=r.get(t);t.depthTexture&&(t.depthTexture.dispose(),r.remove(t.depthTexture));if(t.isWebGLCubeRenderTarget)for(let t=0;t<6;t++){if(Array.isArray(n.__webglFramebuffer[t]))for(let i=0;i0&&a.__version!==t.version){const e=t.image;if(null===e)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else{if(!1!==e.complete)return void G(a,t,n);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete")}}i.bindTexture(e.TEXTURE_2D,a.__webglTexture,e.TEXTURE0+n)}const y={[it]:e.REPEAT,[rt]:e.CLAMP_TO_EDGE,[at]:e.MIRRORED_REPEAT},I={[Te]:e.NEAREST,[ot]:e.NEAREST_MIPMAP_NEAREST,[st]:e.NEAREST_MIPMAP_LINEAR,[F]:e.LINEAR,[lt]:e.LINEAR_MIPMAP_NEAREST,[ct]:e.LINEAR_MIPMAP_LINEAR},N={[dt]:e.NEVER,[ut]:e.ALWAYS,[ft]:e.LESS,[X]:e.LEQUAL,[pt]:e.EQUAL,[mt]:e.GEQUAL,[ht]:e.GREATER,[_t]:e.NOTEQUAL};function O(n,i){if(i.type!==M||!1!==t.has("OES_texture_float_linear")||i.magFilter!==F&&i.magFilter!==lt&&i.magFilter!==st&&i.magFilter!==ct&&i.minFilter!==F&&i.minFilter!==lt&&i.minFilter!==st&&i.minFilter!==ct||console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),e.texParameteri(n,e.TEXTURE_WRAP_S,y[i.wrapS]),e.texParameteri(n,e.TEXTURE_WRAP_T,y[i.wrapT]),n!==e.TEXTURE_3D&&n!==e.TEXTURE_2D_ARRAY||e.texParameteri(n,e.TEXTURE_WRAP_R,y[i.wrapR]),e.texParameteri(n,e.TEXTURE_MAG_FILTER,I[i.magFilter]),e.texParameteri(n,e.TEXTURE_MIN_FILTER,I[i.minFilter]),i.compareFunction&&(e.texParameteri(n,e.TEXTURE_COMPARE_MODE,e.COMPARE_REF_TO_TEXTURE),e.texParameteri(n,e.TEXTURE_COMPARE_FUNC,N[i.compareFunction])),!0===t.has("EXT_texture_filter_anisotropic")){if(i.magFilter===Te)return;if(i.minFilter!==st&&i.minFilter!==ct)return;if(i.type===M&&!1===t.has("OES_texture_float_linear"))return;if(i.anisotropy>1||r.get(i).__currentAnisotropy){const o=t.get("EXT_texture_filter_anisotropic");e.texParameterf(n,o.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(i.anisotropy,a.getMaxAnisotropy())),r.get(i).__currentAnisotropy=i.anisotropy}}}function H(t,n){let i=!1;void 0===t.__webglInit&&(t.__webglInit=!0,n.addEventListener("dispose",L));const r=n.source;let a=h.get(r);void 0===a&&(a={},h.set(r,a));const o=function(e){const t=[];return t.push(e.wrapS),t.push(e.wrapT),t.push(e.wrapR||0),t.push(e.magFilter),t.push(e.minFilter),t.push(e.anisotropy),t.push(e.internalFormat),t.push(e.format),t.push(e.type),t.push(e.generateMipmaps),t.push(e.premultiplyAlpha),t.push(e.flipY),t.push(e.unpackAlignment),t.push(e.colorSpace),t.join()}(n);if(o!==t.__cacheKey){void 0===a[o]&&(a[o]={texture:e.createTexture(),usedTimes:0},s.memory.textures++,i=!0),a[o].usedTimes++;const r=a[t.__cacheKey];void 0!==r&&(a[t.__cacheKey].usedTimes--,0===r.usedTimes&&U(n)),t.__cacheKey=o,t.__webglTexture=a[o].texture}return i}function G(t,n,s){let l=e.TEXTURE_2D;(n.isDataArrayTexture||n.isCompressedArrayTexture)&&(l=e.TEXTURE_2D_ARRAY),n.isData3DTexture&&(l=e.TEXTURE_3D);const c=H(t,n),d=n.source;i.bindTexture(l,t.__webglTexture,e.TEXTURE0+s);const f=r.get(d);if(d.version!==f.__version||!0===c){i.activeTexture(e.TEXTURE0+s);const t=u.getPrimaries(u.workingColorSpace),r=n.colorSpace===gt?null:u.getPrimaries(n.colorSpace),p=n.colorSpace===gt||t===r?e.NONE:e.BROWSER_DEFAULT_WEBGL;e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,n.flipY),e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL,n.premultiplyAlpha),e.pixelStorei(e.UNPACK_ALIGNMENT,n.unpackAlignment),e.pixelStorei(e.UNPACK_COLORSPACE_CONVERSION_WEBGL,p);let m=v(n.image,!1,a.maxTextureSize);m=q(n,m);const h=o.convert(n.format,n.colorSpace),_=o.convert(n.type);let g,T=A(n.internalFormat,h,_,n.colorSpace,n.isVideoTexture);O(l,n);const M=n.mipmaps,R=!0!==n.isVideoTexture,L=void 0===f.__version||!0===c,P=d.dataReady,U=C(n,m);if(n.isDepthTexture)T=b(n.format===vt,n.type),L&&(R?i.texStorage2D(e.TEXTURE_2D,1,T,m.width,m.height):i.texImage2D(e.TEXTURE_2D,0,T,m.width,m.height,0,h,_,null));else if(n.isDataTexture)if(M.length>0){R&&L&&i.texStorage2D(e.TEXTURE_2D,U,T,M[0].width,M[0].height);for(let t=0,n=M.length;t0){const r=Et(g.width,g.height,n.format,n.type);for(const a of n.layerUpdates){const n=g.data.subarray(a*r/g.data.BYTES_PER_ELEMENT,(a+1)*r/g.data.BYTES_PER_ELEMENT);i.compressedTexSubImage3D(e.TEXTURE_2D_ARRAY,t,0,0,a,g.width,g.height,1,h,n)}n.clearLayerUpdates()}else i.compressedTexSubImage3D(e.TEXTURE_2D_ARRAY,t,0,0,0,g.width,g.height,m.depth,h,g.data)}else i.compressedTexImage3D(e.TEXTURE_2D_ARRAY,t,T,g.width,g.height,m.depth,0,g.data,0,0);else console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else R?P&&i.texSubImage3D(e.TEXTURE_2D_ARRAY,t,0,0,0,g.width,g.height,m.depth,h,_,g.data):i.texImage3D(e.TEXTURE_2D_ARRAY,t,T,g.width,g.height,m.depth,0,h,_,g.data)}else{R&&L&&i.texStorage2D(e.TEXTURE_2D,U,T,M[0].width,M[0].height);for(let t=0,r=M.length;t0){const t=Et(m.width,m.height,n.format,n.type);for(const r of n.layerUpdates){const n=m.data.subarray(r*t/m.data.BYTES_PER_ELEMENT,(r+1)*t/m.data.BYTES_PER_ELEMENT);i.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,r,m.width,m.height,1,h,_,n)}n.clearLayerUpdates()}else i.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,0,m.width,m.height,m.depth,h,_,m.data)}else i.texImage3D(e.TEXTURE_2D_ARRAY,0,T,m.width,m.height,m.depth,0,h,_,m.data);else if(n.isData3DTexture)R?(L&&i.texStorage3D(e.TEXTURE_3D,U,T,m.width,m.height,m.depth),P&&i.texSubImage3D(e.TEXTURE_3D,0,0,0,0,m.width,m.height,m.depth,h,_,m.data)):i.texImage3D(e.TEXTURE_3D,0,T,m.width,m.height,m.depth,0,h,_,m.data);else if(n.isFramebufferTexture){if(L)if(R)i.texStorage2D(e.TEXTURE_2D,U,T,m.width,m.height);else{let t=m.width,n=m.height;for(let r=0;r>=1,n>>=1}}else if(M.length>0){if(R&&L){const t=Z(M[0]);i.texStorage2D(e.TEXTURE_2D,U,T,t.width,t.height)}for(let t=0,n=M.length;t>d),r=Math.max(1,n.height>>d);c===e.TEXTURE_3D||c===e.TEXTURE_2D_ARRAY?i.texImage3D(c,d,p,t,r,n.depth,0,u,f,null):i.texImage2D(c,d,p,t,r,0,u,f,null)}i.bindFramebuffer(e.FRAMEBUFFER,t),K(n)?l.framebufferTexture2DMultisampleEXT(e.FRAMEBUFFER,s,c,h.__webglTexture,0,j(n)):(c===e.TEXTURE_2D||c>=e.TEXTURE_CUBE_MAP_POSITIVE_X&&c<=e.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&e.framebufferTexture2D(e.FRAMEBUFFER,s,c,h.__webglTexture,d),i.bindFramebuffer(e.FRAMEBUFFER,null)}function z(t,n,i){if(e.bindRenderbuffer(e.RENDERBUFFER,t),n.depthBuffer){const r=n.depthTexture,a=r&&r.isDepthTexture?r.type:null,o=b(n.stencilBuffer,a),s=n.stencilBuffer?e.DEPTH_STENCIL_ATTACHMENT:e.DEPTH_ATTACHMENT,c=j(n);K(n)?l.renderbufferStorageMultisampleEXT(e.RENDERBUFFER,c,o,n.width,n.height):i?e.renderbufferStorageMultisample(e.RENDERBUFFER,c,o,n.width,n.height):e.renderbufferStorage(e.RENDERBUFFER,o,n.width,n.height),e.framebufferRenderbuffer(e.FRAMEBUFFER,s,e.RENDERBUFFER,t)}else{const t=n.textures;for(let r=0;r{delete n.__boundDepthTexture,delete n.__depthDisposeCallback,e.removeEventListener("dispose",t)};e.addEventListener("dispose",t),n.__depthDisposeCallback=t}n.__boundDepthTexture=e}if(t.depthTexture&&!n.__autoAllocateDepthBuffer){if(a)throw new Error("target.depthTexture not supported in Cube render targets");!function(t,n){if(n&&n.isWebGLCubeRenderTarget)throw new Error("Depth Texture with cube render targets is not supported");if(i.bindFramebuffer(e.FRAMEBUFFER,t),!n.depthTexture||!n.depthTexture.isDepthTexture)throw new Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture");const a=r.get(n.depthTexture);a.__renderTarget=n,a.__webglTexture&&n.depthTexture.image.width===n.width&&n.depthTexture.image.height===n.height||(n.depthTexture.image.width=n.width,n.depthTexture.image.height=n.height,n.depthTexture.needsUpdate=!0),D(n.depthTexture,0);const o=a.__webglTexture,s=j(n);if(n.depthTexture.format===xt)K(n)?l.framebufferTexture2DMultisampleEXT(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.TEXTURE_2D,o,0,s):e.framebufferTexture2D(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.TEXTURE_2D,o,0);else{if(n.depthTexture.format!==vt)throw new Error("Unknown depthTexture format");K(n)?l.framebufferTexture2DMultisampleEXT(e.FRAMEBUFFER,e.DEPTH_STENCIL_ATTACHMENT,e.TEXTURE_2D,o,0,s):e.framebufferTexture2D(e.FRAMEBUFFER,e.DEPTH_STENCIL_ATTACHMENT,e.TEXTURE_2D,o,0)}}(n.__webglFramebuffer,t)}else if(a){n.__webglDepthbuffer=[];for(let r=0;r<6;r++)if(i.bindFramebuffer(e.FRAMEBUFFER,n.__webglFramebuffer[r]),void 0===n.__webglDepthbuffer[r])n.__webglDepthbuffer[r]=e.createRenderbuffer(),z(n.__webglDepthbuffer[r],t,!1);else{const i=t.stencilBuffer?e.DEPTH_STENCIL_ATTACHMENT:e.DEPTH_ATTACHMENT,a=n.__webglDepthbuffer[r];e.bindRenderbuffer(e.RENDERBUFFER,a),e.framebufferRenderbuffer(e.FRAMEBUFFER,i,e.RENDERBUFFER,a)}}else if(i.bindFramebuffer(e.FRAMEBUFFER,n.__webglFramebuffer),void 0===n.__webglDepthbuffer)n.__webglDepthbuffer=e.createRenderbuffer(),z(n.__webglDepthbuffer,t,!1);else{const i=t.stencilBuffer?e.DEPTH_STENCIL_ATTACHMENT:e.DEPTH_ATTACHMENT,r=n.__webglDepthbuffer;e.bindRenderbuffer(e.RENDERBUFFER,r),e.framebufferRenderbuffer(e.FRAMEBUFFER,i,e.RENDERBUFFER,r)}i.bindFramebuffer(e.FRAMEBUFFER,null)}const W=[],Y=[];function j(e){return Math.min(a.maxSamples,e.samples)}function K(e){const n=r.get(e);return e.samples>0&&!0===t.has("WEBGL_multisampled_render_to_texture")&&!1!==n.__useRenderToTexture}function q(e,t){const n=e.colorSpace,i=e.format,r=e.type;return!0===e.isCompressedTexture||!0===e.isVideoTexture||n!==B&&n!==gt&&(u.getTransfer(n)===f?i===E&&r===T||console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",n)),t}function Z(e){return"undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement?(d.width=e.naturalWidth||e.width,d.height=e.naturalHeight||e.height):"undefined"!=typeof VideoFrame&&e instanceof VideoFrame?(d.width=e.displayWidth,d.height=e.displayHeight):(d.width=e.width,d.height=e.height),d}this.allocateTextureUnit=function(){const e=w;return e>=a.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+e+" texture units while this GPU supports only "+a.maxTextures),w+=1,e},this.resetTextureUnits=function(){w=0},this.setTexture2D=D,this.setTexture2DArray=function(t,n){const a=r.get(t);t.version>0&&a.__version!==t.version?G(a,t,n):i.bindTexture(e.TEXTURE_2D_ARRAY,a.__webglTexture,e.TEXTURE0+n)},this.setTexture3D=function(t,n){const a=r.get(t);t.version>0&&a.__version!==t.version?G(a,t,n):i.bindTexture(e.TEXTURE_3D,a.__webglTexture,e.TEXTURE0+n)},this.setTextureCube=function(t,n){const s=r.get(t);t.version>0&&s.__version!==t.version?function(t,n,s){if(6!==n.image.length)return;const l=H(t,n),c=n.source;i.bindTexture(e.TEXTURE_CUBE_MAP,t.__webglTexture,e.TEXTURE0+s);const d=r.get(c);if(c.version!==d.__version||!0===l){i.activeTexture(e.TEXTURE0+s);const t=u.getPrimaries(u.workingColorSpace),r=n.colorSpace===gt?null:u.getPrimaries(n.colorSpace),f=n.colorSpace===gt||t===r?e.NONE:e.BROWSER_DEFAULT_WEBGL;e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,n.flipY),e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL,n.premultiplyAlpha),e.pixelStorei(e.UNPACK_ALIGNMENT,n.unpackAlignment),e.pixelStorei(e.UNPACK_COLORSPACE_CONVERSION_WEBGL,f);const p=n.isCompressedTexture||n.image[0].isCompressedTexture,m=n.image[0]&&n.image[0].isDataTexture,h=[];for(let e=0;e<6;e++)h[e]=p||m?m?n.image[e].image:n.image[e]:v(n.image[e],!0,a.maxCubemapSize),h[e]=q(n,h[e]);const _=h[0],g=o.convert(n.format,n.colorSpace),T=o.convert(n.type),M=A(n.internalFormat,g,T,n.colorSpace),R=!0!==n.isVideoTexture,b=void 0===d.__version||!0===l,L=c.dataReady;let P,U=C(n,_);if(O(e.TEXTURE_CUBE_MAP,n),p){R&&b&&i.texStorage2D(e.TEXTURE_CUBE_MAP,U,M,_.width,_.height);for(let t=0;t<6;t++){P=h[t].mipmaps;for(let r=0;r0&&U++;const t=Z(h[0]);i.texStorage2D(e.TEXTURE_CUBE_MAP,U,M,t.width,t.height)}for(let t=0;t<6;t++)if(m){R?L&&i.texSubImage2D(e.TEXTURE_CUBE_MAP_POSITIVE_X+t,0,0,0,h[t].width,h[t].height,g,T,h[t].data):i.texImage2D(e.TEXTURE_CUBE_MAP_POSITIVE_X+t,0,M,h[t].width,h[t].height,0,g,T,h[t].data);for(let n=0;n1;if(u||(void 0===l.__webglTexture&&(l.__webglTexture=e.createTexture()),l.__version=n.version,s.memory.textures++),d){a.__webglFramebuffer=[];for(let t=0;t<6;t++)if(n.mipmaps&&n.mipmaps.length>0){a.__webglFramebuffer[t]=[];for(let i=0;i0){a.__webglFramebuffer=[];for(let t=0;t0&&!1===K(t)){a.__webglMultisampledFramebuffer=e.createFramebuffer(),a.__webglColorRenderbuffer=[],i.bindFramebuffer(e.FRAMEBUFFER,a.__webglMultisampledFramebuffer);for(let n=0;n0)for(let r=0;r0)for(let i=0;i0)if(!1===K(t)){const n=t.textures,a=t.width,o=t.height;let s=e.COLOR_BUFFER_BIT;const l=t.stencilBuffer?e.DEPTH_STENCIL_ATTACHMENT:e.DEPTH_ATTACHMENT,d=r.get(t),u=n.length>1;if(u)for(let t=0;ts+c?(l.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!l.inputState.pinching&&o<=s-c&&(l.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else null!==s&&e.gripSpace&&(r=t.getPose(e.gripSpace,n),null!==r&&(s.matrix.fromArray(r.transform.matrix),s.matrix.decompose(s.position,s.rotation,s.scale),s.matrixWorldNeedsUpdate=!0,r.linearVelocity?(s.hasLinearVelocity=!0,s.linearVelocity.copy(r.linearVelocity)):s.hasLinearVelocity=!1,r.angularVelocity?(s.hasAngularVelocity=!0,s.angularVelocity.copy(r.angularVelocity)):s.hasAngularVelocity=!1));null!==o&&(i=t.getPose(e.targetRaySpace,n),null===i&&null!==r&&(i=r),null!==i&&(o.matrix.fromArray(i.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,i.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(i.linearVelocity)):o.hasLinearVelocity=!1,i.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(i.angularVelocity)):o.hasAngularVelocity=!1,this.dispatchEvent(ra)))}return null!==o&&(o.visible=null!==i),null!==s&&(s.visible=null!==r),null!==l&&(l.visible=null!==a),this}_getHandJoint(e,t){if(void 0===e.joints[t.jointName]){const n=new vn;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}}class oa{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t,n){if(null===this.texture){const i=new Y;e.properties.get(i).__webglTexture=t.texture,t.depthNear===n.depthNear&&t.depthFar===n.depthFar||(this.depthNear=t.depthNear,this.depthFar=t.depthFar),this.texture=i}}getMesh(e){if(null!==this.texture&&null===this.mesh){const t=e.cameras[0].viewport,n=new l({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:t.z},depthHeight:{value:t.w}}});this.mesh=new o(new p(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class sa extends En{constructor(e,t){super();const i=this;let a=null,o=1,s=null,l="local-floor",c=1,d=null,u=null,f=null,p=null,m=null,h=null;const _=new oa,g=t.getContextAttributes();let v=null,S=null;const M=[],x=[],R=new n;let A=null;const b=new P;b.viewport=new k;const C=new P;C.viewport=new k;const L=[b,C],U=new Sn;let w=null,D=null;function y(e){const t=x.indexOf(e.inputSource);if(-1===t)return;const n=M[t];void 0!==n&&(n.update(e.inputSource,e.frame,d||s),n.dispatchEvent({type:e.type,data:e.inputSource}))}function N(){a.removeEventListener("select",y),a.removeEventListener("selectstart",y),a.removeEventListener("selectend",y),a.removeEventListener("squeeze",y),a.removeEventListener("squeezestart",y),a.removeEventListener("squeezeend",y),a.removeEventListener("end",N),a.removeEventListener("inputsourceschange",O);for(let e=0;e=0&&(x[i]=null,M[i].disconnect(n))}for(let t=0;t=x.length){x.push(n),i=e;break}if(null===x[e]){x[e]=n,i=e;break}}if(-1===i)break}const r=M[i];r&&r.connect(n)}}this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(e){let t=M[e];return void 0===t&&(t=new aa,M[e]=t),t.getTargetRaySpace()},this.getControllerGrip=function(e){let t=M[e];return void 0===t&&(t=new aa,M[e]=t),t.getGripSpace()},this.getHand=function(e){let t=M[e];return void 0===t&&(t=new aa,M[e]=t),t.getHandSpace()},this.setFramebufferScaleFactor=function(e){o=e,!0===i.isPresenting&&console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(e){l=e,!0===i.isPresenting&&console.warn("THREE.WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return d||s},this.setReferenceSpace=function(e){d=e},this.getBaseLayer=function(){return null!==p?p:m},this.getBinding=function(){return f},this.getFrame=function(){return h},this.getSession=function(){return a},this.setSession=async function(n){if(a=n,null!==a){if(v=e.getRenderTarget(),a.addEventListener("select",y),a.addEventListener("selectstart",y),a.addEventListener("selectend",y),a.addEventListener("squeeze",y),a.addEventListener("squeezestart",y),a.addEventListener("squeezeend",y),a.addEventListener("end",N),a.addEventListener("inputsourceschange",O),!0!==g.xrCompatible&&await t.makeXRCompatible(),A=e.getPixelRatio(),e.getSize(R),void 0===a.renderState.layers){const n={antialias:g.antialias,alpha:!0,depth:g.depth,stencil:g.stencil,framebufferScaleFactor:o};m=new XRWebGLLayer(a,t,n),a.updateRenderState({baseLayer:m}),e.setPixelRatio(1),e.setSize(m.framebufferWidth,m.framebufferHeight,!1),S=new I(m.framebufferWidth,m.framebufferHeight,{format:E,type:T,colorSpace:e.outputColorSpace,stencilBuffer:g.stencil})}else{let n=null,i=null,r=null;g.depth&&(r=g.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,n=g.stencil?vt:xt,i=g.stencil?Tt:St);const s={colorFormat:t.RGBA8,depthFormat:r,scaleFactor:o};f=new XRWebGLBinding(a,t),p=f.createProjectionLayer(s),a.updateRenderState({layers:[p]}),e.setPixelRatio(1),e.setSize(p.textureWidth,p.textureHeight,!1),S=new I(p.textureWidth,p.textureHeight,{format:E,type:T,depthTexture:new j(p.textureWidth,p.textureHeight,i,void 0,void 0,void 0,void 0,void 0,void 0,n),stencilBuffer:g.stencil,colorSpace:e.outputColorSpace,samples:g.antialias?4:0,resolveDepthBuffer:!1===p.ignoreDepthValues})}S.isXRRenderTarget=!0,this.setFoveation(c),d=null,s=await a.requestReferenceSpace(l),V.setContext(a),V.start(),i.isPresenting=!0,i.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(null!==a)return a.environmentBlendMode},this.getDepthTexture=function(){return _.getDepthTexture()};const F=new r,B=new r;function H(e,t){null===t?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(t.matrixWorld,e.matrix),e.matrixWorldInverse.copy(e.matrixWorld).invert()}this.updateCamera=function(e){if(null===a)return;let t=e.near,n=e.far;null!==_.texture&&(_.depthNear>0&&(t=_.depthNear),_.depthFar>0&&(n=_.depthFar)),U.near=C.near=b.near=t,U.far=C.far=b.far=n,w===U.near&&D===U.far||(a.updateRenderState({depthNear:U.near,depthFar:U.far}),w=U.near,D=U.far),b.layers.mask=2|e.layers.mask,C.layers.mask=4|e.layers.mask,U.layers.mask=b.layers.mask|C.layers.mask;const i=e.parent,r=U.cameras;H(U,i);for(let e=0;e0&&(e.alphaTest.value=i.alphaTest);const r=t.get(i),a=r.envMap,o=r.envMapRotation;a&&(e.envMap.value=a,la.copy(o),la.x*=-1,la.y*=-1,la.z*=-1,a.isCubeTexture&&!1===a.isRenderTargetTexture&&(la.y*=-1,la.z*=-1),e.envMapRotation.value.setFromMatrix4(ca.makeRotationFromEuler(la)),e.flipEnvMap.value=a.isCubeTexture&&!1===a.isRenderTargetTexture?-1:1,e.reflectivity.value=i.reflectivity,e.ior.value=i.ior,e.refractionRatio.value=i.refractionRatio),i.lightMap&&(e.lightMap.value=i.lightMap,e.lightMapIntensity.value=i.lightMapIntensity,n(i.lightMap,e.lightMapTransform)),i.aoMap&&(e.aoMap.value=i.aoMap,e.aoMapIntensity.value=i.aoMapIntensity,n(i.aoMap,e.aoMapTransform))}return{refreshFogUniforms:function(t,n){n.color.getRGB(t.fogColor.value,h(e)),n.isFog?(t.fogNear.value=n.near,t.fogFar.value=n.far):n.isFogExp2&&(t.fogDensity.value=n.density)},refreshMaterialUniforms:function(e,r,a,o,s){r.isMeshBasicMaterial||r.isMeshLambertMaterial?i(e,r):r.isMeshToonMaterial?(i(e,r),function(e,t){t.gradientMap&&(e.gradientMap.value=t.gradientMap)}(e,r)):r.isMeshPhongMaterial?(i(e,r),function(e,t){e.specular.value.copy(t.specular),e.shininess.value=Math.max(t.shininess,1e-4)}(e,r)):r.isMeshStandardMaterial?(i(e,r),function(e,t){e.metalness.value=t.metalness,t.metalnessMap&&(e.metalnessMap.value=t.metalnessMap,n(t.metalnessMap,e.metalnessMapTransform));e.roughness.value=t.roughness,t.roughnessMap&&(e.roughnessMap.value=t.roughnessMap,n(t.roughnessMap,e.roughnessMapTransform));t.envMap&&(e.envMapIntensity.value=t.envMapIntensity)}(e,r),r.isMeshPhysicalMaterial&&function(e,t,i){e.ior.value=t.ior,t.sheen>0&&(e.sheenColor.value.copy(t.sheenColor).multiplyScalar(t.sheen),e.sheenRoughness.value=t.sheenRoughness,t.sheenColorMap&&(e.sheenColorMap.value=t.sheenColorMap,n(t.sheenColorMap,e.sheenColorMapTransform)),t.sheenRoughnessMap&&(e.sheenRoughnessMap.value=t.sheenRoughnessMap,n(t.sheenRoughnessMap,e.sheenRoughnessMapTransform)));t.clearcoat>0&&(e.clearcoat.value=t.clearcoat,e.clearcoatRoughness.value=t.clearcoatRoughness,t.clearcoatMap&&(e.clearcoatMap.value=t.clearcoatMap,n(t.clearcoatMap,e.clearcoatMapTransform)),t.clearcoatRoughnessMap&&(e.clearcoatRoughnessMap.value=t.clearcoatRoughnessMap,n(t.clearcoatRoughnessMap,e.clearcoatRoughnessMapTransform)),t.clearcoatNormalMap&&(e.clearcoatNormalMap.value=t.clearcoatNormalMap,n(t.clearcoatNormalMap,e.clearcoatNormalMapTransform),e.clearcoatNormalScale.value.copy(t.clearcoatNormalScale),t.side===d&&e.clearcoatNormalScale.value.negate()));t.dispersion>0&&(e.dispersion.value=t.dispersion);t.iridescence>0&&(e.iridescence.value=t.iridescence,e.iridescenceIOR.value=t.iridescenceIOR,e.iridescenceThicknessMinimum.value=t.iridescenceThicknessRange[0],e.iridescenceThicknessMaximum.value=t.iridescenceThicknessRange[1],t.iridescenceMap&&(e.iridescenceMap.value=t.iridescenceMap,n(t.iridescenceMap,e.iridescenceMapTransform)),t.iridescenceThicknessMap&&(e.iridescenceThicknessMap.value=t.iridescenceThicknessMap,n(t.iridescenceThicknessMap,e.iridescenceThicknessMapTransform)));t.transmission>0&&(e.transmission.value=t.transmission,e.transmissionSamplerMap.value=i.texture,e.transmissionSamplerSize.value.set(i.width,i.height),t.transmissionMap&&(e.transmissionMap.value=t.transmissionMap,n(t.transmissionMap,e.transmissionMapTransform)),e.thickness.value=t.thickness,t.thicknessMap&&(e.thicknessMap.value=t.thicknessMap,n(t.thicknessMap,e.thicknessMapTransform)),e.attenuationDistance.value=t.attenuationDistance,e.attenuationColor.value.copy(t.attenuationColor));t.anisotropy>0&&(e.anisotropyVector.value.set(t.anisotropy*Math.cos(t.anisotropyRotation),t.anisotropy*Math.sin(t.anisotropyRotation)),t.anisotropyMap&&(e.anisotropyMap.value=t.anisotropyMap,n(t.anisotropyMap,e.anisotropyMapTransform)));e.specularIntensity.value=t.specularIntensity,e.specularColor.value.copy(t.specularColor),t.specularColorMap&&(e.specularColorMap.value=t.specularColorMap,n(t.specularColorMap,e.specularColorMapTransform));t.specularIntensityMap&&(e.specularIntensityMap.value=t.specularIntensityMap,n(t.specularIntensityMap,e.specularIntensityMapTransform))}(e,r,s)):r.isMeshMatcapMaterial?(i(e,r),function(e,t){t.matcap&&(e.matcap.value=t.matcap)}(e,r)):r.isMeshDepthMaterial?i(e,r):r.isMeshDistanceMaterial?(i(e,r),function(e,n){const i=t.get(n).light;e.referencePosition.value.setFromMatrixPosition(i.matrixWorld),e.nearDistance.value=i.shadow.camera.near,e.farDistance.value=i.shadow.camera.far}(e,r)):r.isMeshNormalMaterial?i(e,r):r.isLineBasicMaterial?(function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,t.map&&(e.map.value=t.map,n(t.map,e.mapTransform))}(e,r),r.isLineDashedMaterial&&function(e,t){e.dashSize.value=t.dashSize,e.totalSize.value=t.dashSize+t.gapSize,e.scale.value=t.scale}(e,r)):r.isPointsMaterial?function(e,t,i,r){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,e.size.value=t.size*i,e.scale.value=.5*r,t.map&&(e.map.value=t.map,n(t.map,e.uvTransform));t.alphaMap&&(e.alphaMap.value=t.alphaMap,n(t.alphaMap,e.alphaMapTransform));t.alphaTest>0&&(e.alphaTest.value=t.alphaTest)}(e,r,a,o):r.isSpriteMaterial?function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,e.rotation.value=t.rotation,t.map&&(e.map.value=t.map,n(t.map,e.mapTransform));t.alphaMap&&(e.alphaMap.value=t.alphaMap,n(t.alphaMap,e.alphaMapTransform));t.alphaTest>0&&(e.alphaTest.value=t.alphaTest)}(e,r):r.isShadowMaterial?(e.color.value.copy(r.color),e.opacity.value=r.opacity):r.isShaderMaterial&&(r.uniformsNeedUpdate=!1)}}}function ua(e,t,n,i){let r={},a={},o=[];const s=e.getParameter(e.MAX_UNIFORM_BUFFER_BINDINGS);function l(e,t,n,i){const r=e.value,a=t+"_"+n;if(void 0===i[a])return i[a]="number"==typeof r||"boolean"==typeof r?r:r.clone(),!0;{const e=i[a];if("number"==typeof r||"boolean"==typeof r){if(e!==r)return i[a]=r,!0}else if(!1===e.equals(r))return e.copy(r),!0}return!1}function c(e){const t={boundary:0,storage:0};return"number"==typeof e||"boolean"==typeof e?(t.boundary=4,t.storage=4):e.isVector2?(t.boundary=8,t.storage=8):e.isVector3||e.isColor?(t.boundary=16,t.storage=12):e.isVector4?(t.boundary=16,t.storage=16):e.isMatrix3?(t.boundary=48,t.storage=48):e.isMatrix4?(t.boundary=64,t.storage=64):e.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",e),t}function d(t){const n=t.target;n.removeEventListener("dispose",d);const i=o.indexOf(n.__bindingPointIndex);o.splice(i,1),e.deleteBuffer(r[n.id]),delete r[n.id],delete a[n.id]}return{bind:function(e,t){const n=t.program;i.uniformBlockBinding(e,n)},update:function(n,u){let f=r[n.id];void 0===f&&(!function(e){const t=e.uniforms;let n=0;const i=16;for(let e=0,r=t.length;e0&&(n+=i-r);e.__size=n,e.__cache={}}(n),f=function(t){const n=function(){for(let e=0;e0),u=!!n.morphAttributes.position,f=!!n.morphAttributes.normal,p=!!n.morphAttributes.color;let m=U;i.toneMapped&&(null!==D&&!0!==D.isXRRenderTarget||(m=C.toneMapping));const h=n.morphAttributes.position||n.morphAttributes.normal||n.morphAttributes.color,_=void 0!==h?h.length:0,g=fe.get(i),v=R.state.lights;if(!0===J&&(!0===ee||e!==N)){const t=e===N&&i.id===y;Ae.setState(i,e,t)}let E=!1;i.version===g.__version?g.needsLights&&g.lightsStateVersion!==v.state.version||g.outputColorSpace!==s||r.isBatchedMesh&&!1===g.batching?E=!0:r.isBatchedMesh||!0!==g.batching?r.isBatchedMesh&&!0===g.batchingColor&&null===r.colorTexture||r.isBatchedMesh&&!1===g.batchingColor&&null!==r.colorTexture||r.isInstancedMesh&&!1===g.instancing?E=!0:r.isInstancedMesh||!0!==g.instancing?r.isSkinnedMesh&&!1===g.skinning?E=!0:r.isSkinnedMesh||!0!==g.skinning?r.isInstancedMesh&&!0===g.instancingColor&&null===r.instanceColor||r.isInstancedMesh&&!1===g.instancingColor&&null!==r.instanceColor||r.isInstancedMesh&&!0===g.instancingMorph&&null===r.morphTexture||r.isInstancedMesh&&!1===g.instancingMorph&&null!==r.morphTexture||g.envMap!==l||!0===i.fog&&g.fog!==a?E=!0:void 0===g.numClippingPlanes||g.numClippingPlanes===Ae.numPlanes&&g.numIntersection===Ae.numIntersection?(g.vertexAlphas!==c||g.vertexTangents!==d||g.morphTargets!==u||g.morphNormals!==f||g.morphColors!==p||g.toneMapping!==m||g.morphTargetsCount!==_)&&(E=!0):E=!0:E=!0:E=!0:E=!0:(E=!0,g.__version=i.version);let S=g.currentProgram;!0===E&&(S=Qe(i,t,r));let T=!1,M=!1,x=!1;const A=S.getUniforms(),b=g.uniforms;de.useProgram(S.program)&&(T=!0,M=!0,x=!0);i.id!==y&&(y=i.id,M=!0);if(T||N!==e){de.buffers.depth.getReversed()?(te.copy(e.projectionMatrix),An(te),bn(te),A.setValue(Ie,"projectionMatrix",te)):A.setValue(Ie,"projectionMatrix",e.projectionMatrix),A.setValue(Ie,"viewMatrix",e.matrixWorldInverse);const t=A.map.cameraPosition;void 0!==t&&t.setValue(Ie,ie.setFromMatrixPosition(e.matrixWorld)),ce.logarithmicDepthBuffer&&A.setValue(Ie,"logDepthBufFC",2/(Math.log(e.far+1)/Math.LN2)),(i.isMeshPhongMaterial||i.isMeshToonMaterial||i.isMeshLambertMaterial||i.isMeshBasicMaterial||i.isMeshStandardMaterial||i.isShaderMaterial)&&A.setValue(Ie,"isOrthographic",!0===e.isOrthographicCamera),N!==e&&(N=e,M=!0,x=!0)}if(r.isSkinnedMesh){A.setOptional(Ie,r,"bindMatrix"),A.setOptional(Ie,r,"bindMatrixInverse");const e=r.skeleton;e&&(null===e.boneTexture&&e.computeBoneTexture(),A.setValue(Ie,"boneTexture",e.boneTexture,pe))}r.isBatchedMesh&&(A.setOptional(Ie,r,"batchingTexture"),A.setValue(Ie,"batchingTexture",r._matricesTexture,pe),A.setOptional(Ie,r,"batchingIdTexture"),A.setValue(Ie,"batchingIdTexture",r._indirectTexture,pe),A.setOptional(Ie,r,"batchingColorTexture"),null!==r._colorsTexture&&A.setValue(Ie,"batchingColorTexture",r._colorsTexture,pe));const L=n.morphAttributes;void 0===L.position&&void 0===L.normal&&void 0===L.color||Le.update(r,n,S);(M||g.receiveShadow!==r.receiveShadow)&&(g.receiveShadow=r.receiveShadow,A.setValue(Ie,"receiveShadow",r.receiveShadow));i.isMeshGouraudMaterial&&null!==i.envMap&&(b.envMap.value=l,b.flipEnvMap.value=l.isCubeTexture&&!1===l.isRenderTargetTexture?-1:1);i.isMeshStandardMaterial&&null===i.envMap&&null!==t.environment&&(b.envMapIntensity.value=t.environmentIntensity);M&&(A.setValue(Ie,"toneMappingExposure",C.toneMappingExposure),g.needsLights&&(w=x,(P=b).ambientLightColor.needsUpdate=w,P.lightProbe.needsUpdate=w,P.directionalLights.needsUpdate=w,P.directionalLightShadows.needsUpdate=w,P.pointLights.needsUpdate=w,P.pointLightShadows.needsUpdate=w,P.spotLights.needsUpdate=w,P.spotLightShadows.needsUpdate=w,P.rectAreaLights.needsUpdate=w,P.hemisphereLights.needsUpdate=w),a&&!0===i.fog&&Me.refreshFogUniforms(b,a),Me.refreshMaterialUniforms(b,i,Y,X,R.state.transmissionRenderTarget[e.id]),gr.upload(Ie,Je(g),b,pe));var P,w;i.isShaderMaterial&&!0===i.uniformsNeedUpdate&&(gr.upload(Ie,Je(g),b,pe),i.uniformsNeedUpdate=!1);i.isSpriteMaterial&&A.setValue(Ie,"center",r.center);if(A.setValue(Ie,"modelViewMatrix",r.modelViewMatrix),A.setValue(Ie,"normalMatrix",r.normalMatrix),A.setValue(Ie,"modelMatrix",r.matrixWorld),i.isShaderMaterial||i.isRawShaderMaterial){const e=i.uniformsGroups;for(let t=0,n=e.length;t{function n(){i.forEach((function(e){fe.get(e).currentProgram.isReady()&&i.delete(e)})),0!==i.size?setTimeout(n,10):t(e)}null!==le.get("KHR_parallel_shader_compile")?n():setTimeout(n,10)}))};let ke=null;function We(){Ye.stop()}function Xe(){Ye.start()}const Ye=new Pn;function je(e,t,n,i){if(!1===e.visible)return;if(e.layers.test(t.layers))if(e.isGroup)n=e.renderOrder;else if(e.isLOD)!0===e.autoUpdate&&e.update(t);else if(e.isLight)R.pushLight(e),e.castShadow&&R.pushShadow(e);else if(e.isSprite){if(!e.frustumCulled||Q.intersectsSprite(e)){i&&re.setFromMatrixPosition(e.matrixWorld).applyMatrix4(ne);const t=Se.update(e),r=e.material;r.visible&&x.push(e,t,r,n,re.z,null)}}else if((e.isMesh||e.isLine||e.isPoints)&&(!e.frustumCulled||Q.intersectsObject(e))){const t=Se.update(e),r=e.material;if(i&&(void 0!==e.boundingSphere?(null===e.boundingSphere&&e.computeBoundingSphere(),re.copy(e.boundingSphere.center)):(null===t.boundingSphere&&t.computeBoundingSphere(),re.copy(t.boundingSphere.center)),re.applyMatrix4(e.matrixWorld).applyMatrix4(ne)),Array.isArray(r)){const i=t.groups;for(let a=0,o=i.length;a0&&Ze(r,t,n),a.length>0&&Ze(a,t,n),o.length>0&&Ze(o,t,n),de.buffers.depth.setTest(!0),de.buffers.depth.setMask(!0),de.buffers.color.setMask(!0),de.setPolygonOffset(!1)}function qe(e,t,n,i){if(null!==(!0===n.isScene?n.overrideMaterial:null))return;void 0===R.state.transmissionRenderTarget[i.id]&&(R.state.transmissionRenderTarget[i.id]=new I(1,1,{generateMipmaps:!0,type:le.has("EXT_color_buffer_half_float")||le.has("EXT_color_buffer_float")?S:T,minFilter:ct,samples:4,stencilBuffer:o,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:u.workingColorSpace}));const r=R.state.transmissionRenderTarget[i.id],a=i.viewport||O;r.setSize(a.z*C.transmissionResolutionScale,a.w*C.transmissionResolutionScale);const s=C.getRenderTarget();C.setRenderTarget(r),C.getClearColor(V),z=C.getClearAlpha(),z<1&&C.setClearColor(16777215,.5),C.clear(),oe&&Ce.render(n);const l=C.toneMapping;C.toneMapping=U;const c=i.viewport;if(void 0!==i.viewport&&(i.viewport=void 0),R.setupLightsView(i),!0===J&&Ae.setGlobalState(C.clippingPlanes,i),Ze(e,n,i),pe.updateMultisampleRenderTarget(r),pe.updateRenderTargetMipmap(r),!1===le.has("WEBGL_multisampled_render_to_texture")){let e=!1;for(let r=0,a=t.length;r0)for(let t=0,a=n.length;t0&&qe(i,r,e,t),oe&&Ce.render(e),Ke(x,e,t);null!==D&&(pe.updateMultisampleRenderTarget(D),pe.updateRenderTargetMipmap(D)),!0===e.isScene&&e.onAfterRender(C,e,t),De.resetDefaultState(),y=-1,N=null,b.pop(),b.length>0?(R=b[b.length-1],!0===J&&Ae.setGlobalState(C.clippingPlanes,R.state.camera)):R=null,A.pop(),x=A.length>0?A[A.length-1]:null},this.getActiveCubeFace=function(){return P},this.getActiveMipmapLevel=function(){return w},this.getRenderTarget=function(){return D},this.setRenderTargetTextures=function(e,t,n){fe.get(e.texture).__webglTexture=t,fe.get(e.depthTexture).__webglTexture=n;const i=fe.get(e);i.__hasExternalTextures=!0,i.__autoAllocateDepthBuffer=void 0===n,i.__autoAllocateDepthBuffer||!0===le.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(e,t){const n=fe.get(e);n.__webglFramebuffer=t,n.__useDefaultFramebuffer=void 0===t},this.setRenderTarget=function(e,t=0,n=0){D=e,P=t,w=n;let i=!0,r=null,a=!1,o=!1;if(e){const s=fe.get(e);if(void 0!==s.__useDefaultFramebuffer)de.bindFramebuffer(Ie.FRAMEBUFFER,null),i=!1;else if(void 0===s.__webglFramebuffer)pe.setupRenderTarget(e);else if(s.__hasExternalTextures)pe.rebindTextures(e,fe.get(e.texture).__webglTexture,fe.get(e.depthTexture).__webglTexture);else if(e.depthBuffer){const t=e.depthTexture;if(s.__boundDepthTexture!==t){if(null!==t&&fe.has(t)&&(e.width!==t.image.width||e.height!==t.image.height))throw new Error("WebGLRenderTarget: Attached DepthTexture is initialized to the incorrect size.");pe.setupDepthRenderbuffer(e)}}const l=e.texture;(l.isData3DTexture||l.isDataArrayTexture||l.isCompressedArrayTexture)&&(o=!0);const c=fe.get(e).__webglFramebuffer;e.isWebGLCubeRenderTarget?(r=Array.isArray(c[t])?c[t][n]:c[t],a=!0):r=e.samples>0&&!1===pe.useMultisampledRTT(e)?fe.get(e).__webglMultisampledFramebuffer:Array.isArray(c)?c[n]:c,O.copy(e.viewport),F.copy(e.scissor),G=e.scissorTest}else O.copy(q).multiplyScalar(Y).floor(),F.copy(Z).multiplyScalar(Y).floor(),G=$;if(de.bindFramebuffer(Ie.FRAMEBUFFER,r)&&i&&de.drawBuffers(e,r),de.viewport(O),de.scissor(F),de.setScissorTest(G),a){const i=fe.get(e.texture);Ie.framebufferTexture2D(Ie.FRAMEBUFFER,Ie.COLOR_ATTACHMENT0,Ie.TEXTURE_CUBE_MAP_POSITIVE_X+t,i.__webglTexture,n)}else if(o){const i=fe.get(e.texture),r=t||0;Ie.framebufferTextureLayer(Ie.FRAMEBUFFER,Ie.COLOR_ATTACHMENT0,i.__webglTexture,n||0,r)}y=-1},this.readRenderTargetPixels=function(e,t,n,i,r,a,o){if(!e||!e.isWebGLRenderTarget)return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let s=fe.get(e).__webglFramebuffer;if(e.isWebGLCubeRenderTarget&&void 0!==o&&(s=s[o]),s){de.bindFramebuffer(Ie.FRAMEBUFFER,s);try{const o=e.texture,s=o.format,l=o.type;if(!ce.textureFormatReadable(s))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");if(!ce.textureTypeReadable(l))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");t>=0&&t<=e.width-i&&n>=0&&n<=e.height-r&&Ie.readPixels(t,n,i,r,we.convert(s),we.convert(l),a)}finally{const e=null!==D?fe.get(D).__webglFramebuffer:null;de.bindFramebuffer(Ie.FRAMEBUFFER,e)}}},this.readRenderTargetPixelsAsync=async function(e,t,n,i,r,a,o){if(!e||!e.isWebGLRenderTarget)throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let s=fe.get(e).__webglFramebuffer;if(e.isWebGLCubeRenderTarget&&void 0!==o&&(s=s[o]),s){const o=e.texture,l=o.format,c=o.type;if(!ce.textureFormatReadable(l))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!ce.textureTypeReadable(c))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");if(t>=0&&t<=e.width-i&&n>=0&&n<=e.height-r){de.bindFramebuffer(Ie.FRAMEBUFFER,s);const e=Ie.createBuffer();Ie.bindBuffer(Ie.PIXEL_PACK_BUFFER,e),Ie.bufferData(Ie.PIXEL_PACK_BUFFER,a.byteLength,Ie.STREAM_READ),Ie.readPixels(t,n,i,r,we.convert(l),we.convert(c),0);const o=null!==D?fe.get(D).__webglFramebuffer:null;de.bindFramebuffer(Ie.FRAMEBUFFER,o);const d=Ie.fenceSync(Ie.SYNC_GPU_COMMANDS_COMPLETE,0);return Ie.flush(),await Cn(Ie,d,4),Ie.bindBuffer(Ie.PIXEL_PACK_BUFFER,e),Ie.getBufferSubData(Ie.PIXEL_PACK_BUFFER,0,a),Ie.deleteBuffer(e),Ie.deleteSync(d),a}throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")}},this.copyFramebufferToTexture=function(e,t=null,n=0){!0!==e.isTexture&&(H("WebGLRenderer: copyFramebufferToTexture function signature has changed."),t=arguments[0]||null,e=arguments[1]);const i=Math.pow(2,-n),r=Math.floor(e.image.width*i),a=Math.floor(e.image.height*i),o=null!==t?t.x:0,s=null!==t?t.y:0;pe.setTexture2D(e,0),Ie.copyTexSubImage2D(Ie.TEXTURE_2D,n,0,0,o,s,r,a),de.unbindTexture()};const tt=Ie.createFramebuffer(),nt=Ie.createFramebuffer();this.copyTextureToTexture=function(e,t,n=null,i=null,r=0,a=null){let o,s,l,c,d,u,f,p,m;!0!==e.isTexture&&(H("WebGLRenderer: copyTextureToTexture function signature has changed."),i=arguments[0]||null,e=arguments[1],t=arguments[2],a=arguments[3]||0,n=null),null===a&&(0!==r?(H("WebGLRenderer: copyTextureToTexture function signature has changed to support src and dst mipmap levels."),a=r,r=0):a=0);const h=e.isCompressedTexture?e.mipmaps[a]:e.image;if(null!==n)o=n.max.x-n.min.x,s=n.max.y-n.min.y,l=n.isBox3?n.max.z-n.min.z:1,c=n.min.x,d=n.min.y,u=n.isBox3?n.min.z:0;else{const t=Math.pow(2,-r);o=Math.floor(h.width*t),s=Math.floor(h.height*t),l=e.isDataArrayTexture?h.depth:e.isData3DTexture?Math.floor(h.depth*t):1,c=0,d=0,u=0}null!==i?(f=i.x,p=i.y,m=i.z):(f=0,p=0,m=0);const _=we.convert(t.format),g=we.convert(t.type);let v;t.isData3DTexture?(pe.setTexture3D(t,0),v=Ie.TEXTURE_3D):t.isDataArrayTexture||t.isCompressedArrayTexture?(pe.setTexture2DArray(t,0),v=Ie.TEXTURE_2D_ARRAY):(pe.setTexture2D(t,0),v=Ie.TEXTURE_2D),Ie.pixelStorei(Ie.UNPACK_FLIP_Y_WEBGL,t.flipY),Ie.pixelStorei(Ie.UNPACK_PREMULTIPLY_ALPHA_WEBGL,t.premultiplyAlpha),Ie.pixelStorei(Ie.UNPACK_ALIGNMENT,t.unpackAlignment);const E=Ie.getParameter(Ie.UNPACK_ROW_LENGTH),S=Ie.getParameter(Ie.UNPACK_IMAGE_HEIGHT),T=Ie.getParameter(Ie.UNPACK_SKIP_PIXELS),M=Ie.getParameter(Ie.UNPACK_SKIP_ROWS),x=Ie.getParameter(Ie.UNPACK_SKIP_IMAGES);Ie.pixelStorei(Ie.UNPACK_ROW_LENGTH,h.width),Ie.pixelStorei(Ie.UNPACK_IMAGE_HEIGHT,h.height),Ie.pixelStorei(Ie.UNPACK_SKIP_PIXELS,c),Ie.pixelStorei(Ie.UNPACK_SKIP_ROWS,d),Ie.pixelStorei(Ie.UNPACK_SKIP_IMAGES,u);const R=e.isDataArrayTexture||e.isData3DTexture,A=t.isDataArrayTexture||t.isData3DTexture;if(e.isDepthTexture){const n=fe.get(e),i=fe.get(t),h=fe.get(n.__renderTarget),_=fe.get(i.__renderTarget);de.bindFramebuffer(Ie.READ_FRAMEBUFFER,h.__webglFramebuffer),de.bindFramebuffer(Ie.DRAW_FRAMEBUFFER,_.__webglFramebuffer);for(let n=0;ne.start-t.start));let t=0;for(let e=1;e 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\t#ifdef DECODE_VIDEO_TEXTURE_EMISSIVE\n\t\temissiveColor = sRGBTransferEOTF( emissiveColor );\n\t#endif\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:"vec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferEOTF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\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 = sRGBTransferEOTF( sampledDiffuseColor );\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\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\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#else\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#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}"},Dn={common:{diffuse:{value:new e(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new t},alphaMap:{value:null},alphaMapTransform:{value:new t},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new t}},envmap:{envMap:{value:null},envMapRotation:{value:new t},flipEnvMap:{value:-1},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new t}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new t}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new t},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new t},normalScale:{value:new n(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new t},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new t}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new t}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new t}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new e(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 e(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new t},alphaTest:{value:0},uvTransform:{value:new t}},sprite:{diffuse:{value:new e(16777215)},opacity:{value:1},center:{value:new n(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new t},alphaMap:{value:null},alphaMapTransform:{value:new t},alphaTest:{value:0}}},yn={basic:{uniforms:i([Dn.common,Dn.specularmap,Dn.envmap,Dn.aomap,Dn.lightmap,Dn.fog]),vertexShader:wn.meshbasic_vert,fragmentShader:wn.meshbasic_frag},lambert:{uniforms:i([Dn.common,Dn.specularmap,Dn.envmap,Dn.aomap,Dn.lightmap,Dn.emissivemap,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.fog,Dn.lights,{emissive:{value:new e(0)}}]),vertexShader:wn.meshlambert_vert,fragmentShader:wn.meshlambert_frag},phong:{uniforms:i([Dn.common,Dn.specularmap,Dn.envmap,Dn.aomap,Dn.lightmap,Dn.emissivemap,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.fog,Dn.lights,{emissive:{value:new e(0)},specular:{value:new e(1118481)},shininess:{value:30}}]),vertexShader:wn.meshphong_vert,fragmentShader:wn.meshphong_frag},standard:{uniforms:i([Dn.common,Dn.envmap,Dn.aomap,Dn.lightmap,Dn.emissivemap,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.roughnessmap,Dn.metalnessmap,Dn.fog,Dn.lights,{emissive:{value:new e(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:wn.meshphysical_vert,fragmentShader:wn.meshphysical_frag},toon:{uniforms:i([Dn.common,Dn.aomap,Dn.lightmap,Dn.emissivemap,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.gradientmap,Dn.fog,Dn.lights,{emissive:{value:new e(0)}}]),vertexShader:wn.meshtoon_vert,fragmentShader:wn.meshtoon_frag},matcap:{uniforms:i([Dn.common,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,Dn.fog,{matcap:{value:null}}]),vertexShader:wn.meshmatcap_vert,fragmentShader:wn.meshmatcap_frag},points:{uniforms:i([Dn.points,Dn.fog]),vertexShader:wn.points_vert,fragmentShader:wn.points_frag},dashed:{uniforms:i([Dn.common,Dn.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:wn.linedashed_vert,fragmentShader:wn.linedashed_frag},depth:{uniforms:i([Dn.common,Dn.displacementmap]),vertexShader:wn.depth_vert,fragmentShader:wn.depth_frag},normal:{uniforms:i([Dn.common,Dn.bumpmap,Dn.normalmap,Dn.displacementmap,{opacity:{value:1}}]),vertexShader:wn.meshnormal_vert,fragmentShader:wn.meshnormal_frag},sprite:{uniforms:i([Dn.sprite,Dn.fog]),vertexShader:wn.sprite_vert,fragmentShader:wn.sprite_frag},background:{uniforms:{uvTransform:{value:new t},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:wn.background_vert,fragmentShader:wn.background_frag},backgroundCube:{uniforms:{envMap:{value:null},flipEnvMap:{value:-1},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new t}},vertexShader:wn.backgroundCube_vert,fragmentShader:wn.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:wn.cube_vert,fragmentShader:wn.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:wn.equirect_vert,fragmentShader:wn.equirect_frag},distanceRGBA:{uniforms:i([Dn.common,Dn.displacementmap,{referencePosition:{value:new r},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:wn.distanceRGBA_vert,fragmentShader:wn.distanceRGBA_frag},shadow:{uniforms:i([Dn.lights,Dn.fog,{color:{value:new e(0)},opacity:{value:1}}]),vertexShader:wn.shadow_vert,fragmentShader:wn.shadow_frag}};yn.physical={uniforms:i([yn.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new t},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new t},clearcoatNormalScale:{value:new n(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new t},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new t},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new t},sheen:{value:0},sheenColor:{value:new e(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new t},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new t},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new t},transmissionSamplerSize:{value:new n},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new t},attenuationDistance:{value:0},attenuationColor:{value:new e(0)},specularColor:{value:new e(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new t},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new t},anisotropyVector:{value:new n},anisotropyMap:{value:null},anisotropyMapTransform:{value:new t}}]),vertexShader:wn.meshphysical_vert,fragmentShader:wn.meshphysical_frag};const In={r:0,b:0,g:0},Nn=new _,On=new g;function Fn(t,n,i,r,_,g,v){const E=new e(0);let S,T,M=!0===g?0:1,x=null,R=0,A=null;function b(e){let t=!0===e.isScene?e.background:null;if(t&&t.isTexture){t=(e.backgroundBlurriness>0?i:n).get(t)}return t}function C(e,n){e.getRGB(In,h(t)),r.buffers.color.setClear(In.r,In.g,In.b,n,v)}return{getClearColor:function(){return E},setClearColor:function(e,t=1){E.set(e),M=t,C(E,M)},getClearAlpha:function(){return M},setClearAlpha:function(e){M=e,C(E,M)},render:function(e){let n=!1;const i=b(e);null===i?C(E,M):i&&i.isColor&&(C(i,1),n=!0);const a=t.xr.getEnvironmentBlendMode();"additive"===a?r.buffers.color.setClear(0,0,0,1,v):"alpha-blend"===a&&r.buffers.color.setClear(0,0,0,0,v),(t.autoClear||n)&&(r.buffers.depth.setTest(!0),r.buffers.depth.setMask(!0),r.buffers.color.setMask(!0),t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil))},addToRenderList:function(e,n){const i=b(n);i&&(i.isCubeTexture||i.mapping===a)?(void 0===T&&(T=new o(new s(1,1,1),new l({name:"BackgroundCubeMaterial",uniforms:c(yn.backgroundCube.uniforms),vertexShader:yn.backgroundCube.vertexShader,fragmentShader:yn.backgroundCube.fragmentShader,side:d,depthTest:!1,depthWrite:!1,fog:!1})),T.geometry.deleteAttribute("normal"),T.geometry.deleteAttribute("uv"),T.onBeforeRender=function(e,t,n){this.matrixWorld.copyPosition(n.matrixWorld)},Object.defineProperty(T.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),_.update(T)),Nn.copy(n.backgroundRotation),Nn.x*=-1,Nn.y*=-1,Nn.z*=-1,i.isCubeTexture&&!1===i.isRenderTargetTexture&&(Nn.y*=-1,Nn.z*=-1),T.material.uniforms.envMap.value=i,T.material.uniforms.flipEnvMap.value=i.isCubeTexture&&!1===i.isRenderTargetTexture?-1:1,T.material.uniforms.backgroundBlurriness.value=n.backgroundBlurriness,T.material.uniforms.backgroundIntensity.value=n.backgroundIntensity,T.material.uniforms.backgroundRotation.value.setFromMatrix4(On.makeRotationFromEuler(Nn)),T.material.toneMapped=u.getTransfer(i.colorSpace)!==f,x===i&&R===i.version&&A===t.toneMapping||(T.material.needsUpdate=!0,x=i,R=i.version,A=t.toneMapping),T.layers.enableAll(),e.unshift(T,T.geometry,T.material,0,0,null)):i&&i.isTexture&&(void 0===S&&(S=new o(new p(2,2),new l({name:"BackgroundMaterial",uniforms:c(yn.background.uniforms),vertexShader:yn.background.vertexShader,fragmentShader:yn.background.fragmentShader,side:m,depthTest:!1,depthWrite:!1,fog:!1})),S.geometry.deleteAttribute("normal"),Object.defineProperty(S.material,"map",{get:function(){return this.uniforms.t2D.value}}),_.update(S)),S.material.uniforms.t2D.value=i,S.material.uniforms.backgroundIntensity.value=n.backgroundIntensity,S.material.toneMapped=u.getTransfer(i.colorSpace)!==f,!0===i.matrixAutoUpdate&&i.updateMatrix(),S.material.uniforms.uvTransform.value.copy(i.matrix),x===i&&R===i.version&&A===t.toneMapping||(S.material.needsUpdate=!0,x=i,R=i.version,A=t.toneMapping),S.layers.enableAll(),e.unshift(S,S.geometry,S.material,0,0,null))},dispose:function(){void 0!==T&&(T.geometry.dispose(),T.material.dispose(),T=void 0),void 0!==S&&(S.geometry.dispose(),S.material.dispose(),S=void 0)}}}function Bn(e,t){const n=e.getParameter(e.MAX_VERTEX_ATTRIBS),i={},r=c(null);let a=r,o=!1;function s(t){return e.bindVertexArray(t)}function l(t){return e.deleteVertexArray(t)}function c(e){const t=[],i=[],r=[];for(let e=0;e=0){const n=r[t];let i=o[t];if(void 0===i&&("instanceMatrix"===t&&e.instanceMatrix&&(i=e.instanceMatrix),"instanceColor"===t&&e.instanceColor&&(i=e.instanceColor)),void 0===n)return!0;if(n.attribute!==i)return!0;if(i&&n.data!==i.data)return!0;s++}}return a.attributesNum!==s||a.index!==i}(n,h,l,_),g&&function(e,t,n,i){const r={},o=t.attributes;let s=0;const l=n.getAttributes();for(const t in l){if(l[t].location>=0){let n=o[t];void 0===n&&("instanceMatrix"===t&&e.instanceMatrix&&(n=e.instanceMatrix),"instanceColor"===t&&e.instanceColor&&(n=e.instanceColor));const i={};i.attribute=n,n&&n.data&&(i.data=n.data),r[t]=i,s++}}a.attributes=r,a.attributesNum=s,a.index=i}(n,h,l,_),null!==_&&t.update(_,e.ELEMENT_ARRAY_BUFFER),(g||o)&&(o=!1,function(n,i,r,a){d();const o=a.attributes,s=r.getAttributes(),l=i.defaultAttributeValues;for(const i in s){const r=s[i];if(r.location>=0){let s=o[i];if(void 0===s&&("instanceMatrix"===i&&n.instanceMatrix&&(s=n.instanceMatrix),"instanceColor"===i&&n.instanceColor&&(s=n.instanceColor)),void 0!==s){const i=s.normalized,o=s.itemSize,l=t.get(s);if(void 0===l)continue;const c=l.buffer,d=l.type,p=l.bytesPerElement,h=d===e.INT||d===e.UNSIGNED_INT||s.gpuType===v;if(s.isInterleavedBufferAttribute){const t=s.data,l=t.stride,_=s.offset;if(t.isInstancedInterleavedBuffer){for(let e=0;e0&&e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT).precision>0)return"highp";t="mediump"}return"mediump"===t&&e.getShaderPrecisionFormat(e.VERTEX_SHADER,e.MEDIUM_FLOAT).precision>0&&e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let o=void 0!==n.precision?n.precision:"highp";const s=a(o);s!==o&&(console.warn("THREE.WebGLRenderer:",o,"not supported, using",s,"instead."),o=s);const l=!0===n.logarithmicDepthBuffer,c=!0===n.reverseDepthBuffer&&t.has("EXT_clip_control"),d=e.getParameter(e.MAX_TEXTURE_IMAGE_UNITS),u=e.getParameter(e.MAX_VERTEX_TEXTURE_IMAGE_UNITS);return{isWebGL2:!0,getMaxAnisotropy:function(){if(void 0!==r)return r;if(!0===t.has("EXT_texture_filter_anisotropic")){const n=t.get("EXT_texture_filter_anisotropic");r=e.getParameter(n.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else r=0;return r},getMaxPrecision:a,textureFormatReadable:function(t){return t===E||i.convert(t)===e.getParameter(e.IMPLEMENTATION_COLOR_READ_FORMAT)},textureTypeReadable:function(n){const r=n===S&&(t.has("EXT_color_buffer_half_float")||t.has("EXT_color_buffer_float"));return!(n!==T&&i.convert(n)!==e.getParameter(e.IMPLEMENTATION_COLOR_READ_TYPE)&&n!==M&&!r)},precision:o,logarithmicDepthBuffer:l,reverseDepthBuffer:c,maxTextures:d,maxVertexTextures:u,maxTextureSize:e.getParameter(e.MAX_TEXTURE_SIZE),maxCubemapSize:e.getParameter(e.MAX_CUBE_MAP_TEXTURE_SIZE),maxAttributes:e.getParameter(e.MAX_VERTEX_ATTRIBS),maxVertexUniforms:e.getParameter(e.MAX_VERTEX_UNIFORM_VECTORS),maxVaryings:e.getParameter(e.MAX_VARYING_VECTORS),maxFragmentUniforms:e.getParameter(e.MAX_FRAGMENT_UNIFORM_VECTORS),vertexTextures:u>0,maxSamples:e.getParameter(e.MAX_SAMPLES)}}function Vn(e){const n=this;let i=null,r=0,a=!1,o=!1;const s=new x,l=new t,c={value:null,needsUpdate:!1};function d(e,t,i,r){const a=null!==e?e.length:0;let o=null;if(0!==a){if(o=c.value,!0!==r||null===o){const n=i+4*a,r=t.matrixWorldInverse;l.getNormalMatrix(r),(null===o||o.length0);n.numPlanes=r,n.numIntersection=0}();else{const e=o?0:r,t=4*e;let n=m.clippingState||null;c.value=n,n=d(u,s,t,l);for(let e=0;e!==t;++e)n[e]=i[e];m.clippingState=n,this.numIntersection=f?this.numPlanes:0,this.numPlanes+=e}}}function zn(e){let t=new WeakMap;function n(e,t){return t===R?e.mapping=C:t===A&&(e.mapping=L),e}function i(e){const n=e.target;n.removeEventListener("dispose",i);const r=t.get(n);void 0!==r&&(t.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const a=r.mapping;if(a===R||a===A){if(t.has(r)){return n(t.get(r).texture,r.mapping)}{const a=r.image;if(a&&a.height>0){const o=new b(a.height);return o.fromEquirectangularTexture(e,r),t.set(r,o),r.addEventListener("dispose",i),n(o.texture,r.mapping)}return null}}}return r},dispose:function(){t=new WeakMap}}}const kn=[.125,.215,.35,.446,.526,.582],Wn=20,Xn=new O,Yn=new e;let jn=null,Kn=0,qn=0,Zn=!1;const $n=(1+Math.sqrt(5))/2,Qn=1/$n,Jn=[new r(-$n,Qn,0),new r($n,Qn,0),new r(-Qn,0,$n),new r(Qn,0,$n),new r(0,$n,-Qn),new r(0,$n,Qn),new r(-1,1,-1),new r(1,1,-1),new r(-1,1,1),new r(1,1,1)];class ei{constructor(e){this._renderer=e,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(e,t=0,n=.1,i=100){jn=this._renderer.getRenderTarget(),Kn=this._renderer.getActiveCubeFace(),qn=this._renderer.getActiveMipmapLevel(),Zn=this._renderer.xr.enabled,this._renderer.xr.enabled=!1,this._setSize(256);const r=this._allocateTargets();return r.depthBuffer=!0,this._sceneToCubeUV(e,n,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=ri(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=ii(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),null!==this._cubemapMaterial&&this._cubemapMaterial.dispose(),null!==this._equirectMaterial&&this._equirectMaterial.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?s=kn[o-e+4-1]:0===o&&(s=0),i.push(s);const l=1/(a-2),c=-l,d=1+l,u=[c,c,d,c,d,d,c,c,d,d,c,d],f=6,p=6,m=3,h=2,_=1,g=new Float32Array(m*p*f),v=new Float32Array(h*p*f),E=new Float32Array(_*p*f);for(let e=0;e2?0:-1,i=[t,n,0,t+2/3,n,0,t+2/3,n+1,0,t,n,0,t+2/3,n+1,0,t,n+1,0];g.set(i,m*p*e),v.set(u,h*p*e);const r=[e,e,e,e,e,e];E.set(r,_*p*e)}const S=new D;S.setAttribute("position",new y(g,m)),S.setAttribute("uv",new y(v,h)),S.setAttribute("faceIndex",new y(E,_)),t.push(S),r>4&&r--}return{lodPlanes:t,sizeLods:n,sigmas:i}}(i)),this._blurMaterial=function(e,t,n){const i=new Float32Array(Wn),a=new r(0,1,0),o=new l({name:"SphericalGaussianBlur",defines:{n:Wn,CUBEUV_TEXEL_WIDTH:1/t,CUBEUV_TEXEL_HEIGHT:1/n,CUBEUV_MAX_MIP:`${e}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:i},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:a}},vertexShader:ai(),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:N,depthTest:!1,depthWrite:!1});return o}(i,e,t)}return i}_compileMaterial(e){const t=new o(this._lodPlanes[0],e);this._renderer.compile(t,Xn)}_sceneToCubeUV(e,t,n,i){const r=new P(90,1,t,n),a=[1,-1,1,1,1,1],l=[1,1,1,-1,-1,-1],c=this._renderer,u=c.autoClear,f=c.toneMapping;c.getClearColor(Yn),c.toneMapping=U,c.autoClear=!1;const p=new w({name:"PMREM.Background",side:d,depthWrite:!1,depthTest:!1}),m=new o(new s,p);let h=!1;const _=e.background;_?_.isColor&&(p.color.copy(_),e.background=null,h=!0):(p.color.copy(Yn),h=!0);for(let t=0;t<6;t++){const n=t%3;0===n?(r.up.set(0,a[t],0),r.lookAt(l[t],0,0)):1===n?(r.up.set(0,0,a[t]),r.lookAt(0,l[t],0)):(r.up.set(0,a[t],0),r.lookAt(0,0,l[t]));const o=this._cubeSize;ni(i,n*o,t>2?o:0,o,o),c.setRenderTarget(i),h&&c.render(m,r),c.render(e,r)}m.geometry.dispose(),m.material.dispose(),c.toneMapping=f,c.autoClear=u,e.background=_}_textureToCubeUV(e,t){const n=this._renderer,i=e.mapping===C||e.mapping===L;i?(null===this._cubemapMaterial&&(this._cubemapMaterial=ri()),this._cubemapMaterial.uniforms.flipEnvMap.value=!1===e.isRenderTargetTexture?-1:1):null===this._equirectMaterial&&(this._equirectMaterial=ii());const r=i?this._cubemapMaterial:this._equirectMaterial,a=new o(this._lodPlanes[0],r);r.uniforms.envMap.value=e;const s=this._cubeSize;ni(t,0,0,3*s,2*s),n.setRenderTarget(t),n.render(a,Xn)}_applyPMREM(e){const t=this._renderer,n=t.autoClear;t.autoClear=!1;const i=this._lodPlanes.length;for(let t=1;tWn&&console.warn(`sigmaRadians, ${r}, is too large and will clip, as it requested ${h} samples when the maximum is set to 20`);const _=[];let g=0;for(let e=0;ev-4?i-v+4:0),4*(this._cubeSize-E),3*E,2*E),l.setRenderTarget(t),l.render(d,Xn)}}function ti(e,t,n){const i=new I(e,t,n);return i.texture.mapping=a,i.texture.name="PMREM.cubeUv",i.scissorTest=!0,i}function ni(e,t,n,i,r){e.viewport.set(t,n,i,r),e.scissor.set(t,n,i,r)}function ii(){return new l({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:ai(),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:N,depthTest:!1,depthWrite:!1})}function ri(){return new l({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:ai(),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:N,depthTest:!1,depthWrite:!1})}function ai(){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 oi(e){let t=new WeakMap,n=null;function i(e){const n=e.target;n.removeEventListener("dispose",i);const r=t.get(n);void 0!==r&&(t.delete(n),r.dispose())}return{get:function(r){if(r&&r.isTexture){const a=r.mapping,o=a===R||a===A,s=a===C||a===L;if(o||s){let a=t.get(r);const l=void 0!==a?a.texture.pmremVersion:0;if(r.isRenderTargetTexture&&r.pmremVersion!==l)return null===n&&(n=new ei(e)),a=o?n.fromEquirectangular(r,a):n.fromCubemap(r,a),a.texture.pmremVersion=r.pmremVersion,t.set(r,a),a.texture;if(void 0!==a)return a.texture;{const l=r.image;return o&&l&&l.height>0||s&&l&&function(e){let t=0;const n=6;for(let i=0;it.maxTextureSize&&(T=Math.ceil(S/t.maxTextureSize),S=t.maxTextureSize);const x=new Float32Array(S*T*4*u),R=new W(x,S,T,u);R.type=M,R.needsUpdate=!0;const A=4*E;for(let C=0;C0)return e;const r=t*n;let a=vi[r];if(void 0===a&&(a=new Float32Array(r),vi[r]=a),0!==t){i.toArray(a,0);for(let i=1,r=0;i!==t;++i)r+=n,e[i].toArray(a,r)}return a}function Ri(e,t){if(e.length!==t.length)return!1;for(let n=0,i=e.length;n":" "} ${r}: ${n[e]}`)}return i.join("\n")}(e.getShaderSource(t),i)}return r}function Mr(e,t){const n=function(e){u._getMatrix(Sr,u.workingColorSpace,e);const t=`mat3( ${Sr.elements.map((e=>e.toFixed(4)))} )`;switch(u.getTransfer(e)){case se:return[t,"LinearTransferOETF"];case f:return[t,"sRGBTransferOETF"];default:return console.warn("THREE.WebGLProgram: Unsupported color space: ",e),[t,"LinearTransferOETF"]}}(t);return[`vec4 ${e}( vec4 value ) {`,`\treturn ${n[1]}( vec4( value.rgb * ${n[0]}, value.a ) );`,"}"].join("\n")}function xr(e,t){let n;switch(t){case ie:n="Linear";break;case ne:n="Reinhard";break;case te:n="Cineon";break;case ee:n="ACESFilmic";break;case J:n="AgX";break;case Q:n="Neutral";break;case $:n="Custom";break;default:console.warn("THREE.WebGLProgram: Unsupported toneMapping:",t),n="Linear"}return"vec3 "+e+"( vec3 color ) { return "+n+"ToneMapping( color ); }"}const Rr=new r;function Ar(){u.getLuminanceCoefficients(Rr);return["float luminance( const in vec3 rgb ) {",`\tconst vec3 weights = vec3( ${Rr.x.toFixed(4)}, ${Rr.y.toFixed(4)}, ${Rr.z.toFixed(4)} );`,"\treturn dot( weights, rgb );","}"].join("\n")}function br(e){return""!==e}function Cr(e,t){const n=t.numSpotLightShadows+t.numSpotLightMaps-t.numSpotLightShadowsWithMaps;return e.replace(/NUM_DIR_LIGHTS/g,t.numDirLights).replace(/NUM_SPOT_LIGHTS/g,t.numSpotLights).replace(/NUM_SPOT_LIGHT_MAPS/g,t.numSpotLightMaps).replace(/NUM_SPOT_LIGHT_COORDS/g,n).replace(/NUM_RECT_AREA_LIGHTS/g,t.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g,t.numPointLights).replace(/NUM_HEMI_LIGHTS/g,t.numHemiLights).replace(/NUM_DIR_LIGHT_SHADOWS/g,t.numDirLightShadows).replace(/NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g,t.numSpotLightShadowsWithMaps).replace(/NUM_SPOT_LIGHT_SHADOWS/g,t.numSpotLightShadows).replace(/NUM_POINT_LIGHT_SHADOWS/g,t.numPointLightShadows)}function Lr(e,t){return e.replace(/NUM_CLIPPING_PLANES/g,t.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g,t.numClippingPlanes-t.numClipIntersection)}const Pr=/^[ \t]*#include +<([\w\d./]+)>/gm;function Ur(e){return e.replace(Pr,Dr)}const wr=new Map;function Dr(e,t){let n=wn[t];if(void 0===n){const e=wr.get(t);if(void 0===e)throw new Error("Can not resolve #include <"+t+">");n=wn[e],console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',t,e)}return Ur(n)}const yr=/#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 Ir(e){return e.replace(yr,Nr)}function Nr(e,t,n,i){let r="";for(let e=parseInt(t);e0&&(g+="\n"),v=["#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,h].filter(br).join("\n"),v.length>0&&(v+="\n")):(g=[Or(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,h,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 "+u:"",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 "+c:"",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(br).join("\n"),v=[Or(n),"#define SHADER_TYPE "+n.shaderType,"#define SHADER_NAME "+n.shaderName,h,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 "+u:"",n.envMap?"#define "+f:"",p?"#define CUBEUV_TEXEL_WIDTH "+p.texelWidth:"",p?"#define CUBEUV_TEXEL_HEIGHT "+p.texelHeight:"",p?"#define CUBEUV_MAX_MIP "+p.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 "+c:"",n.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",n.numLightProbes>0?"#define USE_LIGHT_PROBES":"",n.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",n.decodeVideoTextureEmissive?"#define DECODE_VIDEO_TEXTURE_EMISSIVE":"",n.logarithmicDepthBuffer?"#define USE_LOGDEPTHBUF":"",n.reverseDepthBuffer?"#define USE_REVERSEDEPTHBUF":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",n.toneMapping!==U?"#define TONE_MAPPING":"",n.toneMapping!==U?wn.tonemapping_pars_fragment:"",n.toneMapping!==U?xr("toneMapping",n.toneMapping):"",n.dithering?"#define DITHERING":"",n.opaque?"#define OPAQUE":"",wn.colorspace_pars_fragment,Mr("linearToOutputTexel",n.outputColorSpace),Ar(),n.useDepthPacking?"#define DEPTH_PACKING "+n.depthPacking:"","\n"].filter(br).join("\n")),s=Ur(s),s=Cr(s,n),s=Lr(s,n),l=Ur(l),l=Cr(l,n),l=Lr(l,n),s=Ir(s),l=Ir(l),!0!==n.isRawShaderMaterial&&(E="#version 300 es\n",g=[m,"#define attribute in","#define varying out","#define texture2D texture"].join("\n")+"\n"+g,v=["#define varying in",n.glslVersion===Z?"":"layout(location = 0) out highp vec4 pc_fragColor;",n.glslVersion===Z?"":"#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"+v);const S=E+g+s,T=E+v+l,M=vr(r,r.VERTEX_SHADER,S),x=vr(r,r.FRAGMENT_SHADER,T);function R(t){if(e.debug.checkShaderErrors){const n=r.getProgramInfoLog(_).trim(),i=r.getShaderInfoLog(M).trim(),a=r.getShaderInfoLog(x).trim();let o=!0,s=!0;if(!1===r.getProgramParameter(_,r.LINK_STATUS))if(o=!1,"function"==typeof e.debug.onShaderError)e.debug.onShaderError(r,_,M,x);else{const e=Tr(r,M,"vertex"),i=Tr(r,x,"fragment");console.error("THREE.WebGLProgram: Shader Error "+r.getError()+" - VALIDATE_STATUS "+r.getProgramParameter(_,r.VALIDATE_STATUS)+"\n\nMaterial Name: "+t.name+"\nMaterial Type: "+t.type+"\n\nProgram Info Log: "+n+"\n"+e+"\n"+i)}else""!==n?console.warn("THREE.WebGLProgram: Program Info Log:",n):""!==i&&""!==a||(s=!1);s&&(t.diagnostics={runnable:o,programLog:n,vertexShader:{log:i,prefix:g},fragmentShader:{log:a,prefix:v}})}r.deleteShader(M),r.deleteShader(x),A=new gr(r,_),b=function(e,t){const n={},i=e.getProgramParameter(t,e.ACTIVE_ATTRIBUTES);for(let r=0;r0,J=o.clearcoat>0,ee=o.dispersion>0,te=o.iridescence>0,ne=o.sheen>0,ie=o.transmission>0,re=Q&&!!o.anisotropyMap,ae=J&&!!o.clearcoatMap,oe=J&&!!o.clearcoatNormalMap,se=J&&!!o.clearcoatRoughnessMap,le=te&&!!o.iridescenceMap,ce=te&&!!o.iridescenceThicknessMap,de=ne&&!!o.sheenColorMap,he=ne&&!!o.sheenRoughnessMap,_e=!!o.specularMap,ge=!!o.specularColorMap,ve=!!o.specularIntensityMap,Ee=ie&&!!o.transmissionMap,Se=ie&&!!o.thicknessMap,Te=!!o.gradientMap,Me=!!o.alphaMap,xe=o.alphaTest>0,Re=!!o.alphaHash,Ae=!!o.extensions;let be=U;o.toneMapped&&(null!==O&&!0!==O.isXRRenderTarget||(be=e.toneMapping));const Ce={shaderID:C,shaderType:o.type,shaderName:o.name,vertexShader:w,fragmentShader:D,defines:o.defines,customVertexShaderID:y,customFragmentShaderID:I,isRawShaderMaterial:!0===o.isRawShaderMaterial,glslVersion:o.glslVersion,precision:g,batching:G,batchingColor:G&&null!==T._colorsTexture,instancing:H,instancingColor:H&&null!==T.instanceColor,instancingMorph:H&&null!==T.morphTexture,supportsVertexTextures:_,outputColorSpace:null===O?e.outputColorSpace:!0===O.isXRRenderTarget?O.texture.colorSpace:B,alphaToCoverage:!!o.alphaToCoverage,map:V,matcap:z,envMap:k,envMapMode:k&&A.mapping,envMapCubeUVHeight:b,aoMap:W,lightMap:X,bumpMap:Y,normalMap:j,displacementMap:_&&K,emissiveMap:q,normalMapObjectSpace:j&&o.normalMapType===ue,normalMapTangentSpace:j&&o.normalMapType===fe,metalnessMap:Z,roughnessMap:$,anisotropy:Q,anisotropyMap:re,clearcoat:J,clearcoatMap:ae,clearcoatNormalMap:oe,clearcoatRoughnessMap:se,dispersion:ee,iridescence:te,iridescenceMap:le,iridescenceThicknessMap:ce,sheen:ne,sheenColorMap:de,sheenRoughnessMap:he,specularMap:_e,specularColorMap:ge,specularIntensityMap:ve,transmission:ie,transmissionMap:Ee,thicknessMap:Se,gradientMap:Te,opaque:!1===o.transparent&&o.blending===pe&&!1===o.alphaToCoverage,alphaMap:Me,alphaTest:xe,alphaHash:Re,combine:o.combine,mapUv:V&&E(o.map.channel),aoMapUv:W&&E(o.aoMap.channel),lightMapUv:X&&E(o.lightMap.channel),bumpMapUv:Y&&E(o.bumpMap.channel),normalMapUv:j&&E(o.normalMap.channel),displacementMapUv:K&&E(o.displacementMap.channel),emissiveMapUv:q&&E(o.emissiveMap.channel),metalnessMapUv:Z&&E(o.metalnessMap.channel),roughnessMapUv:$&&E(o.roughnessMap.channel),anisotropyMapUv:re&&E(o.anisotropyMap.channel),clearcoatMapUv:ae&&E(o.clearcoatMap.channel),clearcoatNormalMapUv:oe&&E(o.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:se&&E(o.clearcoatRoughnessMap.channel),iridescenceMapUv:le&&E(o.iridescenceMap.channel),iridescenceThicknessMapUv:ce&&E(o.iridescenceThicknessMap.channel),sheenColorMapUv:de&&E(o.sheenColorMap.channel),sheenRoughnessMapUv:he&&E(o.sheenRoughnessMap.channel),specularMapUv:_e&&E(o.specularMap.channel),specularColorMapUv:ge&&E(o.specularColorMap.channel),specularIntensityMapUv:ve&&E(o.specularIntensityMap.channel),transmissionMapUv:Ee&&E(o.transmissionMap.channel),thicknessMapUv:Se&&E(o.thicknessMap.channel),alphaMapUv:Me&&E(o.alphaMap.channel),vertexTangents:!!x.attributes.tangent&&(j||Q),vertexColors:o.vertexColors,vertexAlphas:!0===o.vertexColors&&!!x.attributes.color&&4===x.attributes.color.itemSize,pointsUvs:!0===T.isPoints&&!!x.attributes.uv&&(V||Me),fog:!!M,useFog:!0===o.fog,fogExp2:!!M&&M.isFogExp2,flatShading:!0===o.flatShading,sizeAttenuation:!0===o.sizeAttenuation,logarithmicDepthBuffer:h,reverseDepthBuffer:F,skinning:!0===T.isSkinnedMesh,morphTargets:void 0!==x.morphAttributes.position,morphNormals:void 0!==x.morphAttributes.normal,morphColors:void 0!==x.morphAttributes.color,morphTargetsCount:P,morphTextureStride:N,numDirLights:l.directional.length,numPointLights:l.point.length,numSpotLights:l.spot.length,numSpotLightMaps:l.spotLightMap.length,numRectAreaLights:l.rectArea.length,numHemiLights:l.hemi.length,numDirLightShadows:l.directionalShadowMap.length,numPointLightShadows:l.pointShadowMap.length,numSpotLightShadows:l.spotShadowMap.length,numSpotLightShadowsWithMaps:l.numSpotLightShadowsWithMaps,numLightProbes:l.numLightProbes,numClippingPlanes:s.numPlanes,numClipIntersection:s.numIntersection,dithering:o.dithering,shadowMapEnabled:e.shadowMap.enabled&&m.length>0,shadowMapType:e.shadowMap.type,toneMapping:be,decodeVideoTexture:V&&!0===o.map.isVideoTexture&&u.getTransfer(o.map.colorSpace)===f,decodeVideoTextureEmissive:q&&!0===o.emissiveMap.isVideoTexture&&u.getTransfer(o.emissiveMap.colorSpace)===f,premultipliedAlpha:o.premultipliedAlpha,doubleSided:o.side===me,flipSided:o.side===d,useDepthPacking:o.depthPacking>=0,depthPacking:o.depthPacking||0,index0AttributeName:o.index0AttributeName,extensionClipCullDistance:Ae&&!0===o.extensions.clipCullDistance&&i.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(Ae&&!0===o.extensions.multiDraw||G)&&i.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:i.has("KHR_parallel_shader_compile"),customProgramCacheKey:o.customProgramCacheKey()};return Ce.vertexUv1s=p.has(1),Ce.vertexUv2s=p.has(2),Ce.vertexUv3s=p.has(3),p.clear(),Ce},getProgramCacheKey:function(t){const n=[];if(t.shaderID?n.push(t.shaderID):(n.push(t.customVertexShaderID),n.push(t.customFragmentShaderID)),void 0!==t.defines)for(const e in t.defines)n.push(e),n.push(t.defines[e]);return!1===t.isRawShaderMaterial&&(!function(e,t){e.push(t.precision),e.push(t.outputColorSpace),e.push(t.envMapMode),e.push(t.envMapCubeUVHeight),e.push(t.mapUv),e.push(t.alphaMapUv),e.push(t.lightMapUv),e.push(t.aoMapUv),e.push(t.bumpMapUv),e.push(t.normalMapUv),e.push(t.displacementMapUv),e.push(t.emissiveMapUv),e.push(t.metalnessMapUv),e.push(t.roughnessMapUv),e.push(t.anisotropyMapUv),e.push(t.clearcoatMapUv),e.push(t.clearcoatNormalMapUv),e.push(t.clearcoatRoughnessMapUv),e.push(t.iridescenceMapUv),e.push(t.iridescenceThicknessMapUv),e.push(t.sheenColorMapUv),e.push(t.sheenRoughnessMapUv),e.push(t.specularMapUv),e.push(t.specularColorMapUv),e.push(t.specularIntensityMapUv),e.push(t.transmissionMapUv),e.push(t.thicknessMapUv),e.push(t.combine),e.push(t.fogExp2),e.push(t.sizeAttenuation),e.push(t.morphTargetsCount),e.push(t.morphAttributeCount),e.push(t.numDirLights),e.push(t.numPointLights),e.push(t.numSpotLights),e.push(t.numSpotLightMaps),e.push(t.numHemiLights),e.push(t.numRectAreaLights),e.push(t.numDirLightShadows),e.push(t.numPointLightShadows),e.push(t.numSpotLightShadows),e.push(t.numSpotLightShadowsWithMaps),e.push(t.numLightProbes),e.push(t.shadowMapType),e.push(t.toneMapping),e.push(t.numClippingPlanes),e.push(t.numClipIntersection),e.push(t.depthPacking)}(n,t),function(e,t){l.disableAll(),t.supportsVertexTextures&&l.enable(0);t.instancing&&l.enable(1);t.instancingColor&&l.enable(2);t.instancingMorph&&l.enable(3);t.matcap&&l.enable(4);t.envMap&&l.enable(5);t.normalMapObjectSpace&&l.enable(6);t.normalMapTangentSpace&&l.enable(7);t.clearcoat&&l.enable(8);t.iridescence&&l.enable(9);t.alphaTest&&l.enable(10);t.vertexColors&&l.enable(11);t.vertexAlphas&&l.enable(12);t.vertexUv1s&&l.enable(13);t.vertexUv2s&&l.enable(14);t.vertexUv3s&&l.enable(15);t.vertexTangents&&l.enable(16);t.anisotropy&&l.enable(17);t.alphaHash&&l.enable(18);t.batching&&l.enable(19);t.dispersion&&l.enable(20);t.batchingColor&&l.enable(21);e.push(l.mask),l.disableAll(),t.fog&&l.enable(0);t.useFog&&l.enable(1);t.flatShading&&l.enable(2);t.logarithmicDepthBuffer&&l.enable(3);t.reverseDepthBuffer&&l.enable(4);t.skinning&&l.enable(5);t.morphTargets&&l.enable(6);t.morphNormals&&l.enable(7);t.morphColors&&l.enable(8);t.premultipliedAlpha&&l.enable(9);t.shadowMapEnabled&&l.enable(10);t.doubleSided&&l.enable(11);t.flipSided&&l.enable(12);t.useDepthPacking&&l.enable(13);t.dithering&&l.enable(14);t.transmission&&l.enable(15);t.sheen&&l.enable(16);t.opaque&&l.enable(17);t.pointsUvs&&l.enable(18);t.decodeVideoTexture&&l.enable(19);t.decodeVideoTextureEmissive&&l.enable(20);t.alphaToCoverage&&l.enable(21);e.push(l.mask)}(n,t),n.push(e.outputColorSpace)),n.push(t.customProgramCacheKey),n.join()},getUniforms:function(e){const t=v[e.type];let n;if(t){const e=yn[t];n=he.clone(e.uniforms)}else n=e.uniforms;return n},acquireProgram:function(t,n){let i;for(let e=0,t=m.length;e0?i.push(d):!0===o.transparent?r.push(d):n.push(d)},unshift:function(e,t,o,s,l,c){const d=a(e,t,o,s,l,c);o.transmission>0?i.unshift(d):!0===o.transparent?r.unshift(d):n.unshift(d)},finish:function(){for(let n=t,i=e.length;n1&&n.sort(e||kr),i.length>1&&i.sort(t||Wr),r.length>1&&r.sort(t||Wr)}}}function Yr(){let e=new WeakMap;return{get:function(t,n){const i=e.get(t);let r;return void 0===i?(r=new Xr,e.set(t,[r])):n>=i.length?(r=new Xr,i.push(r)):r=i[n],r},dispose:function(){e=new WeakMap}}}function jr(){const t={};return{get:function(n){if(void 0!==t[n.id])return t[n.id];let i;switch(n.type){case"DirectionalLight":i={direction:new r,color:new e};break;case"SpotLight":i={position:new r,direction:new r,color:new e,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":i={position:new r,color:new e,distance:0,decay:0};break;case"HemisphereLight":i={direction:new r,skyColor:new e,groundColor:new e};break;case"RectAreaLight":i={color:new e,position:new r,halfWidth:new r,halfHeight:new r}}return t[n.id]=i,i}}}let Kr=0;function qr(e,t){return(t.castShadow?2:0)-(e.castShadow?2:0)+(t.map?1:0)-(e.map?1:0)}function Zr(e){const t=new jr,i=function(){const e={};return{get:function(t){if(void 0!==e[t.id])return e[t.id];let i;switch(t.type){case"DirectionalLight":case"SpotLight":i={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new n};break;case"PointLight":i={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new n,shadowCameraNear:1,shadowCameraFar:1e3}}return e[t.id]=i,i}}}(),a={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 e=0;e<9;e++)a.probe.push(new r);const o=new r,s=new g,l=new g;return{setup:function(n){let r=0,o=0,s=0;for(let e=0;e<9;e++)a.probe[e].set(0,0,0);let l=0,c=0,d=0,u=0,f=0,p=0,m=0,h=0,_=0,g=0,v=0;n.sort(qr);for(let e=0,E=n.length;e0&&(!0===e.has("OES_texture_float_linear")?(a.rectAreaLTC1=Dn.LTC_FLOAT_1,a.rectAreaLTC2=Dn.LTC_FLOAT_2):(a.rectAreaLTC1=Dn.LTC_HALF_1,a.rectAreaLTC2=Dn.LTC_HALF_2)),a.ambient[0]=r,a.ambient[1]=o,a.ambient[2]=s;const E=a.hash;E.directionalLength===l&&E.pointLength===c&&E.spotLength===d&&E.rectAreaLength===u&&E.hemiLength===f&&E.numDirectionalShadows===p&&E.numPointShadows===m&&E.numSpotShadows===h&&E.numSpotMaps===_&&E.numLightProbes===v||(a.directional.length=l,a.spot.length=d,a.rectArea.length=u,a.point.length=c,a.hemi.length=f,a.directionalShadow.length=p,a.directionalShadowMap.length=p,a.pointShadow.length=m,a.pointShadowMap.length=m,a.spotShadow.length=h,a.spotShadowMap.length=h,a.directionalShadowMatrix.length=p,a.pointShadowMatrix.length=m,a.spotLightMatrix.length=h+_-g,a.spotLightMap.length=_,a.numSpotLightShadowsWithMaps=g,a.numLightProbes=v,E.directionalLength=l,E.pointLength=c,E.spotLength=d,E.rectAreaLength=u,E.hemiLength=f,E.numDirectionalShadows=p,E.numPointShadows=m,E.numSpotShadows=h,E.numSpotMaps=_,E.numLightProbes=v,a.version=Kr++)},setupView:function(e,t){let n=0,i=0,r=0,c=0,d=0;const u=t.matrixWorldInverse;for(let t=0,f=e.length;t=r.length?(a=new $r(e),r.push(a)):a=r[i],a},dispose:function(){t=new WeakMap}}}function Jr(e,t,i){let r=new ge;const a=new n,s=new n,c=new k,u=new ve({depthPacking:Ee}),f=new Se,p={},h=i.maxTextureSize,_={[m]:d,[d]:m,[me]:me},g=new l({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new n},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 E=new D;E.setAttribute("position",new y(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const S=new o(E,g),T=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=re;let M=this.type;function x(n,i){const r=t.update(S);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 I(a.x,a.y)),g.uniforms.shadow_pass.value=n.map.texture,g.uniforms.resolution.value=n.mapSize,g.uniforms.radius.value=n.radius,e.setRenderTarget(n.mapPass),e.clear(),e.renderBufferDirect(i,null,r,g,S,null),v.uniforms.shadow_pass.value=n.mapPass.texture,v.uniforms.resolution.value=n.mapSize,v.uniforms.radius.value=n.radius,e.setRenderTarget(n.map),e.clear(),e.renderBufferDirect(i,null,r,v,S,null)}function R(t,n,i,r){let a=null;const o=!0===i.isPointLight?t.customDistanceMaterial:t.customDepthMaterial;if(void 0!==o)a=o;else if(a=!0===i.isPointLight?f:u,e.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 e=a.uuid,t=n.uuid;let i=p[e];void 0===i&&(i={},p[e]=i);let r=i[t];void 0===r&&(r=a.clone(),i[t]=r,n.addEventListener("dispose",b)),a=r}if(a.visible=n.visible,a.wireframe=n.wireframe,a.side=r===oe?null!==n.shadowSide?n.shadowSide:n.side:null!==n.shadowSide?n.shadowSide:_[n.side],a.alphaMap=n.alphaMap,a.alphaTest=n.alphaTest,a.map=n.map,a.clipShadows=n.clipShadows,a.clippingPlanes=n.clippingPlanes,a.clipIntersection=n.clipIntersection,a.displacementMap=n.displacementMap,a.displacementScale=n.displacementScale,a.displacementBias=n.displacementBias,a.wireframeLinewidth=n.wireframeLinewidth,a.linewidth=n.linewidth,!0===i.isPointLight&&!0===a.isMeshDistanceMaterial){e.properties.get(a).light=i}return a}function A(n,i,a,o,s){if(!1===n.visible)return;if(n.layers.test(i.layers)&&(n.isMesh||n.isLine||n.isPoints)&&(n.castShadow||n.receiveShadow&&s===oe)&&(!n.frustumCulled||r.intersectsObject(n))){n.modelViewMatrix.multiplyMatrices(a.matrixWorldInverse,n.matrixWorld);const r=t.update(n),l=n.material;if(Array.isArray(l)){const t=r.groups;for(let c=0,d=t.length;ch||a.y>h)&&(a.x>h&&(s.x=Math.floor(h/m.x),a.x=s.x*m.x,d.mapSize.x=s.x),a.y>h&&(s.y=Math.floor(h/m.y),a.y=s.y*m.y,d.mapSize.y=s.y)),null===d.map||!0===f||!0===p){const e=this.type!==oe?{minFilter:Te,magFilter:Te}:{};null!==d.map&&d.map.dispose(),d.map=new I(a.x,a.y,e),d.map.texture.name=l.name+".shadowMap",d.camera.updateProjectionMatrix()}e.setRenderTarget(d.map),e.clear();const _=d.getViewportCount();for(let e=0;e<_;e++){const t=d.getViewport(e);c.set(s.x*t.x,s.y*t.y,s.x*t.z,s.y*t.w),u.viewport(c),d.updateMatrices(l,e),r=d.getFrustum(),A(n,i,d.camera,l,this.type)}!0!==d.isPointLightShadow&&this.type===oe&&x(d,i),d.needsUpdate=!1}M=this.type,T.needsUpdate=!1,e.setRenderTarget(o,l,d)}}const ea={[et]:Je,[Qe]:qe,[$e]:Ke,[Me]:Ze,[Je]:et,[qe]:Qe,[Ke]:$e,[Ze]:Me};function ta(t,n){const i=new function(){let e=!1;const n=new k;let i=null;const r=new k(0,0,0,0);return{setMask:function(n){i===n||e||(t.colorMask(n,n,n,n),i=n)},setLocked:function(t){e=t},setClear:function(e,i,a,o,s){!0===s&&(e*=o,i*=o,a*=o),n.set(e,i,a,o),!1===r.equals(n)&&(t.clearColor(e,i,a,o),r.copy(n))},reset:function(){e=!1,i=null,r.set(-1,0,0,0)}}},r=new function(){let e=!1,i=!1,r=null,a=null,o=null;return{setReversed:function(e){if(i!==e){const e=n.get("EXT_clip_control");i?e.clipControlEXT(e.LOWER_LEFT_EXT,e.ZERO_TO_ONE_EXT):e.clipControlEXT(e.LOWER_LEFT_EXT,e.NEGATIVE_ONE_TO_ONE_EXT);const t=o;o=null,this.setClear(t)}i=e},getReversed:function(){return i},setTest:function(e){e?W(t.DEPTH_TEST):X(t.DEPTH_TEST)},setMask:function(n){r===n||e||(t.depthMask(n),r=n)},setFunc:function(e){if(i&&(e=ea[e]),a!==e){switch(e){case et:t.depthFunc(t.NEVER);break;case Je:t.depthFunc(t.ALWAYS);break;case Qe:t.depthFunc(t.LESS);break;case Me:t.depthFunc(t.LEQUAL);break;case $e:t.depthFunc(t.EQUAL);break;case Ze:t.depthFunc(t.GEQUAL);break;case qe:t.depthFunc(t.GREATER);break;case Ke:t.depthFunc(t.NOTEQUAL);break;default:t.depthFunc(t.LEQUAL)}a=e}},setLocked:function(t){e=t},setClear:function(e){o!==e&&(i&&(e=1-e),t.clearDepth(e),o=e)},reset:function(){e=!1,r=null,a=null,o=null,i=!1}}},a=new function(){let e=!1,n=null,i=null,r=null,a=null,o=null,s=null,l=null,c=null;return{setTest:function(n){e||(n?W(t.STENCIL_TEST):X(t.STENCIL_TEST))},setMask:function(i){n===i||e||(t.stencilMask(i),n=i)},setFunc:function(e,n,o){i===e&&r===n&&a===o||(t.stencilFunc(e,n,o),i=e,r=n,a=o)},setOp:function(e,n,i){o===e&&s===n&&l===i||(t.stencilOp(e,n,i),o=e,s=n,l=i)},setLocked:function(t){e=t},setClear:function(e){c!==e&&(t.clearStencil(e),c=e)},reset:function(){e=!1,n=null,i=null,r=null,a=null,o=null,s=null,l=null,c=null}}},o=new WeakMap,s=new WeakMap;let l={},c={},u=new WeakMap,f=[],p=null,m=!1,h=null,_=null,g=null,v=null,E=null,S=null,T=null,M=new e(0,0,0),x=0,R=!1,A=null,b=null,C=null,L=null,P=null;const U=t.getParameter(t.MAX_COMBINED_TEXTURE_IMAGE_UNITS);let w=!1,D=0;const y=t.getParameter(t.VERSION);-1!==y.indexOf("WebGL")?(D=parseFloat(/^WebGL (\d)/.exec(y)[1]),w=D>=1):-1!==y.indexOf("OpenGL ES")&&(D=parseFloat(/^OpenGL ES (\d)/.exec(y)[1]),w=D>=2);let I=null,O={};const F=t.getParameter(t.SCISSOR_BOX),B=t.getParameter(t.VIEWPORT),H=(new k).fromArray(F),G=(new k).fromArray(B);function V(e,n,i,r){const a=new Uint8Array(4),o=t.createTexture();t.bindTexture(e,o),t.texParameteri(e,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(e,t.TEXTURE_MAG_FILTER,t.NEAREST);for(let o=0;on||r.height>n)&&(i=n/Math.max(r.width,r.height)),i<1){if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap||"undefined"!=typeof VideoFrame&&e instanceof VideoFrame){const n=Math.floor(i*r.width),a=Math.floor(i*r.height);void 0===m&&(m=g(n,a));const o=t?g(n,a):m;o.width=n,o.height=a;return o.getContext("2d").drawImage(e,0,0,n,a),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+r.width+"x"+r.height+") to ("+n+"x"+a+")."),o}return"data"in e&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+r.width+"x"+r.height+")."),e}return e}function S(e){return e.generateMipmaps}function x(t){e.generateMipmap(t)}function R(t){return t.isWebGLCubeRenderTarget?e.TEXTURE_CUBE_MAP:t.isWebGL3DRenderTarget?e.TEXTURE_3D:t.isWebGLArrayRenderTarget||t.isCompressedArrayTexture?e.TEXTURE_2D_ARRAY:e.TEXTURE_2D}function A(n,i,r,a,o=!1){if(null!==n){if(void 0!==e[n])return e[n];console.warn("THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format '"+n+"'")}let s=i;if(i===e.RED&&(r===e.FLOAT&&(s=e.R32F),r===e.HALF_FLOAT&&(s=e.R16F),r===e.UNSIGNED_BYTE&&(s=e.R8)),i===e.RED_INTEGER&&(r===e.UNSIGNED_BYTE&&(s=e.R8UI),r===e.UNSIGNED_SHORT&&(s=e.R16UI),r===e.UNSIGNED_INT&&(s=e.R32UI),r===e.BYTE&&(s=e.R8I),r===e.SHORT&&(s=e.R16I),r===e.INT&&(s=e.R32I)),i===e.RG&&(r===e.FLOAT&&(s=e.RG32F),r===e.HALF_FLOAT&&(s=e.RG16F),r===e.UNSIGNED_BYTE&&(s=e.RG8)),i===e.RG_INTEGER&&(r===e.UNSIGNED_BYTE&&(s=e.RG8UI),r===e.UNSIGNED_SHORT&&(s=e.RG16UI),r===e.UNSIGNED_INT&&(s=e.RG32UI),r===e.BYTE&&(s=e.RG8I),r===e.SHORT&&(s=e.RG16I),r===e.INT&&(s=e.RG32I)),i===e.RGB_INTEGER&&(r===e.UNSIGNED_BYTE&&(s=e.RGB8UI),r===e.UNSIGNED_SHORT&&(s=e.RGB16UI),r===e.UNSIGNED_INT&&(s=e.RGB32UI),r===e.BYTE&&(s=e.RGB8I),r===e.SHORT&&(s=e.RGB16I),r===e.INT&&(s=e.RGB32I)),i===e.RGBA_INTEGER&&(r===e.UNSIGNED_BYTE&&(s=e.RGBA8UI),r===e.UNSIGNED_SHORT&&(s=e.RGBA16UI),r===e.UNSIGNED_INT&&(s=e.RGBA32UI),r===e.BYTE&&(s=e.RGBA8I),r===e.SHORT&&(s=e.RGBA16I),r===e.INT&&(s=e.RGBA32I)),i===e.RGB&&r===e.UNSIGNED_INT_5_9_9_9_REV&&(s=e.RGB9_E5),i===e.RGBA){const t=o?se:u.getTransfer(a);r===e.FLOAT&&(s=e.RGBA32F),r===e.HALF_FLOAT&&(s=e.RGBA16F),r===e.UNSIGNED_BYTE&&(s=t===f?e.SRGB8_ALPHA8:e.RGBA8),r===e.UNSIGNED_SHORT_4_4_4_4&&(s=e.RGBA4),r===e.UNSIGNED_SHORT_5_5_5_1&&(s=e.RGB5_A1)}return s!==e.R16F&&s!==e.R32F&&s!==e.RG16F&&s!==e.RG32F&&s!==e.RGBA16F&&s!==e.RGBA32F||t.get("EXT_color_buffer_float"),s}function b(t,n){let i;return t?null===n||n===St||n===Tt?i=e.DEPTH24_STENCIL8:n===M?i=e.DEPTH32F_STENCIL8:n===Mt&&(i=e.DEPTH24_STENCIL8,console.warn("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):null===n||n===St||n===Tt?i=e.DEPTH_COMPONENT24:n===M?i=e.DEPTH_COMPONENT32F:n===Mt&&(i=e.DEPTH_COMPONENT16),i}function C(e,t){return!0===S(e)||e.isFramebufferTexture&&e.minFilter!==Te&&e.minFilter!==F?Math.log2(Math.max(t.width,t.height))+1:void 0!==e.mipmaps&&e.mipmaps.length>0?e.mipmaps.length:e.isCompressedTexture&&Array.isArray(e.image)?t.mipmaps.length:1}function L(e){const t=e.target;t.removeEventListener("dispose",L),function(e){const t=r.get(e);if(void 0===t.__webglInit)return;const n=e.source,i=h.get(n);if(i){const r=i[t.__cacheKey];r.usedTimes--,0===r.usedTimes&&U(e),0===Object.keys(i).length&&h.delete(n)}r.remove(e)}(t),t.isVideoTexture&&p.delete(t)}function P(t){const n=t.target;n.removeEventListener("dispose",P),function(t){const n=r.get(t);t.depthTexture&&(t.depthTexture.dispose(),r.remove(t.depthTexture));if(t.isWebGLCubeRenderTarget)for(let t=0;t<6;t++){if(Array.isArray(n.__webglFramebuffer[t]))for(let i=0;i0&&a.__version!==t.version){const e=t.image;if(null===e)console.warn("THREE.WebGLRenderer: Texture marked for update but no image data found.");else{if(!1!==e.complete)return void G(a,t,n);console.warn("THREE.WebGLRenderer: Texture marked for update but image is incomplete")}}i.bindTexture(e.TEXTURE_2D,a.__webglTexture,e.TEXTURE0+n)}const y={[it]:e.REPEAT,[rt]:e.CLAMP_TO_EDGE,[at]:e.MIRRORED_REPEAT},I={[Te]:e.NEAREST,[ot]:e.NEAREST_MIPMAP_NEAREST,[st]:e.NEAREST_MIPMAP_LINEAR,[F]:e.LINEAR,[lt]:e.LINEAR_MIPMAP_NEAREST,[ct]:e.LINEAR_MIPMAP_LINEAR},N={[dt]:e.NEVER,[ut]:e.ALWAYS,[ft]:e.LESS,[X]:e.LEQUAL,[pt]:e.EQUAL,[mt]:e.GEQUAL,[ht]:e.GREATER,[_t]:e.NOTEQUAL};function O(n,i){if(i.type!==M||!1!==t.has("OES_texture_float_linear")||i.magFilter!==F&&i.magFilter!==lt&&i.magFilter!==st&&i.magFilter!==ct&&i.minFilter!==F&&i.minFilter!==lt&&i.minFilter!==st&&i.minFilter!==ct||console.warn("THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),e.texParameteri(n,e.TEXTURE_WRAP_S,y[i.wrapS]),e.texParameteri(n,e.TEXTURE_WRAP_T,y[i.wrapT]),n!==e.TEXTURE_3D&&n!==e.TEXTURE_2D_ARRAY||e.texParameteri(n,e.TEXTURE_WRAP_R,y[i.wrapR]),e.texParameteri(n,e.TEXTURE_MAG_FILTER,I[i.magFilter]),e.texParameteri(n,e.TEXTURE_MIN_FILTER,I[i.minFilter]),i.compareFunction&&(e.texParameteri(n,e.TEXTURE_COMPARE_MODE,e.COMPARE_REF_TO_TEXTURE),e.texParameteri(n,e.TEXTURE_COMPARE_FUNC,N[i.compareFunction])),!0===t.has("EXT_texture_filter_anisotropic")){if(i.magFilter===Te)return;if(i.minFilter!==st&&i.minFilter!==ct)return;if(i.type===M&&!1===t.has("OES_texture_float_linear"))return;if(i.anisotropy>1||r.get(i).__currentAnisotropy){const o=t.get("EXT_texture_filter_anisotropic");e.texParameterf(n,o.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(i.anisotropy,a.getMaxAnisotropy())),r.get(i).__currentAnisotropy=i.anisotropy}}}function H(t,n){let i=!1;void 0===t.__webglInit&&(t.__webglInit=!0,n.addEventListener("dispose",L));const r=n.source;let a=h.get(r);void 0===a&&(a={},h.set(r,a));const o=function(e){const t=[];return t.push(e.wrapS),t.push(e.wrapT),t.push(e.wrapR||0),t.push(e.magFilter),t.push(e.minFilter),t.push(e.anisotropy),t.push(e.internalFormat),t.push(e.format),t.push(e.type),t.push(e.generateMipmaps),t.push(e.premultiplyAlpha),t.push(e.flipY),t.push(e.unpackAlignment),t.push(e.colorSpace),t.join()}(n);if(o!==t.__cacheKey){void 0===a[o]&&(a[o]={texture:e.createTexture(),usedTimes:0},s.memory.textures++,i=!0),a[o].usedTimes++;const r=a[t.__cacheKey];void 0!==r&&(a[t.__cacheKey].usedTimes--,0===r.usedTimes&&U(n)),t.__cacheKey=o,t.__webglTexture=a[o].texture}return i}function G(t,n,s){let l=e.TEXTURE_2D;(n.isDataArrayTexture||n.isCompressedArrayTexture)&&(l=e.TEXTURE_2D_ARRAY),n.isData3DTexture&&(l=e.TEXTURE_3D);const c=H(t,n),d=n.source;i.bindTexture(l,t.__webglTexture,e.TEXTURE0+s);const f=r.get(d);if(d.version!==f.__version||!0===c){i.activeTexture(e.TEXTURE0+s);const t=u.getPrimaries(u.workingColorSpace),r=n.colorSpace===gt?null:u.getPrimaries(n.colorSpace),p=n.colorSpace===gt||t===r?e.NONE:e.BROWSER_DEFAULT_WEBGL;e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,n.flipY),e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL,n.premultiplyAlpha),e.pixelStorei(e.UNPACK_ALIGNMENT,n.unpackAlignment),e.pixelStorei(e.UNPACK_COLORSPACE_CONVERSION_WEBGL,p);let m=v(n.image,!1,a.maxTextureSize);m=q(n,m);const h=o.convert(n.format,n.colorSpace),_=o.convert(n.type);let g,T=A(n.internalFormat,h,_,n.colorSpace,n.isVideoTexture);O(l,n);const M=n.mipmaps,R=!0!==n.isVideoTexture,L=void 0===f.__version||!0===c,P=d.dataReady,U=C(n,m);if(n.isDepthTexture)T=b(n.format===vt,n.type),L&&(R?i.texStorage2D(e.TEXTURE_2D,1,T,m.width,m.height):i.texImage2D(e.TEXTURE_2D,0,T,m.width,m.height,0,h,_,null));else if(n.isDataTexture)if(M.length>0){R&&L&&i.texStorage2D(e.TEXTURE_2D,U,T,M[0].width,M[0].height);for(let t=0,n=M.length;t0){const r=Et(g.width,g.height,n.format,n.type);for(const a of n.layerUpdates){const n=g.data.subarray(a*r/g.data.BYTES_PER_ELEMENT,(a+1)*r/g.data.BYTES_PER_ELEMENT);i.compressedTexSubImage3D(e.TEXTURE_2D_ARRAY,t,0,0,a,g.width,g.height,1,h,n)}n.clearLayerUpdates()}else i.compressedTexSubImage3D(e.TEXTURE_2D_ARRAY,t,0,0,0,g.width,g.height,m.depth,h,g.data)}else i.compressedTexImage3D(e.TEXTURE_2D_ARRAY,t,T,g.width,g.height,m.depth,0,g.data,0,0);else console.warn("THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else R?P&&i.texSubImage3D(e.TEXTURE_2D_ARRAY,t,0,0,0,g.width,g.height,m.depth,h,_,g.data):i.texImage3D(e.TEXTURE_2D_ARRAY,t,T,g.width,g.height,m.depth,0,h,_,g.data)}else{R&&L&&i.texStorage2D(e.TEXTURE_2D,U,T,M[0].width,M[0].height);for(let t=0,r=M.length;t0){const t=Et(m.width,m.height,n.format,n.type);for(const r of n.layerUpdates){const n=m.data.subarray(r*t/m.data.BYTES_PER_ELEMENT,(r+1)*t/m.data.BYTES_PER_ELEMENT);i.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,r,m.width,m.height,1,h,_,n)}n.clearLayerUpdates()}else i.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,0,m.width,m.height,m.depth,h,_,m.data)}else i.texImage3D(e.TEXTURE_2D_ARRAY,0,T,m.width,m.height,m.depth,0,h,_,m.data);else if(n.isData3DTexture)R?(L&&i.texStorage3D(e.TEXTURE_3D,U,T,m.width,m.height,m.depth),P&&i.texSubImage3D(e.TEXTURE_3D,0,0,0,0,m.width,m.height,m.depth,h,_,m.data)):i.texImage3D(e.TEXTURE_3D,0,T,m.width,m.height,m.depth,0,h,_,m.data);else if(n.isFramebufferTexture){if(L)if(R)i.texStorage2D(e.TEXTURE_2D,U,T,m.width,m.height);else{let t=m.width,n=m.height;for(let r=0;r>=1,n>>=1}}else if(M.length>0){if(R&&L){const t=Z(M[0]);i.texStorage2D(e.TEXTURE_2D,U,T,t.width,t.height)}for(let t=0,n=M.length;t>d),r=Math.max(1,n.height>>d);c===e.TEXTURE_3D||c===e.TEXTURE_2D_ARRAY?i.texImage3D(c,d,p,t,r,n.depth,0,u,f,null):i.texImage2D(c,d,p,t,r,0,u,f,null)}i.bindFramebuffer(e.FRAMEBUFFER,t),K(n)?l.framebufferTexture2DMultisampleEXT(e.FRAMEBUFFER,s,c,h.__webglTexture,0,j(n)):(c===e.TEXTURE_2D||c>=e.TEXTURE_CUBE_MAP_POSITIVE_X&&c<=e.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&e.framebufferTexture2D(e.FRAMEBUFFER,s,c,h.__webglTexture,d),i.bindFramebuffer(e.FRAMEBUFFER,null)}function z(t,n,i){if(e.bindRenderbuffer(e.RENDERBUFFER,t),n.depthBuffer){const r=n.depthTexture,a=r&&r.isDepthTexture?r.type:null,o=b(n.stencilBuffer,a),s=n.stencilBuffer?e.DEPTH_STENCIL_ATTACHMENT:e.DEPTH_ATTACHMENT,c=j(n);K(n)?l.renderbufferStorageMultisampleEXT(e.RENDERBUFFER,c,o,n.width,n.height):i?e.renderbufferStorageMultisample(e.RENDERBUFFER,c,o,n.width,n.height):e.renderbufferStorage(e.RENDERBUFFER,o,n.width,n.height),e.framebufferRenderbuffer(e.FRAMEBUFFER,s,e.RENDERBUFFER,t)}else{const t=n.textures;for(let r=0;r{delete n.__boundDepthTexture,delete n.__depthDisposeCallback,e.removeEventListener("dispose",t)};e.addEventListener("dispose",t),n.__depthDisposeCallback=t}n.__boundDepthTexture=e}if(t.depthTexture&&!n.__autoAllocateDepthBuffer){if(a)throw new Error("target.depthTexture not supported in Cube render targets");!function(t,n){if(n&&n.isWebGLCubeRenderTarget)throw new Error("Depth Texture with cube render targets is not supported");if(i.bindFramebuffer(e.FRAMEBUFFER,t),!n.depthTexture||!n.depthTexture.isDepthTexture)throw new Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture");const a=r.get(n.depthTexture);a.__renderTarget=n,a.__webglTexture&&n.depthTexture.image.width===n.width&&n.depthTexture.image.height===n.height||(n.depthTexture.image.width=n.width,n.depthTexture.image.height=n.height,n.depthTexture.needsUpdate=!0),D(n.depthTexture,0);const o=a.__webglTexture,s=j(n);if(n.depthTexture.format===xt)K(n)?l.framebufferTexture2DMultisampleEXT(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.TEXTURE_2D,o,0,s):e.framebufferTexture2D(e.FRAMEBUFFER,e.DEPTH_ATTACHMENT,e.TEXTURE_2D,o,0);else{if(n.depthTexture.format!==vt)throw new Error("Unknown depthTexture format");K(n)?l.framebufferTexture2DMultisampleEXT(e.FRAMEBUFFER,e.DEPTH_STENCIL_ATTACHMENT,e.TEXTURE_2D,o,0,s):e.framebufferTexture2D(e.FRAMEBUFFER,e.DEPTH_STENCIL_ATTACHMENT,e.TEXTURE_2D,o,0)}}(n.__webglFramebuffer,t)}else if(a){n.__webglDepthbuffer=[];for(let r=0;r<6;r++)if(i.bindFramebuffer(e.FRAMEBUFFER,n.__webglFramebuffer[r]),void 0===n.__webglDepthbuffer[r])n.__webglDepthbuffer[r]=e.createRenderbuffer(),z(n.__webglDepthbuffer[r],t,!1);else{const i=t.stencilBuffer?e.DEPTH_STENCIL_ATTACHMENT:e.DEPTH_ATTACHMENT,a=n.__webglDepthbuffer[r];e.bindRenderbuffer(e.RENDERBUFFER,a),e.framebufferRenderbuffer(e.FRAMEBUFFER,i,e.RENDERBUFFER,a)}}else if(i.bindFramebuffer(e.FRAMEBUFFER,n.__webglFramebuffer),void 0===n.__webglDepthbuffer)n.__webglDepthbuffer=e.createRenderbuffer(),z(n.__webglDepthbuffer,t,!1);else{const i=t.stencilBuffer?e.DEPTH_STENCIL_ATTACHMENT:e.DEPTH_ATTACHMENT,r=n.__webglDepthbuffer;e.bindRenderbuffer(e.RENDERBUFFER,r),e.framebufferRenderbuffer(e.FRAMEBUFFER,i,e.RENDERBUFFER,r)}i.bindFramebuffer(e.FRAMEBUFFER,null)}const W=[],Y=[];function j(e){return Math.min(a.maxSamples,e.samples)}function K(e){const n=r.get(e);return e.samples>0&&!0===t.has("WEBGL_multisampled_render_to_texture")&&!1!==n.__useRenderToTexture}function q(e,t){const n=e.colorSpace,i=e.format,r=e.type;return!0===e.isCompressedTexture||!0===e.isVideoTexture||n!==B&&n!==gt&&(u.getTransfer(n)===f?i===E&&r===T||console.warn("THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):console.error("THREE.WebGLTextures: Unsupported texture color space:",n)),t}function Z(e){return"undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement?(d.width=e.naturalWidth||e.width,d.height=e.naturalHeight||e.height):"undefined"!=typeof VideoFrame&&e instanceof VideoFrame?(d.width=e.displayWidth,d.height=e.displayHeight):(d.width=e.width,d.height=e.height),d}this.allocateTextureUnit=function(){const e=w;return e>=a.maxTextures&&console.warn("THREE.WebGLTextures: Trying to use "+e+" texture units while this GPU supports only "+a.maxTextures),w+=1,e},this.resetTextureUnits=function(){w=0},this.setTexture2D=D,this.setTexture2DArray=function(t,n){const a=r.get(t);t.version>0&&a.__version!==t.version?G(a,t,n):i.bindTexture(e.TEXTURE_2D_ARRAY,a.__webglTexture,e.TEXTURE0+n)},this.setTexture3D=function(t,n){const a=r.get(t);t.version>0&&a.__version!==t.version?G(a,t,n):i.bindTexture(e.TEXTURE_3D,a.__webglTexture,e.TEXTURE0+n)},this.setTextureCube=function(t,n){const s=r.get(t);t.version>0&&s.__version!==t.version?function(t,n,s){if(6!==n.image.length)return;const l=H(t,n),c=n.source;i.bindTexture(e.TEXTURE_CUBE_MAP,t.__webglTexture,e.TEXTURE0+s);const d=r.get(c);if(c.version!==d.__version||!0===l){i.activeTexture(e.TEXTURE0+s);const t=u.getPrimaries(u.workingColorSpace),r=n.colorSpace===gt?null:u.getPrimaries(n.colorSpace),f=n.colorSpace===gt||t===r?e.NONE:e.BROWSER_DEFAULT_WEBGL;e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,n.flipY),e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL,n.premultiplyAlpha),e.pixelStorei(e.UNPACK_ALIGNMENT,n.unpackAlignment),e.pixelStorei(e.UNPACK_COLORSPACE_CONVERSION_WEBGL,f);const p=n.isCompressedTexture||n.image[0].isCompressedTexture,m=n.image[0]&&n.image[0].isDataTexture,h=[];for(let e=0;e<6;e++)h[e]=p||m?m?n.image[e].image:n.image[e]:v(n.image[e],!0,a.maxCubemapSize),h[e]=q(n,h[e]);const _=h[0],g=o.convert(n.format,n.colorSpace),T=o.convert(n.type),M=A(n.internalFormat,g,T,n.colorSpace),R=!0!==n.isVideoTexture,b=void 0===d.__version||!0===l,L=c.dataReady;let P,U=C(n,_);if(O(e.TEXTURE_CUBE_MAP,n),p){R&&b&&i.texStorage2D(e.TEXTURE_CUBE_MAP,U,M,_.width,_.height);for(let t=0;t<6;t++){P=h[t].mipmaps;for(let r=0;r0&&U++;const t=Z(h[0]);i.texStorage2D(e.TEXTURE_CUBE_MAP,U,M,t.width,t.height)}for(let t=0;t<6;t++)if(m){R?L&&i.texSubImage2D(e.TEXTURE_CUBE_MAP_POSITIVE_X+t,0,0,0,h[t].width,h[t].height,g,T,h[t].data):i.texImage2D(e.TEXTURE_CUBE_MAP_POSITIVE_X+t,0,M,h[t].width,h[t].height,0,g,T,h[t].data);for(let n=0;n1;if(u||(void 0===l.__webglTexture&&(l.__webglTexture=e.createTexture()),l.__version=n.version,s.memory.textures++),d){a.__webglFramebuffer=[];for(let t=0;t<6;t++)if(n.mipmaps&&n.mipmaps.length>0){a.__webglFramebuffer[t]=[];for(let i=0;i0){a.__webglFramebuffer=[];for(let t=0;t0&&!1===K(t)){a.__webglMultisampledFramebuffer=e.createFramebuffer(),a.__webglColorRenderbuffer=[],i.bindFramebuffer(e.FRAMEBUFFER,a.__webglMultisampledFramebuffer);for(let n=0;n0)for(let r=0;r0)for(let i=0;i0)if(!1===K(t)){const n=t.textures,a=t.width,o=t.height;let s=e.COLOR_BUFFER_BIT;const l=t.stencilBuffer?e.DEPTH_STENCIL_ATTACHMENT:e.DEPTH_ATTACHMENT,d=r.get(t),u=n.length>1;if(u)for(let t=0;ts+c?(l.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!l.inputState.pinching&&o<=s-c&&(l.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else null!==s&&e.gripSpace&&(r=t.getPose(e.gripSpace,n),null!==r&&(s.matrix.fromArray(r.transform.matrix),s.matrix.decompose(s.position,s.rotation,s.scale),s.matrixWorldNeedsUpdate=!0,r.linearVelocity?(s.hasLinearVelocity=!0,s.linearVelocity.copy(r.linearVelocity)):s.hasLinearVelocity=!1,r.angularVelocity?(s.hasAngularVelocity=!0,s.angularVelocity.copy(r.angularVelocity)):s.hasAngularVelocity=!1));null!==o&&(i=t.getPose(e.targetRaySpace,n),null===i&&null!==r&&(i=r),null!==i&&(o.matrix.fromArray(i.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,i.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(i.linearVelocity)):o.hasLinearVelocity=!1,i.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(i.angularVelocity)):o.hasAngularVelocity=!1,this.dispatchEvent(ra)))}return null!==o&&(o.visible=null!==i),null!==s&&(s.visible=null!==r),null!==l&&(l.visible=null!==a),this}_getHandJoint(e,t){if(void 0===e.joints[t.jointName]){const n=new vn;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}}class oa{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t,n){if(null===this.texture){const i=new Y;e.properties.get(i).__webglTexture=t.texture,t.depthNear===n.depthNear&&t.depthFar===n.depthFar||(this.depthNear=t.depthNear,this.depthFar=t.depthFar),this.texture=i}}getMesh(e){if(null!==this.texture&&null===this.mesh){const t=e.cameras[0].viewport,n=new l({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:t.z},depthHeight:{value:t.w}}});this.mesh=new o(new p(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class sa extends En{constructor(e,t){super();const i=this;let a=null,o=1,s=null,l="local-floor",c=1,d=null,u=null,f=null,p=null,m=null,h=null;const _=new oa,g=t.getContextAttributes();let v=null,S=null;const M=[],x=[],R=new n;let A=null;const b=new P;b.viewport=new k;const C=new P;C.viewport=new k;const L=[b,C],U=new Sn;let w=null,D=null;function y(e){const t=x.indexOf(e.inputSource);if(-1===t)return;const n=M[t];void 0!==n&&(n.update(e.inputSource,e.frame,d||s),n.dispatchEvent({type:e.type,data:e.inputSource}))}function N(){a.removeEventListener("select",y),a.removeEventListener("selectstart",y),a.removeEventListener("selectend",y),a.removeEventListener("squeeze",y),a.removeEventListener("squeezestart",y),a.removeEventListener("squeezeend",y),a.removeEventListener("end",N),a.removeEventListener("inputsourceschange",O);for(let e=0;e=0&&(x[i]=null,M[i].disconnect(n))}for(let t=0;t=x.length){x.push(n),i=e;break}if(null===x[e]){x[e]=n,i=e;break}}if(-1===i)break}const r=M[i];r&&r.connect(n)}}this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(e){let t=M[e];return void 0===t&&(t=new aa,M[e]=t),t.getTargetRaySpace()},this.getControllerGrip=function(e){let t=M[e];return void 0===t&&(t=new aa,M[e]=t),t.getGripSpace()},this.getHand=function(e){let t=M[e];return void 0===t&&(t=new aa,M[e]=t),t.getHandSpace()},this.setFramebufferScaleFactor=function(e){o=e,!0===i.isPresenting&&console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(e){l=e,!0===i.isPresenting&&console.warn("THREE.WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return d||s},this.setReferenceSpace=function(e){d=e},this.getBaseLayer=function(){return null!==p?p:m},this.getBinding=function(){return f},this.getFrame=function(){return h},this.getSession=function(){return a},this.setSession=async function(n){if(a=n,null!==a){v=e.getRenderTarget(),a.addEventListener("select",y),a.addEventListener("selectstart",y),a.addEventListener("selectend",y),a.addEventListener("squeeze",y),a.addEventListener("squeezestart",y),a.addEventListener("squeezeend",y),a.addEventListener("end",N),a.addEventListener("inputsourceschange",O),!0!==g.xrCompatible&&await t.makeXRCompatible(),A=e.getPixelRatio(),e.getSize(R);if("undefined"!=typeof XRWebGLBinding&&"createProjectionLayer"in XRWebGLBinding.prototype){let n=null,i=null,r=null;g.depth&&(r=g.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,n=g.stencil?vt:xt,i=g.stencil?Tt:St);const s={colorFormat:t.RGBA8,depthFormat:r,scaleFactor:o};f=new XRWebGLBinding(a,t),p=f.createProjectionLayer(s),a.updateRenderState({layers:[p]}),e.setPixelRatio(1),e.setSize(p.textureWidth,p.textureHeight,!1),S=new I(p.textureWidth,p.textureHeight,{format:E,type:T,depthTexture:new j(p.textureWidth,p.textureHeight,i,void 0,void 0,void 0,void 0,void 0,void 0,n),stencilBuffer:g.stencil,colorSpace:e.outputColorSpace,samples:g.antialias?4:0,resolveDepthBuffer:!1===p.ignoreDepthValues})}else{const n={antialias:g.antialias,alpha:!0,depth:g.depth,stencil:g.stencil,framebufferScaleFactor:o};m=new XRWebGLLayer(a,t,n),a.updateRenderState({baseLayer:m}),e.setPixelRatio(1),e.setSize(m.framebufferWidth,m.framebufferHeight,!1),S=new I(m.framebufferWidth,m.framebufferHeight,{format:E,type:T,colorSpace:e.outputColorSpace,stencilBuffer:g.stencil})}S.isXRRenderTarget=!0,this.setFoveation(c),d=null,s=await a.requestReferenceSpace(l),V.setContext(a),V.start(),i.isPresenting=!0,i.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(null!==a)return a.environmentBlendMode},this.getDepthTexture=function(){return _.getDepthTexture()};const F=new r,B=new r;function H(e,t){null===t?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(t.matrixWorld,e.matrix),e.matrixWorldInverse.copy(e.matrixWorld).invert()}this.updateCamera=function(e){if(null===a)return;let t=e.near,n=e.far;null!==_.texture&&(_.depthNear>0&&(t=_.depthNear),_.depthFar>0&&(n=_.depthFar)),U.near=C.near=b.near=t,U.far=C.far=b.far=n,w===U.near&&D===U.far||(a.updateRenderState({depthNear:U.near,depthFar:U.far}),w=U.near,D=U.far),b.layers.mask=2|e.layers.mask,C.layers.mask=4|e.layers.mask,U.layers.mask=b.layers.mask|C.layers.mask;const i=e.parent,r=U.cameras;H(U,i);for(let e=0;e0&&(e.alphaTest.value=i.alphaTest);const r=t.get(i),a=r.envMap,o=r.envMapRotation;a&&(e.envMap.value=a,la.copy(o),la.x*=-1,la.y*=-1,la.z*=-1,a.isCubeTexture&&!1===a.isRenderTargetTexture&&(la.y*=-1,la.z*=-1),e.envMapRotation.value.setFromMatrix4(ca.makeRotationFromEuler(la)),e.flipEnvMap.value=a.isCubeTexture&&!1===a.isRenderTargetTexture?-1:1,e.reflectivity.value=i.reflectivity,e.ior.value=i.ior,e.refractionRatio.value=i.refractionRatio),i.lightMap&&(e.lightMap.value=i.lightMap,e.lightMapIntensity.value=i.lightMapIntensity,n(i.lightMap,e.lightMapTransform)),i.aoMap&&(e.aoMap.value=i.aoMap,e.aoMapIntensity.value=i.aoMapIntensity,n(i.aoMap,e.aoMapTransform))}return{refreshFogUniforms:function(t,n){n.color.getRGB(t.fogColor.value,h(e)),n.isFog?(t.fogNear.value=n.near,t.fogFar.value=n.far):n.isFogExp2&&(t.fogDensity.value=n.density)},refreshMaterialUniforms:function(e,r,a,o,s){r.isMeshBasicMaterial||r.isMeshLambertMaterial?i(e,r):r.isMeshToonMaterial?(i(e,r),function(e,t){t.gradientMap&&(e.gradientMap.value=t.gradientMap)}(e,r)):r.isMeshPhongMaterial?(i(e,r),function(e,t){e.specular.value.copy(t.specular),e.shininess.value=Math.max(t.shininess,1e-4)}(e,r)):r.isMeshStandardMaterial?(i(e,r),function(e,t){e.metalness.value=t.metalness,t.metalnessMap&&(e.metalnessMap.value=t.metalnessMap,n(t.metalnessMap,e.metalnessMapTransform));e.roughness.value=t.roughness,t.roughnessMap&&(e.roughnessMap.value=t.roughnessMap,n(t.roughnessMap,e.roughnessMapTransform));t.envMap&&(e.envMapIntensity.value=t.envMapIntensity)}(e,r),r.isMeshPhysicalMaterial&&function(e,t,i){e.ior.value=t.ior,t.sheen>0&&(e.sheenColor.value.copy(t.sheenColor).multiplyScalar(t.sheen),e.sheenRoughness.value=t.sheenRoughness,t.sheenColorMap&&(e.sheenColorMap.value=t.sheenColorMap,n(t.sheenColorMap,e.sheenColorMapTransform)),t.sheenRoughnessMap&&(e.sheenRoughnessMap.value=t.sheenRoughnessMap,n(t.sheenRoughnessMap,e.sheenRoughnessMapTransform)));t.clearcoat>0&&(e.clearcoat.value=t.clearcoat,e.clearcoatRoughness.value=t.clearcoatRoughness,t.clearcoatMap&&(e.clearcoatMap.value=t.clearcoatMap,n(t.clearcoatMap,e.clearcoatMapTransform)),t.clearcoatRoughnessMap&&(e.clearcoatRoughnessMap.value=t.clearcoatRoughnessMap,n(t.clearcoatRoughnessMap,e.clearcoatRoughnessMapTransform)),t.clearcoatNormalMap&&(e.clearcoatNormalMap.value=t.clearcoatNormalMap,n(t.clearcoatNormalMap,e.clearcoatNormalMapTransform),e.clearcoatNormalScale.value.copy(t.clearcoatNormalScale),t.side===d&&e.clearcoatNormalScale.value.negate()));t.dispersion>0&&(e.dispersion.value=t.dispersion);t.iridescence>0&&(e.iridescence.value=t.iridescence,e.iridescenceIOR.value=t.iridescenceIOR,e.iridescenceThicknessMinimum.value=t.iridescenceThicknessRange[0],e.iridescenceThicknessMaximum.value=t.iridescenceThicknessRange[1],t.iridescenceMap&&(e.iridescenceMap.value=t.iridescenceMap,n(t.iridescenceMap,e.iridescenceMapTransform)),t.iridescenceThicknessMap&&(e.iridescenceThicknessMap.value=t.iridescenceThicknessMap,n(t.iridescenceThicknessMap,e.iridescenceThicknessMapTransform)));t.transmission>0&&(e.transmission.value=t.transmission,e.transmissionSamplerMap.value=i.texture,e.transmissionSamplerSize.value.set(i.width,i.height),t.transmissionMap&&(e.transmissionMap.value=t.transmissionMap,n(t.transmissionMap,e.transmissionMapTransform)),e.thickness.value=t.thickness,t.thicknessMap&&(e.thicknessMap.value=t.thicknessMap,n(t.thicknessMap,e.thicknessMapTransform)),e.attenuationDistance.value=t.attenuationDistance,e.attenuationColor.value.copy(t.attenuationColor));t.anisotropy>0&&(e.anisotropyVector.value.set(t.anisotropy*Math.cos(t.anisotropyRotation),t.anisotropy*Math.sin(t.anisotropyRotation)),t.anisotropyMap&&(e.anisotropyMap.value=t.anisotropyMap,n(t.anisotropyMap,e.anisotropyMapTransform)));e.specularIntensity.value=t.specularIntensity,e.specularColor.value.copy(t.specularColor),t.specularColorMap&&(e.specularColorMap.value=t.specularColorMap,n(t.specularColorMap,e.specularColorMapTransform));t.specularIntensityMap&&(e.specularIntensityMap.value=t.specularIntensityMap,n(t.specularIntensityMap,e.specularIntensityMapTransform))}(e,r,s)):r.isMeshMatcapMaterial?(i(e,r),function(e,t){t.matcap&&(e.matcap.value=t.matcap)}(e,r)):r.isMeshDepthMaterial?i(e,r):r.isMeshDistanceMaterial?(i(e,r),function(e,n){const i=t.get(n).light;e.referencePosition.value.setFromMatrixPosition(i.matrixWorld),e.nearDistance.value=i.shadow.camera.near,e.farDistance.value=i.shadow.camera.far}(e,r)):r.isMeshNormalMaterial?i(e,r):r.isLineBasicMaterial?(function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,t.map&&(e.map.value=t.map,n(t.map,e.mapTransform))}(e,r),r.isLineDashedMaterial&&function(e,t){e.dashSize.value=t.dashSize,e.totalSize.value=t.dashSize+t.gapSize,e.scale.value=t.scale}(e,r)):r.isPointsMaterial?function(e,t,i,r){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,e.size.value=t.size*i,e.scale.value=.5*r,t.map&&(e.map.value=t.map,n(t.map,e.uvTransform));t.alphaMap&&(e.alphaMap.value=t.alphaMap,n(t.alphaMap,e.alphaMapTransform));t.alphaTest>0&&(e.alphaTest.value=t.alphaTest)}(e,r,a,o):r.isSpriteMaterial?function(e,t){e.diffuse.value.copy(t.color),e.opacity.value=t.opacity,e.rotation.value=t.rotation,t.map&&(e.map.value=t.map,n(t.map,e.mapTransform));t.alphaMap&&(e.alphaMap.value=t.alphaMap,n(t.alphaMap,e.alphaMapTransform));t.alphaTest>0&&(e.alphaTest.value=t.alphaTest)}(e,r):r.isShadowMaterial?(e.color.value.copy(r.color),e.opacity.value=r.opacity):r.isShaderMaterial&&(r.uniformsNeedUpdate=!1)}}}function ua(e,t,n,i){let r={},a={},o=[];const s=e.getParameter(e.MAX_UNIFORM_BUFFER_BINDINGS);function l(e,t,n,i){const r=e.value,a=t+"_"+n;if(void 0===i[a])return i[a]="number"==typeof r||"boolean"==typeof r?r:r.clone(),!0;{const e=i[a];if("number"==typeof r||"boolean"==typeof r){if(e!==r)return i[a]=r,!0}else if(!1===e.equals(r))return e.copy(r),!0}return!1}function c(e){const t={boundary:0,storage:0};return"number"==typeof e||"boolean"==typeof e?(t.boundary=4,t.storage=4):e.isVector2?(t.boundary=8,t.storage=8):e.isVector3||e.isColor?(t.boundary=16,t.storage=12):e.isVector4?(t.boundary=16,t.storage=16):e.isMatrix3?(t.boundary=48,t.storage=48):e.isMatrix4?(t.boundary=64,t.storage=64):e.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",e),t}function d(t){const n=t.target;n.removeEventListener("dispose",d);const i=o.indexOf(n.__bindingPointIndex);o.splice(i,1),e.deleteBuffer(r[n.id]),delete r[n.id],delete a[n.id]}return{bind:function(e,t){const n=t.program;i.uniformBlockBinding(e,n)},update:function(n,u){let f=r[n.id];void 0===f&&(!function(e){const t=e.uniforms;let n=0;const i=16;for(let e=0,r=t.length;e0&&(n+=i-r);e.__size=n,e.__cache={}}(n),f=function(t){const n=function(){for(let e=0;e0),u=!!n.morphAttributes.position,f=!!n.morphAttributes.normal,p=!!n.morphAttributes.color;let m=U;i.toneMapped&&(null!==D&&!0!==D.isXRRenderTarget||(m=C.toneMapping));const h=n.morphAttributes.position||n.morphAttributes.normal||n.morphAttributes.color,_=void 0!==h?h.length:0,g=fe.get(i),v=R.state.lights;if(!0===J&&(!0===ee||e!==N)){const t=e===N&&i.id===y;Ae.setState(i,e,t)}let E=!1;i.version===g.__version?g.needsLights&&g.lightsStateVersion!==v.state.version||g.outputColorSpace!==s||r.isBatchedMesh&&!1===g.batching?E=!0:r.isBatchedMesh||!0!==g.batching?r.isBatchedMesh&&!0===g.batchingColor&&null===r.colorTexture||r.isBatchedMesh&&!1===g.batchingColor&&null!==r.colorTexture||r.isInstancedMesh&&!1===g.instancing?E=!0:r.isInstancedMesh||!0!==g.instancing?r.isSkinnedMesh&&!1===g.skinning?E=!0:r.isSkinnedMesh||!0!==g.skinning?r.isInstancedMesh&&!0===g.instancingColor&&null===r.instanceColor||r.isInstancedMesh&&!1===g.instancingColor&&null!==r.instanceColor||r.isInstancedMesh&&!0===g.instancingMorph&&null===r.morphTexture||r.isInstancedMesh&&!1===g.instancingMorph&&null!==r.morphTexture||g.envMap!==l||!0===i.fog&&g.fog!==a?E=!0:void 0===g.numClippingPlanes||g.numClippingPlanes===Ae.numPlanes&&g.numIntersection===Ae.numIntersection?(g.vertexAlphas!==c||g.vertexTangents!==d||g.morphTargets!==u||g.morphNormals!==f||g.morphColors!==p||g.toneMapping!==m||g.morphTargetsCount!==_)&&(E=!0):E=!0:E=!0:E=!0:E=!0:(E=!0,g.__version=i.version);let S=g.currentProgram;!0===E&&(S=Qe(i,t,r));let T=!1,M=!1,x=!1;const A=S.getUniforms(),b=g.uniforms;de.useProgram(S.program)&&(T=!0,M=!0,x=!0);i.id!==y&&(y=i.id,M=!0);if(T||N!==e){de.buffers.depth.getReversed()?(te.copy(e.projectionMatrix),An(te),bn(te),A.setValue(Ie,"projectionMatrix",te)):A.setValue(Ie,"projectionMatrix",e.projectionMatrix),A.setValue(Ie,"viewMatrix",e.matrixWorldInverse);const t=A.map.cameraPosition;void 0!==t&&t.setValue(Ie,ie.setFromMatrixPosition(e.matrixWorld)),ce.logarithmicDepthBuffer&&A.setValue(Ie,"logDepthBufFC",2/(Math.log(e.far+1)/Math.LN2)),(i.isMeshPhongMaterial||i.isMeshToonMaterial||i.isMeshLambertMaterial||i.isMeshBasicMaterial||i.isMeshStandardMaterial||i.isShaderMaterial)&&A.setValue(Ie,"isOrthographic",!0===e.isOrthographicCamera),N!==e&&(N=e,M=!0,x=!0)}if(r.isSkinnedMesh){A.setOptional(Ie,r,"bindMatrix"),A.setOptional(Ie,r,"bindMatrixInverse");const e=r.skeleton;e&&(null===e.boneTexture&&e.computeBoneTexture(),A.setValue(Ie,"boneTexture",e.boneTexture,pe))}r.isBatchedMesh&&(A.setOptional(Ie,r,"batchingTexture"),A.setValue(Ie,"batchingTexture",r._matricesTexture,pe),A.setOptional(Ie,r,"batchingIdTexture"),A.setValue(Ie,"batchingIdTexture",r._indirectTexture,pe),A.setOptional(Ie,r,"batchingColorTexture"),null!==r._colorsTexture&&A.setValue(Ie,"batchingColorTexture",r._colorsTexture,pe));const L=n.morphAttributes;void 0===L.position&&void 0===L.normal&&void 0===L.color||Le.update(r,n,S);(M||g.receiveShadow!==r.receiveShadow)&&(g.receiveShadow=r.receiveShadow,A.setValue(Ie,"receiveShadow",r.receiveShadow));i.isMeshGouraudMaterial&&null!==i.envMap&&(b.envMap.value=l,b.flipEnvMap.value=l.isCubeTexture&&!1===l.isRenderTargetTexture?-1:1);i.isMeshStandardMaterial&&null===i.envMap&&null!==t.environment&&(b.envMapIntensity.value=t.environmentIntensity);M&&(A.setValue(Ie,"toneMappingExposure",C.toneMappingExposure),g.needsLights&&(w=x,(P=b).ambientLightColor.needsUpdate=w,P.lightProbe.needsUpdate=w,P.directionalLights.needsUpdate=w,P.directionalLightShadows.needsUpdate=w,P.pointLights.needsUpdate=w,P.pointLightShadows.needsUpdate=w,P.spotLights.needsUpdate=w,P.spotLightShadows.needsUpdate=w,P.rectAreaLights.needsUpdate=w,P.hemisphereLights.needsUpdate=w),a&&!0===i.fog&&Me.refreshFogUniforms(b,a),Me.refreshMaterialUniforms(b,i,Y,X,R.state.transmissionRenderTarget[e.id]),gr.upload(Ie,Je(g),b,pe));var P,w;i.isShaderMaterial&&!0===i.uniformsNeedUpdate&&(gr.upload(Ie,Je(g),b,pe),i.uniformsNeedUpdate=!1);i.isSpriteMaterial&&A.setValue(Ie,"center",r.center);if(A.setValue(Ie,"modelViewMatrix",r.modelViewMatrix),A.setValue(Ie,"normalMatrix",r.normalMatrix),A.setValue(Ie,"modelMatrix",r.matrixWorld),i.isShaderMaterial||i.isRawShaderMaterial){const e=i.uniformsGroups;for(let t=0,n=e.length;t{function n(){i.forEach((function(e){fe.get(e).currentProgram.isReady()&&i.delete(e)})),0!==i.size?setTimeout(n,10):t(e)}null!==le.get("KHR_parallel_shader_compile")?n():setTimeout(n,10)}))};let ke=null;function We(){Ye.stop()}function Xe(){Ye.start()}const Ye=new Pn;function je(e,t,n,i){if(!1===e.visible)return;if(e.layers.test(t.layers))if(e.isGroup)n=e.renderOrder;else if(e.isLOD)!0===e.autoUpdate&&e.update(t);else if(e.isLight)R.pushLight(e),e.castShadow&&R.pushShadow(e);else if(e.isSprite){if(!e.frustumCulled||Q.intersectsSprite(e)){i&&re.setFromMatrixPosition(e.matrixWorld).applyMatrix4(ne);const t=Se.update(e),r=e.material;r.visible&&x.push(e,t,r,n,re.z,null)}}else if((e.isMesh||e.isLine||e.isPoints)&&(!e.frustumCulled||Q.intersectsObject(e))){const t=Se.update(e),r=e.material;if(i&&(void 0!==e.boundingSphere?(null===e.boundingSphere&&e.computeBoundingSphere(),re.copy(e.boundingSphere.center)):(null===t.boundingSphere&&t.computeBoundingSphere(),re.copy(t.boundingSphere.center)),re.applyMatrix4(e.matrixWorld).applyMatrix4(ne)),Array.isArray(r)){const i=t.groups;for(let a=0,o=i.length;a0&&Ze(r,t,n),a.length>0&&Ze(a,t,n),o.length>0&&Ze(o,t,n),de.buffers.depth.setTest(!0),de.buffers.depth.setMask(!0),de.buffers.color.setMask(!0),de.setPolygonOffset(!1)}function qe(e,t,n,i){if(null!==(!0===n.isScene?n.overrideMaterial:null))return;void 0===R.state.transmissionRenderTarget[i.id]&&(R.state.transmissionRenderTarget[i.id]=new I(1,1,{generateMipmaps:!0,type:le.has("EXT_color_buffer_half_float")||le.has("EXT_color_buffer_float")?S:T,minFilter:ct,samples:4,stencilBuffer:o,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:u.workingColorSpace}));const r=R.state.transmissionRenderTarget[i.id],a=i.viewport||O;r.setSize(a.z*C.transmissionResolutionScale,a.w*C.transmissionResolutionScale);const s=C.getRenderTarget();C.setRenderTarget(r),C.getClearColor(V),z=C.getClearAlpha(),z<1&&C.setClearColor(16777215,.5),C.clear(),oe&&Ce.render(n);const l=C.toneMapping;C.toneMapping=U;const c=i.viewport;if(void 0!==i.viewport&&(i.viewport=void 0),R.setupLightsView(i),!0===J&&Ae.setGlobalState(C.clippingPlanes,i),Ze(e,n,i),pe.updateMultisampleRenderTarget(r),pe.updateRenderTargetMipmap(r),!1===le.has("WEBGL_multisampled_render_to_texture")){let e=!1;for(let r=0,a=t.length;r0)for(let t=0,a=n.length;t0&&qe(i,r,e,t),oe&&Ce.render(e),Ke(x,e,t);null!==D&&0===w&&(pe.updateMultisampleRenderTarget(D),pe.updateRenderTargetMipmap(D)),!0===e.isScene&&e.onAfterRender(C,e,t),De.resetDefaultState(),y=-1,N=null,b.pop(),b.length>0?(R=b[b.length-1],!0===J&&Ae.setGlobalState(C.clippingPlanes,R.state.camera)):R=null,A.pop(),x=A.length>0?A[A.length-1]:null},this.getActiveCubeFace=function(){return P},this.getActiveMipmapLevel=function(){return w},this.getRenderTarget=function(){return D},this.setRenderTargetTextures=function(e,t,n){fe.get(e.texture).__webglTexture=t,fe.get(e.depthTexture).__webglTexture=n;const i=fe.get(e);i.__hasExternalTextures=!0,i.__autoAllocateDepthBuffer=void 0===n,i.__autoAllocateDepthBuffer||!0===le.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(e,t){const n=fe.get(e);n.__webglFramebuffer=t,n.__useDefaultFramebuffer=void 0===t};const tt=Ie.createFramebuffer();this.setRenderTarget=function(e,t=0,n=0){D=e,P=t,w=n;let i=!0,r=null,a=!1,o=!1;if(e){const s=fe.get(e);if(void 0!==s.__useDefaultFramebuffer)de.bindFramebuffer(Ie.FRAMEBUFFER,null),i=!1;else if(void 0===s.__webglFramebuffer)pe.setupRenderTarget(e);else if(s.__hasExternalTextures)pe.rebindTextures(e,fe.get(e.texture).__webglTexture,fe.get(e.depthTexture).__webglTexture);else if(e.depthBuffer){const t=e.depthTexture;if(s.__boundDepthTexture!==t){if(null!==t&&fe.has(t)&&(e.width!==t.image.width||e.height!==t.image.height))throw new Error("WebGLRenderTarget: Attached DepthTexture is initialized to the incorrect size.");pe.setupDepthRenderbuffer(e)}}const l=e.texture;(l.isData3DTexture||l.isDataArrayTexture||l.isCompressedArrayTexture)&&(o=!0);const c=fe.get(e).__webglFramebuffer;e.isWebGLCubeRenderTarget?(r=Array.isArray(c[t])?c[t][n]:c[t],a=!0):r=e.samples>0&&!1===pe.useMultisampledRTT(e)?fe.get(e).__webglMultisampledFramebuffer:Array.isArray(c)?c[n]:c,O.copy(e.viewport),F.copy(e.scissor),G=e.scissorTest}else O.copy(q).multiplyScalar(Y).floor(),F.copy(Z).multiplyScalar(Y).floor(),G=$;0!==n&&(r=tt);if(de.bindFramebuffer(Ie.FRAMEBUFFER,r)&&i&&de.drawBuffers(e,r),de.viewport(O),de.scissor(F),de.setScissorTest(G),a){const i=fe.get(e.texture);Ie.framebufferTexture2D(Ie.FRAMEBUFFER,Ie.COLOR_ATTACHMENT0,Ie.TEXTURE_CUBE_MAP_POSITIVE_X+t,i.__webglTexture,n)}else if(o){const i=fe.get(e.texture),r=t;Ie.framebufferTextureLayer(Ie.FRAMEBUFFER,Ie.COLOR_ATTACHMENT0,i.__webglTexture,n,r)}else if(null!==e&&0!==n){const t=fe.get(e.texture);Ie.framebufferTexture2D(Ie.FRAMEBUFFER,Ie.COLOR_ATTACHMENT0,Ie.TEXTURE_2D,t.__webglTexture,n)}y=-1},this.readRenderTargetPixels=function(e,t,n,i,r,a,o){if(!e||!e.isWebGLRenderTarget)return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let s=fe.get(e).__webglFramebuffer;if(e.isWebGLCubeRenderTarget&&void 0!==o&&(s=s[o]),s){de.bindFramebuffer(Ie.FRAMEBUFFER,s);try{const o=e.texture,s=o.format,l=o.type;if(!ce.textureFormatReadable(s))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");if(!ce.textureTypeReadable(l))return void console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");t>=0&&t<=e.width-i&&n>=0&&n<=e.height-r&&Ie.readPixels(t,n,i,r,we.convert(s),we.convert(l),a)}finally{const e=null!==D?fe.get(D).__webglFramebuffer:null;de.bindFramebuffer(Ie.FRAMEBUFFER,e)}}},this.readRenderTargetPixelsAsync=async function(e,t,n,i,r,a,o){if(!e||!e.isWebGLRenderTarget)throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let s=fe.get(e).__webglFramebuffer;if(e.isWebGLCubeRenderTarget&&void 0!==o&&(s=s[o]),s){const o=e.texture,l=o.format,c=o.type;if(!ce.textureFormatReadable(l))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!ce.textureTypeReadable(c))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");if(t>=0&&t<=e.width-i&&n>=0&&n<=e.height-r){de.bindFramebuffer(Ie.FRAMEBUFFER,s);const e=Ie.createBuffer();Ie.bindBuffer(Ie.PIXEL_PACK_BUFFER,e),Ie.bufferData(Ie.PIXEL_PACK_BUFFER,a.byteLength,Ie.STREAM_READ),Ie.readPixels(t,n,i,r,we.convert(l),we.convert(c),0);const o=null!==D?fe.get(D).__webglFramebuffer:null;de.bindFramebuffer(Ie.FRAMEBUFFER,o);const d=Ie.fenceSync(Ie.SYNC_GPU_COMMANDS_COMPLETE,0);return Ie.flush(),await Cn(Ie,d,4),Ie.bindBuffer(Ie.PIXEL_PACK_BUFFER,e),Ie.getBufferSubData(Ie.PIXEL_PACK_BUFFER,0,a),Ie.deleteBuffer(e),Ie.deleteSync(d),a}throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")}},this.copyFramebufferToTexture=function(e,t=null,n=0){!0!==e.isTexture&&(H("WebGLRenderer: copyFramebufferToTexture function signature has changed."),t=arguments[0]||null,e=arguments[1]);const i=Math.pow(2,-n),r=Math.floor(e.image.width*i),a=Math.floor(e.image.height*i),o=null!==t?t.x:0,s=null!==t?t.y:0;pe.setTexture2D(e,0),Ie.copyTexSubImage2D(Ie.TEXTURE_2D,n,0,0,o,s,r,a),de.unbindTexture()};const nt=Ie.createFramebuffer(),it=Ie.createFramebuffer();this.copyTextureToTexture=function(e,t,n=null,i=null,r=0,a=null){let o,s,l,c,d,u,f,p,m;!0!==e.isTexture&&(H("WebGLRenderer: copyTextureToTexture function signature has changed."),i=arguments[0]||null,e=arguments[1],t=arguments[2],a=arguments[3]||0,n=null),null===a&&(0!==r?(H("WebGLRenderer: copyTextureToTexture function signature has changed to support src and dst mipmap levels."),a=r,r=0):a=0);const h=e.isCompressedTexture?e.mipmaps[a]:e.image;if(null!==n)o=n.max.x-n.min.x,s=n.max.y-n.min.y,l=n.isBox3?n.max.z-n.min.z:1,c=n.min.x,d=n.min.y,u=n.isBox3?n.min.z:0;else{const t=Math.pow(2,-r);o=Math.floor(h.width*t),s=Math.floor(h.height*t),l=e.isDataArrayTexture?h.depth:e.isData3DTexture?Math.floor(h.depth*t):1,c=0,d=0,u=0}null!==i?(f=i.x,p=i.y,m=i.z):(f=0,p=0,m=0);const _=we.convert(t.format),g=we.convert(t.type);let v;t.isData3DTexture?(pe.setTexture3D(t,0),v=Ie.TEXTURE_3D):t.isDataArrayTexture||t.isCompressedArrayTexture?(pe.setTexture2DArray(t,0),v=Ie.TEXTURE_2D_ARRAY):(pe.setTexture2D(t,0),v=Ie.TEXTURE_2D),Ie.pixelStorei(Ie.UNPACK_FLIP_Y_WEBGL,t.flipY),Ie.pixelStorei(Ie.UNPACK_PREMULTIPLY_ALPHA_WEBGL,t.premultiplyAlpha),Ie.pixelStorei(Ie.UNPACK_ALIGNMENT,t.unpackAlignment);const E=Ie.getParameter(Ie.UNPACK_ROW_LENGTH),S=Ie.getParameter(Ie.UNPACK_IMAGE_HEIGHT),T=Ie.getParameter(Ie.UNPACK_SKIP_PIXELS),M=Ie.getParameter(Ie.UNPACK_SKIP_ROWS),x=Ie.getParameter(Ie.UNPACK_SKIP_IMAGES);Ie.pixelStorei(Ie.UNPACK_ROW_LENGTH,h.width),Ie.pixelStorei(Ie.UNPACK_IMAGE_HEIGHT,h.height),Ie.pixelStorei(Ie.UNPACK_SKIP_PIXELS,c),Ie.pixelStorei(Ie.UNPACK_SKIP_ROWS,d),Ie.pixelStorei(Ie.UNPACK_SKIP_IMAGES,u);const R=e.isDataArrayTexture||e.isData3DTexture,A=t.isDataArrayTexture||t.isData3DTexture;if(e.isDepthTexture){const n=fe.get(e),i=fe.get(t),h=fe.get(n.__renderTarget),_=fe.get(i.__renderTarget);de.bindFramebuffer(Ie.READ_FRAMEBUFFER,h.__webglFramebuffer),de.bindFramebuffer(Ie.DRAW_FRAMEBUFFER,_.__webglFramebuffer);for(let n=0;n} + */ this.renderObjects = new WeakMap(); + + /** + * Whether the material uses node objects or not. + * + * @type {Boolean} + */ this.hasNode = this.containsNode( builder ); + + /** + * Whether the node builder's 3D object is animated or not. + * + * @type {Boolean} + */ this.hasAnimation = builder.object.isSkinnedMesh === true; + + /** + * A list of all possible material uniforms + * + * @type {Array} + */ this.refreshUniforms = refreshUniforms; + + /** + * Holds the current render ID from the node frame. + * + * @type {Number} + * @default 0 + */ this.renderId = 0; } + /** + * Returns `true` if the given render object is verified for the first time of this observer. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object is verified for the first time of this observer. + */ firstInitialization( renderObject ) { const hasInitialized = this.renderObjects.has( renderObject ); @@ -87,6 +134,12 @@ class NodeMaterialObserver { } + /** + * Returns monitoring data for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Object} The monitoring data. + */ getRenderObjectData( renderObject ) { let data = this.renderObjects.get( renderObject ); @@ -140,6 +193,13 @@ class NodeMaterialObserver { } + /** + * Returns an attribute data structure holding the attributes versions for + * monitoring. + * + * @param {Object} attributes - The geometry attributes. + * @return {Object} An object for monitoring the versions of attributes. + */ getAttributesData( attributes ) { const attributesData = {}; @@ -158,6 +218,13 @@ class NodeMaterialObserver { } + /** + * Returns `true` if the node builder's material uses + * node properties. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Boolean} Whether the node builder's material uses node properties or not. + */ containsNode( builder ) { const material = builder.material; @@ -176,6 +243,13 @@ class NodeMaterialObserver { } + /** + * Returns a material data structure holding the material property values for + * monitoring. + * + * @param {Material} material - The material. + * @return {Object} An object for monitoring material properties. + */ getMaterialData( material ) { const data = {}; @@ -210,6 +284,12 @@ class NodeMaterialObserver { } + /** + * Returns `true` if the given render object has not changed its state. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object has changed its state or not. + */ equals( renderObject ) { const { object, material, geometry } = renderObject; @@ -390,6 +470,13 @@ class NodeMaterialObserver { } + /** + * Checks if the given render object requires a refresh. + * + * @param {RenderObject} renderObject - The render object. + * @param {NodeFrame} nodeFrame - The current node frame. + * @return {Boolean} Whether the given render object requires a refresh or not. + */ needsRefresh( renderObject, nodeFrame ) { if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) ) @@ -509,7 +596,7 @@ function getCacheKey$1( object, force = false ) { for ( const { property, childNode } of getNodeChildren( object ) ) { - values.push( values, cyrb53( property.slice( 0, - 4 ) ), childNode.getCacheKey( force ) ); + values.push( cyrb53( property.slice( 0, - 4 ) ), childNode.getCacheKey( force ) ); } @@ -582,6 +669,8 @@ const typeFromLength = /*@__PURE__*/ new Map( [ [ 16, 'mat4' ] ] ); +const dataFromObject = /*@__PURE__*/ new WeakMap(); + /** * Returns the data type for the given the length. * @@ -595,6 +684,39 @@ function getTypeFromLength( length ) { } +/** + * Returns the typed array for the given data type. + * + * @method + * @param {String} type - The data type. + * @return {TypedArray} The typed array. + */ +function getTypedArrayFromType( type ) { + + // Handle component type for vectors and matrices + if ( /[iu]?vec\d/.test( type ) ) { + + // Handle int vectors + if ( type.startsWith( 'ivec' ) ) return Int32Array; + // Handle uint vectors + if ( type.startsWith( 'uvec' ) ) return Uint32Array; + // Default to float vectors + return Float32Array; + + } + + // Handle matrices (always float) + if ( /mat\d/.test( type ) ) return Float32Array; + + // Basic types + if ( /float/.test( type ) ) return Float32Array; + if ( /uint/.test( type ) ) return Uint32Array; + if ( /int/.test( type ) ) return Int32Array; + + throw new Error( `THREE.NodeUtils: Unsupported type: ${type}` ); + +} + /** * Returns the length for the given data type. * @@ -748,6 +870,27 @@ function getValueFromType( type, ...params ) { } +/** + * Gets the object data that can be shared between different rendering steps. + * + * @param {Object} object - The object to get the data for. + * @return {Object} The object data. + */ +function getDataFromObject( object ) { + + let data = dataFromObject.get( object ); + + if ( data === undefined ) { + + data = {}; + dataFromObject.set( object, data ); + + } + + return data; + +} + /** * Converts the given array buffer to a Base64 string. * @@ -789,9 +932,11 @@ var NodeUtils = /*#__PURE__*/Object.freeze({ arrayBufferToBase64: arrayBufferToBase64, base64ToArrayBuffer: base64ToArrayBuffer, getCacheKey: getCacheKey$1, + getDataFromObject: getDataFromObject, getLengthFromType: getLengthFromType, getNodeChildren: getNodeChildren, getTypeFromLength: getTypeFromLength, + getTypedArrayFromType: getTypedArrayFromType, getValueFromType: getValueFromType, getValueType: getValueType, hash: hash$1, @@ -799,6 +944,8 @@ var NodeUtils = /*#__PURE__*/Object.freeze({ hashString: hashString }); +/** @module NodeConstants **/ + /** * Possible shader stages. * @@ -1338,8 +1485,9 @@ class Node extends EventDispatcher { } - // return a outputNode if exists - return null; + // return a outputNode if exists or null + + return nodeProperties.outputNode || null; } @@ -1473,12 +1621,19 @@ class Node extends EventDispatcher { if ( properties.initialized !== true ) { - const stackNodesBeforeSetup = builder.stack.nodes.length; + //const stackNodesBeforeSetup = builder.stack.nodes.length; properties.initialized = true; - properties.outputNode = this.setup( builder ); - if ( properties.outputNode !== null && builder.stack.nodes.length !== stackNodesBeforeSetup ) ; + const outputNode = this.setup( builder ); // return a node or null + const isNodeOutput = outputNode && outputNode.isNode === true; + + /*if ( isNodeOutput && builder.stack.nodes.length !== stackNodesBeforeSetup ) { + + // !! no outputNode !! + //outputNode = builder.stack; + + }*/ for ( const childNode of Object.values( properties ) ) { @@ -1490,6 +1645,14 @@ class Node extends EventDispatcher { } + if ( isNodeOutput ) { + + outputNode.build( builder ); + + } + + properties.outputNode = outputNode; + } } else if ( buildStage === 'analyze' ) { @@ -1736,7 +1899,7 @@ class ArrayElementNode extends Node { // @TODO: If extending from TempNode it br } /** - * Constructs array element node. + * Constructs an array element node. * * @param {Node} node - The array-like node. * @param {Node} indexNode - The index node that defines the element access. @@ -2618,7 +2781,7 @@ class ConstNode extends InputNode { } -// +/** @module TSLCore **/ let currentStack = null; @@ -2915,7 +3078,7 @@ class ShaderCallNodeInternal extends Node { } else { const jsFunc = shaderNode.jsFunc; - const outputNode = inputNodes !== null ? jsFunc( inputNodes, builder ) : jsFunc( builder ); + const outputNode = inputNodes !== null || jsFunc.length > 1 ? jsFunc( inputNodes || [], builder ) : jsFunc( builder ); result = nodeObject( outputNode ); @@ -3163,6 +3326,13 @@ const Fn = ( jsFunc, nodeType ) => { }; +/** + * @function + * @deprecated since r168. Use {@link Fn} instead. + * + * @param {...any} params + * @returns {Function} + */ const tslFn = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.ShaderNode: tslFn() has been renamed to Fn().' ); @@ -3263,6 +3433,8 @@ const split = ( node, channels ) => nodeObject( new SplitNode( nodeObject( node addMethodChaining( 'element', element ); addMethodChaining( 'convert', convert ); +/** @module UniformGroupNode **/ + /** * This node can be used to group single instances of {@link UniformNode} * and manage them as a uniform buffer. @@ -3352,13 +3524,48 @@ class UniformGroupNode extends Node { } +/** + * TSL function for creating a uniform group node with the given name. + * + * @function + * @param {String} name - The name of the uniform group node. + * @returns {UniformGroupNode} + */ const uniformGroup = ( name ) => new UniformGroupNode( name ); + +/** + * TSL function for creating a shared uniform group node with the given name and order. + * + * @function + * @param {String} name - The name of the uniform group node. + * @param {Number} [order=0] - Influences the internal sorting. + * @returns {UniformGroupNode} + */ const sharedUniformGroup = ( name, order = 0 ) => new UniformGroupNode( name, true, order ); +/** + * TSL object that represents a shared uniform group node which is updated once per frame. + * + * @type {UniformGroupNode} + */ const frameGroup = /*@__PURE__*/ sharedUniformGroup( 'frame' ); + +/** + * TSL object that represents a shared uniform group node which is updated once per render. + * + * @type {UniformGroupNode} + */ const renderGroup = /*@__PURE__*/ sharedUniformGroup( 'render' ); + +/** + * TSL object that represents a uniform group node which is updated once per object. + * + * @type {UniformGroupNode} + */ const objectGroup = /*@__PURE__*/ uniformGroup( 'object' ); +/** @module UniformNode **/ + /** * Class for representing a uniform. * @@ -3511,6 +3718,14 @@ class UniformNode extends InputNode { } +/** + * TSL function for creating a uniform node. + * + * @function + * @param {Any} arg1 - The value of this node. Usually a JS primitive or three.js object (vector, matrix, color, texture). + * @param {String?} arg2 - The node type. If no explicit type is defined, the node tries to derive the type from its value. + * @returns {UniformNode} + */ const uniform = ( arg1, arg2 ) => { const nodeType = getConstNodeType( arg2 || arg1 ); @@ -3522,8 +3737,10 @@ const uniform = ( arg1, arg2 ) => { }; +/** @module PropertyNode **/ + /** - * This class represents a shader property. It can be used on + * This class represents a shader property. It can be used * to explicitly define a property and assign a value to it. * * ```js @@ -3620,38 +3837,224 @@ class PropertyNode extends Node { } +/** + * TSL function for creating a property node. + * + * @function + * @param {String} type - The type of the node. + * @param {String?} [name=null] - The name of the property in the shader. + * @returns {PropertyNode} + */ const property = ( type, name ) => nodeObject( new PropertyNode( type, name ) ); + +/** + * TSL function for creating a varying property node. + * + * @function + * @param {String} type - The type of the node. + * @param {String?} [name=null] - The name of the varying in the shader. + * @returns {PropertyNode} + */ const varyingProperty = ( type, name ) => nodeObject( new PropertyNode( type, name, true ) ); +/** + * TSL object that represents the shader variable `DiffuseColor`. + * + * @type {PropertyNode} + */ const diffuseColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'DiffuseColor' ); + +/** + * TSL object that represents the shader variable `EmissiveColor`. + * + * @type {PropertyNode} + */ const emissive = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'EmissiveColor' ); + +/** + * TSL object that represents the shader variable `Roughness`. + * + * @type {PropertyNode} + */ const roughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Roughness' ); + +/** + * TSL object that represents the shader variable `Metalness`. + * + * @type {PropertyNode} + */ const metalness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Metalness' ); + +/** + * TSL object that represents the shader variable `Clearcoat`. + * + * @type {PropertyNode} + */ const clearcoat = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Clearcoat' ); + +/** + * TSL object that represents the shader variable `ClearcoatRoughness`. + * + * @type {PropertyNode} + */ const clearcoatRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'ClearcoatRoughness' ); + +/** + * TSL object that represents the shader variable `Sheen`. + * + * @type {PropertyNode} + */ const sheen = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'Sheen' ); + +/** + * TSL object that represents the shader variable `SheenRoughness`. + * + * @type {PropertyNode} + */ const sheenRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SheenRoughness' ); + +/** + * TSL object that represents the shader variable `Iridescence`. + * + * @type {PropertyNode} + */ const iridescence = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Iridescence' ); + +/** + * TSL object that represents the shader variable `IridescenceIOR`. + * + * @type {PropertyNode} + */ const iridescenceIOR = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceIOR' ); + +/** + * TSL object that represents the shader variable `IridescenceThickness`. + * + * @type {PropertyNode} + */ const iridescenceThickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceThickness' ); + +/** + * TSL object that represents the shader variable `AlphaT`. + * + * @type {PropertyNode} + */ const alphaT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AlphaT' ); + +/** + * TSL object that represents the shader variable `Anisotropy`. + * + * @type {PropertyNode} + */ const anisotropy = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Anisotropy' ); + +/** + * TSL object that represents the shader variable `AnisotropyT`. + * + * @type {PropertyNode} + */ const anisotropyT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyT' ); + +/** + * TSL object that represents the shader variable `AnisotropyB`. + * + * @type {PropertyNode} + */ const anisotropyB = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyB' ); + +/** + * TSL object that represents the shader variable `SpecularColor`. + * + * @type {PropertyNode} + */ const specularColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'SpecularColor' ); + +/** + * TSL object that represents the shader variable `SpecularF90`. + * + * @type {PropertyNode} + */ const specularF90 = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SpecularF90' ); + +/** + * TSL object that represents the shader variable `Shininess`. + * + * @type {PropertyNode} + */ const shininess = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Shininess' ); + +/** + * TSL object that represents the shader variable `Output`. + * + * @type {PropertyNode} + */ const output = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'Output' ); + +/** + * TSL object that represents the shader variable `dashSize`. + * + * @type {PropertyNode} + */ const dashSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'dashSize' ); + +/** + * TSL object that represents the shader variable `gapSize`. + * + * @type {PropertyNode} + */ const gapSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'gapSize' ); + +/** + * TSL object that represents the shader variable `pointWidth`. + * + * @type {PropertyNode} + */ const pointWidth = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'pointWidth' ); + +/** + * TSL object that represents the shader variable `IOR`. + * + * @type {PropertyNode} + */ const ior = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IOR' ); + +/** + * TSL object that represents the shader variable `Transmission`. + * + * @type {PropertyNode} + */ const transmission = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Transmission' ); + +/** + * TSL object that represents the shader variable `Thickness`. + * + * @type {PropertyNode} + */ const thickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Thickness' ); + +/** + * TSL object that represents the shader variable `AttenuationDistance`. + * + * @type {PropertyNode} + */ const attenuationDistance = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AttenuationDistance' ); + +/** + * TSL object that represents the shader variable `AttenuationColor`. + * + * @type {PropertyNode} + */ const attenuationColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'AttenuationColor' ); + +/** + * TSL object that represents the shader variable `Dispersion`. + * + * @type {PropertyNode} + */ const dispersion = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Dispersion' ); +/** @module AssignNode **/ + /** * These node represents an assign operation. Meaning a node is assigned * to another node. @@ -3810,6 +4213,14 @@ class AssignNode extends TempNode { } +/** + * TSL function for creating an assign node. + * + * @function + * @param {Node} targetNode - The target node. + * @param {Node} sourceNode - The source type. + * @returns {AssignNode} + */ const assign = /*@__PURE__*/ nodeProxy( AssignNode ); addMethodChaining( 'assign', assign ); @@ -3957,6 +4368,8 @@ const call = ( func, ...params ) => { addMethodChaining( 'call', call ); +/** @module OperatorNode **/ + /** * This node represents basic mathematical and logical operations like addition, * subtraction or comparisons (e.g. `equal()`). @@ -4019,6 +4432,15 @@ class OperatorNode extends TempNode { */ this.bNode = bNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isOperatorNode = true; + } /** @@ -4257,26 +4679,218 @@ class OperatorNode extends TempNode { } +/** + * Returns the addition of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ const add = /*@__PURE__*/ nodeProxy( OperatorNode, '+' ); + +/** + * Returns the subtraction of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ const sub = /*@__PURE__*/ nodeProxy( OperatorNode, '-' ); + +/** + * Returns the multiplication of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ const mul = /*@__PURE__*/ nodeProxy( OperatorNode, '*' ); + +/** + * Returns the division of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ const div = /*@__PURE__*/ nodeProxy( OperatorNode, '/' ); + +/** + * Computes the remainder of dividing the first node by the second, for integer values. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const modInt = /*@__PURE__*/ nodeProxy( OperatorNode, '%' ); + +/** + * Checks if two nodes are equal. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const equal = /*@__PURE__*/ nodeProxy( OperatorNode, '==' ); + +/** + * Checks if two nodes are not equal. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const notEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '!=' ); + +/** + * Checks if the first node is less than the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const lessThan = /*@__PURE__*/ nodeProxy( OperatorNode, '<' ); + +/** + * Checks if the first node is greater than the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const greaterThan = /*@__PURE__*/ nodeProxy( OperatorNode, '>' ); + +/** + * Checks if the first node is less than or equal to the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const lessThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '<=' ); + +/** + * Checks if the first node is greater than or equal to the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const greaterThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '>=' ); + +/** + * Performs logical AND on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const and = /*@__PURE__*/ nodeProxy( OperatorNode, '&&' ); + +/** + * Performs logical OR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const or = /*@__PURE__*/ nodeProxy( OperatorNode, '||' ); + +/** + * Performs logical NOT on a node. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const not = /*@__PURE__*/ nodeProxy( OperatorNode, '!' ); + +/** + * Performs logical XOR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const xor = /*@__PURE__*/ nodeProxy( OperatorNode, '^^' ); + +/** + * Performs bitwise AND on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const bitAnd = /*@__PURE__*/ nodeProxy( OperatorNode, '&' ); + +/** + * Performs bitwise NOT on a node. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const bitNot = /*@__PURE__*/ nodeProxy( OperatorNode, '~' ); + +/** + * Performs bitwise OR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const bitOr = /*@__PURE__*/ nodeProxy( OperatorNode, '|' ); + +/** + * Performs bitwise XOR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const bitXor = /*@__PURE__*/ nodeProxy( OperatorNode, '^' ); + +/** + * Shifts a node to the left. + * + * @function + * @param {Node} aNode - The node to shift. + * @param {Node} bNode - The value to shift. + * @returns {OperatorNode} + */ const shiftLeft = /*@__PURE__*/ nodeProxy( OperatorNode, '<<' ); + +/** + * Shifts a node to the right. + * + * @function + * @param {Node} aNode - The node to shift. + * @param {Node} bNode - The value to shift. + * @returns {OperatorNode} + */ const shiftRight = /*@__PURE__*/ nodeProxy( OperatorNode, '>>' ); addMethodChaining( 'add', add ); @@ -4301,7 +4915,13 @@ addMethodChaining( 'bitXor', bitXor ); addMethodChaining( 'shiftLeft', shiftLeft ); addMethodChaining( 'shiftRight', shiftRight ); - +/** + * @function + * @deprecated since r168. Use {@link modInt} instead. + * + * @param {...any} params + * @returns {Function} + */ const remainder = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.OperatorNode: .remainder() has been renamed to .modInt().' ); @@ -4311,6 +4931,8 @@ const remainder = ( ...params ) => { // @deprecated, r168 addMethodChaining( 'remainder', remainder ); +/** @module MathNode **/ + /** * This node represents a variety of mathematical methods available in shaders. * They are divided into three categories: @@ -4342,11 +4964,9 @@ class MathNode extends TempNode { super(); /** - * This flag can be used for type testing. + * The method name. * - * @type {Boolean} - * @readonly - * @default true + * @type {String} */ this.method = method; @@ -4373,6 +4993,15 @@ class MathNode extends TempNode { */ this.cNode = cNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isMathNode = true; + } /** @@ -4449,7 +5078,7 @@ class MathNode extends TempNode { generate( builder, output ) { - const method = this.method; + let method = this.method; const type = this.getNodeType( builder ); const inputType = this.getInputType( builder ); @@ -4458,7 +5087,7 @@ class MathNode extends TempNode { const b = this.bNode; const c = this.cNode; - const isWebGL = builder.renderer.isWebGLRenderer === true; + const coordinateSystem = builder.renderer.coordinateSystem; if ( method === MathNode.TRANSFORM_DIRECTION ) { @@ -4509,14 +5138,14 @@ class MathNode extends TempNode { b.build( builder, type ) ); - } else if ( isWebGL && method === MathNode.STEP ) { + } else if ( coordinateSystem === WebGLCoordinateSystem && 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 ) { + } else if ( ( coordinateSystem === WebGLCoordinateSystem && ( method === MathNode.MIN || method === MathNode.MAX ) ) || method === MathNode.MOD ) { params.push( a.build( builder, inputType ), @@ -4541,6 +5170,12 @@ class MathNode extends TempNode { } else { + if ( coordinateSystem === WebGPUCoordinateSystem && method === MathNode.ATAN && b !== null ) { + + method = 'atan2'; + + } + params.push( a.build( builder, inputType ) ); if ( b !== null ) params.push( b.build( builder, inputType ) ); if ( c !== null ) params.push( c.build( builder, inputType ) ); @@ -4575,7 +5210,6 @@ class MathNode extends TempNode { MathNode.ALL = 'all'; MathNode.ANY = 'any'; -MathNode.EQUALS = 'equals'; MathNode.RADIANS = 'radians'; MathNode.DEGREES = 'degrees'; @@ -4606,12 +5240,12 @@ MathNode.ROUND = 'round'; MathNode.RECIPROCAL = 'reciprocal'; MathNode.TRUNC = 'trunc'; MathNode.FWIDTH = 'fwidth'; -MathNode.BITCAST = 'bitcast'; MathNode.TRANSPOSE = 'transpose'; // 2 inputs -MathNode.ATAN2 = 'atan2'; +MathNode.BITCAST = 'bitcast'; +MathNode.EQUALS = 'equals'; MathNode.MIN = 'min'; MathNode.MAX = 'max'; MathNode.MOD = 'mod'; @@ -4632,72 +5266,574 @@ MathNode.REFRACT = 'refract'; MathNode.SMOOTHSTEP = 'smoothstep'; MathNode.FACEFORWARD = 'faceforward'; +// 1 inputs + +/** + * A small value used to handle floating-point precision errors. + * + * @type {Node} + */ const EPSILON = /*@__PURE__*/ float( 1e-6 ); + +/** + * Represents infinity. + * + * @type {Node} + */ const INFINITY = /*@__PURE__*/ float( 1e6 ); + +/** + * Represents PI. + * + * @type {Node} + */ const PI = /*@__PURE__*/ float( Math.PI ); + +/** + * Represents PI * 2. + * + * @type {Node} + */ const PI2 = /*@__PURE__*/ float( Math.PI * 2 ); +/** + * Returns `true` if all components of `x` are `true`. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const all = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ALL ); + +/** + * Returns `true` if any components of `x` are `true`. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const any = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ANY ); -const equals = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EQUALS ); +/** + * Converts a quantity in degrees to radians. + * + * @function + * @param {Node | Number} x - The input in degrees. + * @returns {Node} + */ const radians = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RADIANS ); + +/** + * Convert a quantity in radians to degrees. + * + * @function + * @param {Node | Number} x - The input in radians. + * @returns {Node} + */ const degrees = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DEGREES ); + +/** + * Returns the natural exponentiation of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const exp = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP ); + +/** + * Returns 2 raised to the power of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const exp2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP2 ); + +/** + * Returns the natural logarithm of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const log = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG ); + +/** + * Returns the base 2 logarithm of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const log2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG2 ); + +/** + * Returns the square root of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const sqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SQRT ); + +/** + * Returns the inverse of the square root of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const inverseSqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.INVERSE_SQRT ); + +/** + * Finds the nearest integer less than or equal to the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const floor = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FLOOR ); + +/** + * Finds the nearest integer that is greater than or equal to the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const ceil = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CEIL ); + +/** + * Calculates the unit vector in the same direction as the original vector. + * + * @function + * @param {Node} x - The input vector. + * @returns {Node} + */ const normalize = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NORMALIZE ); + +/** + * Computes the fractional part of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const fract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FRACT ); + +/** + * Returns the sine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const sin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIN ); + +/** + * Returns the cosine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const cos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.COS ); + +/** + * Returns the tangent of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const tan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TAN ); + +/** + * Returns the arcsine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const asin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ASIN ); + +/** + * Returns the arccosine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const acos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ACOS ); + +/** + * Returns the arc-tangent of the parameter. + * If two parameters are provided, the result is `atan2(y/x)`. + * + * @function + * @param {Node | Number} y - The y parameter. + * @param {(Node | Number)?} x - The x parameter. + * @returns {Node} + */ const atan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN ); + +/** + * Returns the absolute value of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const abs = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ABS ); + +/** + * Extracts the sign of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const sign = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIGN ); + +/** + * Calculates the length of a vector. + * + * @function + * @param {Node} x - The parameter. + * @returns {Node} + */ const length = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LENGTH ); + +/** + * Negates the value of the parameter (-x). + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const negate = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NEGATE ); + +/** + * Return `1` minus the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const oneMinus = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ONE_MINUS ); + +/** + * Returns the partial derivative of the parameter with respect to x. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const dFdx = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDX ); + +/** + * Returns the partial derivative of the parameter with respect to y. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const dFdy = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDY ); + +/** + * Rounds the parameter to the nearest integer. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const round = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ROUND ); + +/** + * Returns the reciprocal of the parameter `(1/x)`. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const reciprocal = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RECIPROCAL ); + +/** + * Truncates the parameter, removing the fractional part. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const trunc = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRUNC ); + +/** + * Returns the sum of the absolute derivatives in x and y. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const fwidth = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FWIDTH ); -const bitcast = /*@__PURE__*/ nodeProxy( MathNode, MathNode.BITCAST ); + +/** + * Returns the transpose of a matrix. + * + * @function + * @param {Node} x - The parameter. + * @returns {Node} + */ const transpose = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSPOSE ); -const atan2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN2 ); +// 2 inputs + +/** + * Reinterpret the bit representation of a value in one type as a value in another type. + * + * @function + * @param {Node | Number} x - The parameter. + * @param {String} y - The new type. + * @returns {Node} + */ +const bitcast = /*@__PURE__*/ nodeProxy( MathNode, MathNode.BITCAST ); + +/** + * Returns `true` if `x` equals `y`. + * + * @function + * @param {Node | Number} x - The first parameter. + * @param {Node | Number} y - The second parameter. + * @returns {Node} + */ +const equals = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EQUALS ); + +/** + * Returns the lesser of two values. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ const min$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIN ); + +/** + * Returns the greater of two values. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ const max$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MAX ); + +/** + * Computes the remainder of dividing the first node by the second one. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ const mod = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MOD ); + +/** + * Generate a step function by comparing two values. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ const step = /*@__PURE__*/ nodeProxy( MathNode, MathNode.STEP ); + +/** + * Calculates the reflection direction for an incident vector. + * + * @function + * @param {Node} I - The incident vector. + * @param {Node} N - The normal vector. + * @returns {Node} + */ const reflect = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFLECT ); + +/** + * Calculates the distance between two points. + * + * @function + * @param {Node} x - The first point. + * @param {Node} y - The second point. + * @returns {Node} + */ const distance = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DISTANCE ); + +/** + * Calculates the absolute difference between two values. + * + * @function + * @param {Node | Number} x - The first parameter. + * @param {Node | Number} y - The second parameter. + * @returns {Node} + */ const difference = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DIFFERENCE ); + +/** + * Calculates the dot product of two vectors. + * + * @function + * @param {Node} x - The first vector. + * @param {Node} y - The second vector. + * @returns {Node} + */ const dot = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DOT ); + +/** + * Calculates the cross product of two vectors. + * + * @function + * @param {Node} x - The first vector. + * @param {Node} y - The second vector. + * @returns {Node} + */ const cross = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CROSS ); + +/** + * Return the value of the first parameter raised to the power of the second one. + * + * @function + * @param {Node | Number} x - The first parameter. + * @param {Node | Number} y - The second parameter. + * @returns {Node} + */ const pow = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW ); + +/** + * Returns the square of the parameter. + * + * @function + * @param {Node | Number} x - The first parameter. + * @returns {Node} + */ const pow2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 2 ); + +/** + * Returns the cube of the parameter. + * + * @function + * @param {Node | Number} x - The first parameter. + * @returns {Node} + */ const pow3 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 3 ); + +/** + * Returns the fourth power of the parameter. + * + * @function + * @param {Node | Number} x - The first parameter. + * @returns {Node} + */ const pow4 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 4 ); + +/** + * Transforms the direction of a vector by a matrix and then normalizes the result. + * + * @function + * @param {Node} direction - The direction vector. + * @param {Node} matrix - The transformation matrix. + * @returns {Node} + */ const transformDirection = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSFORM_DIRECTION ); +/** + * Returns the cube root of a number. + * + * @function + * @param {Node | Number} a - The first parameter. + * @returns {Node} + */ const cbrt = ( a ) => mul( sign( a ), pow( abs( a ), 1.0 / 3.0 ) ); + +/** + * Calculate the squared length of a vector. + * + * @function + * @param {Node} a - The vector. + * @returns {Node} + */ const lengthSq = ( a ) => dot( a, a ); + +/** + * Linearly interpolates between two values. + * + * @function + * @param {Node | Number} a - The first parameter. + * @param {Node | Number} b - The second parameter. + * @param {Node | Number} t - The interpolation value. + * @returns {Node} + */ const mix = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIX ); + +/** + * Constrains a value to lie between two further values. + * + * @function + * @param {Node | Number} value - The value to constrain. + * @param {Node | Number} [low=0] - The lower bound. + * @param {Node | Number} [high=1] - The upper bound. + * @returns {Node} + */ const clamp = ( value, low = 0, high = 1 ) => nodeObject( new MathNode( MathNode.CLAMP, nodeObject( value ), nodeObject( low ), nodeObject( high ) ) ); + +/** + * Constrains a value between `0` and `1`. + * + * @function + * @param {Node | Number} value - The value to constrain. + * @returns {Node} + */ const saturate = ( value ) => clamp( value ); + +/** + * Calculates the refraction direction for an incident vector. + * + * @function + * @param {Node} I - The incident vector. + * @param {Node} N - The normal vector. + * @param {Node} eta - The the ratio of indices of refraction. + * @returns {Node} + */ const refract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFRACT ); + +/** + * Performs a Hermite interpolation between two values. + * + * @function + * @param {Node | Number} low - The value of the lower edge of the Hermite function. + * @param {Node | Number} high - The value of the upper edge of the Hermite function. + * @param {Node | Number} x - The source value for interpolation. + * @returns {Node} + */ const smoothstep = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SMOOTHSTEP ); + +/** + * Returns a vector pointing in the same direction as another. + * + * @function + * @param {Node} N - The vector to orient. + * @param {Node} I - The incident vector. + * @param {Node} Nref - The reference vector. + * @returns {Node} + */ const faceForward = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FACEFORWARD ); +/** + * Returns a random value for the given uv. + * + * @function + * @param {Node} uv - The uv node. + * @returns {Node} + */ const rand = /*@__PURE__*/ Fn( ( [ uv ] ) => { const a = 12.9898, b = 78.233, c = 43758.5453; @@ -4707,9 +5843,52 @@ const rand = /*@__PURE__*/ Fn( ( [ uv ] ) => { } ); +/** + * Alias for `mix()` with a different parameter order. + * + * @function + * @param {Node | Number} t - The interpolation value. + * @param {Node | Number} e1 - The first parameter. + * @param {Node | Number} e2 - The second parameter. + * @returns {Node} + */ const mixElement = ( t, e1, e2 ) => mix( e1, e2, t ); + +/** + * Alias for `smoothstep()` with a different parameter order. + * + * @function + * @param {Node | Number} x - The source value for interpolation. + * @param {Node | Number} low - The value of the lower edge of the Hermite function. + * @param {Node | Number} high - The value of the upper edge of the Hermite function. + * @returns {Node} + */ const smoothstepElement = ( x, low, high ) => smoothstep( low, high, x ); +/** + * Returns the arc-tangent of the quotient of its parameters. + * + * @function + * @deprecated since r172. Use {@link atan} instead. + * + * @param {Node | Number} y - The y parameter. + * @param {Node | Number} x - The x parameter. + * @returns {Node} + */ +const atan2 = ( y, x ) => { // @deprecated, r172 + + console.warn( 'THREE.TSL: "atan2" is overloaded. Use "atan" instead.' ); + return atan( y, x ); + +}; + +// GLSL alias function + +const faceforward = faceForward; +const inversesqrt = inverseSqrt; + +// Method chaining + addMethodChaining( 'all', all ); addMethodChaining( 'any', any ); addMethodChaining( 'equals', equals ); @@ -4769,6 +5948,8 @@ addMethodChaining( 'cbrt', cbrt ); addMethodChaining( 'transpose', transpose ); addMethodChaining( 'rand', rand ); +/** @module ConditionalNode **/ + /** * Represents a logical `if/else` statement. Can be used as an alternative * to the `If()`/`Else()` syntax. @@ -4777,7 +5958,7 @@ addMethodChaining( 'rand', rand ); * ```js * velocity = position.greaterThanEqual( limit ).select( velocity.negate(), velocity ); * ``` - * The `select()` method is called in a chaining fashion on a codition. The parameter nodes of `select()` + * The `select()` method is called in a chaining fashion on a condition. The parameter nodes of `select()` * determine the outcome of the entire statement. * * @augments Node @@ -4818,7 +5999,8 @@ class ConditionalNode extends Node { /** * The node that is evaluate when the condition ends up `false`. * - * @type {Node} + * @type {Node?} + * @default null */ this.elseNode = elseNode; @@ -4833,11 +6015,23 @@ class ConditionalNode extends Node { */ getNodeType( builder ) { - const ifType = this.ifNode.getNodeType( builder ); + const { ifNode, elseNode } = builder.getNodeProperties( this ); + + if ( ifNode === undefined ) { + + // fallback setup + + this.setup( builder ); + + return this.getNodeType( builder ); - if ( this.elseNode !== null ) { + } + + const ifType = ifNode.getNodeType( builder ); + + if ( elseNode !== null ) { - const elseType = this.elseNode.getNodeType( builder ); + const elseType = elseNode.getNodeType( builder ); if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) { @@ -4948,12 +6142,28 @@ class ConditionalNode extends Node { } +/** + * TSL function for creating a conditional node. + * + * @function + * @param {Node} condNode - The node that defines the condition. + * @param {Node} ifNode - The node that is evaluate when the condition ends up `true`. + * @param {Node?} [elseNode=null] - The node that is evaluate when the condition ends up `false`. + * @returns {ConditionalNode} + */ const select = /*@__PURE__*/ nodeProxy( ConditionalNode ); addMethodChaining( 'select', select ); -// +// deprecated +/** + * @function + * @deprecated since r168. Use {@link select} instead. + * + * @param {...any} params + * @returns {ConditionalNode} + */ const cond = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.ConditionalNode: cond() has been renamed to select().' ); @@ -4963,6 +6173,8 @@ const cond = ( ...params ) => { // @deprecated, r168 addMethodChaining( 'cond', cond ); +/** @module ContextNode **/ + /** * This node can be used as a context management component for another node. * {@link NodeBuilder} performs its node building process in a specific context and @@ -5018,9 +6230,9 @@ class ContextNode extends Node { } /** - * This method is overwritten to ensure it returns the reference to {@link ContextNode#node}. + * This method is overwritten to ensure it returns the reference to {@link module:ContextNode~ContextNode#node}. * - * @return {Node} A reference to {@link ContextNode#node}. + * @return {Node} A reference to {@link module:ContextNode~ContextNode#node}. */ getScope() { @@ -5029,10 +6241,10 @@ class ContextNode extends Node { } /** - * This method is overwritten to ensure it returns the type to {@link ContextNode#node}. + * This method is overwritten to ensure it returns the type of {@link module:ContextNode~ContextNode#node}. * * @param {NodeBuilder} builder - The current node builder. - * @return {String} The type of {@link ContextNode#node}. + * @return {String} The node type. */ getNodeType( builder ) { @@ -5076,12 +6288,31 @@ class ContextNode extends Node { } +/** + * TSL function for creating a context node. + * + * @function + * @param {Node} node - The node whose context should be modified. + * @param {Object} [value={}] - The modified context data. + * @returns {ContextNode} + */ const context = /*@__PURE__*/ nodeProxy( ContextNode ); + +/** + * TSL function for defining a label context value for a given node. + * + * @function + * @param {Node} node - The node whose context should be modified. + * @param {String} name - The name/label to set. + * @returns {ContextNode} + */ const label = ( node, name ) => context( node, { label: name } ); addMethodChaining( 'context', context ); addMethodChaining( 'label', label ); +/** @module VarNode **/ + /** * Class for representing shader variables as nodes. Variables are created from * existing nodes like the following: @@ -5105,8 +6336,9 @@ class VarNode extends Node { * * @param {Node} node - The node for which a variable should be created. * @param {String?} name - The name of the variable in the shader. + * @param {Boolean?} readOnly - The read-only flag. */ - constructor( node, name = null ) { + constructor( node, name = null, readOnly = false ) { super(); @@ -5143,6 +6375,15 @@ class VarNode extends Node { */ this.isVarNode = true; + /** + * + * The read-only flag. + * + * @type {Boolean} + * @default false + */ + this.readOnly = readOnly; + } getHash( builder ) { @@ -5159,15 +6400,50 @@ class VarNode extends Node { generate( builder ) { - const { node, name } = this; + const { node, name, readOnly } = this; + const { renderer } = builder; + + const isWebGPUBackend = renderer.backend.isWebGPUBackend === true; + + let isDeterministic = false; + let shouldTreatAsReadOnly = false; - const nodeVar = builder.getVarFromNode( this, name, builder.getVectorType( this.getNodeType( builder ) ) ); + if ( readOnly ) { + + isDeterministic = builder.isDeterministic( node ); + + shouldTreatAsReadOnly = isWebGPUBackend ? readOnly : isDeterministic; + + } + + const vectorType = builder.getVectorType( this.getNodeType( builder ) ); + const snippet = node.build( builder, vectorType ); + + const nodeVar = builder.getVarFromNode( this, name, vectorType, undefined, shouldTreatAsReadOnly ); const propertyName = builder.getPropertyName( nodeVar ); - const snippet = node.build( builder, nodeVar.type ); + let declarationPrefix = propertyName; + + if ( shouldTreatAsReadOnly ) { + + const type = builder.getType( nodeVar.type ); + + if ( isWebGPUBackend ) { - builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); + declarationPrefix = isDeterministic + ? `const ${ propertyName }` + : `let ${ propertyName }`; + + } else { + + declarationPrefix = `const ${ type } ${ propertyName }`; + + } + + } + + builder.addLineFlowCode( `${ declarationPrefix } = ${ snippet }`, this ); return propertyName; @@ -5175,15 +6451,53 @@ class VarNode extends Node { } +/** + * TSL function for creating a var node. + * + * @function + * @param {Node} node - The node for which a variable should be created. + * @param {String?} name - The name of the variable in the shader. + * @returns {VarNode} + */ const createVar = /*@__PURE__*/ nodeProxy( VarNode ); -addMethodChaining( 'toVar', ( ...params ) => createVar( ...params ).append() ); +/** + * TSL function for creating a var node. + * + * @function + * @param {Node} node - The node for which a variable should be created. + * @param {String?} name - The name of the variable in the shader. + * @returns {VarNode} + */ +const Var = ( node, name = null ) => createVar( node, name ).append(); + +/** + * TSL function for creating a const node. + * + * @function + * @param {Node} node - The node for which a constant should be created. + * @param {String?} name - The name of the constant in the shader. + * @returns {VarNode} + */ +const Const = ( node, name = null ) => createVar( node, name, true ).append(); + +// Method chaining + +addMethodChaining( 'toVar', Var ); +addMethodChaining( 'toConst', Const ); // Deprecated +/** + * @function + * @deprecated since r170. Use `Var( node )` or `node.toVar()` instead. + * + * @param {Any} node + * @returns {VarNode} + */ const temp = ( node ) => { // @deprecated, r170 - console.warn( 'TSL: "temp" is deprecated. Use ".toVar()" instead.' ); + console.warn( 'TSL: "temp( node )" is deprecated. Use "Var( node )" or "node.toVar()" instead.' ); return createVar( node ); @@ -5191,6 +6505,8 @@ const temp = ( node ) => { // @deprecated, r170 addMethodChaining( 'temp', temp ); +/** @module VaryingNode **/ + /** * Class for representing shader varyings as nodes. Varyings are create from * existing nodes like the following: @@ -5320,7 +6636,9 @@ class VaryingNode extends Node { const properties = builder.getNodeProperties( this ); const varying = this.setupVarying( builder ); - if ( properties.propertyName === undefined ) { + const needsReassign = builder.shaderStage === 'fragment' && properties.reassignPosition === true && builder.context.needsPositionReassign; + + if ( properties.propertyName === undefined || needsReassign ) { const type = this.getNodeType( builder ); const propertyName = builder.getPropertyName( varying, NodeShaderStage.VERTEX ); @@ -5330,6 +6648,17 @@ class VaryingNode extends Node { properties.propertyName = propertyName; + if ( needsReassign ) { + + // once reassign varying in fragment stage + properties.reassignPosition = false; + + } else if ( properties.reassignPosition === undefined && builder.context.isPositionNodeInput ) { + + properties.reassignPosition = true; + + } + } return builder.getPropertyName( varying ); @@ -5338,9 +6667,27 @@ class VaryingNode extends Node { } +/** + * TSL function for creating a varying node. + * + * @function + * @param {Node} node - The node for which a varying should be created. + * @param {String?} name - The name of the varying in the shader. + * @returns {VaryingNode} + */ const varying = /*@__PURE__*/ nodeProxy( VaryingNode ); +/** + * Computes a node in the vertex stage. + * + * @function + * @param {Node} node - The node which should be executed in the vertex stage. + * @returns {VaryingNode} + */ +const vertexStage = ( node ) => varying( node ); + addMethodChaining( 'varying', varying ); +addMethodChaining( 'vertexStage', vertexStage ); /** @module ColorSpaceFunctions **/ @@ -5394,6 +6741,8 @@ const sRGBTransferOETF = /*@__PURE__*/ Fn( ( [ color ] ) => { ] } ); +/** @module ColorSpaceNode **/ + const WORKING_COLOR_SPACE = 'WorkingColorSpace'; const OUTPUT_COLOR_SPACE = 'OutputColorSpace'; @@ -5432,14 +6781,14 @@ class ColorSpaceNode extends TempNode { /** * The source color space. * - * @type {Node} + * @type {String} */ this.source = source; /** * The target color space. * - * @type {Node} + * @type {String} */ this.target = target; @@ -5512,12 +6861,53 @@ class ColorSpaceNode extends TempNode { } +/** + * TSL function for converting a given color node to the current output color space. + * + * @function + * @param {Node} node - Represents the node to convert. + * @returns {ColorSpaceNode} + */ const toOutputColorSpace = ( node ) => nodeObject( new ColorSpaceNode( nodeObject( node ), WORKING_COLOR_SPACE, OUTPUT_COLOR_SPACE ) ); + +/** + * TSL function for converting a given color node to the current working color space. + * + * @function + * @param {Node} node - Represents the node to convert. + * @returns {ColorSpaceNode} + */ const toWorkingColorSpace = ( node ) => nodeObject( new ColorSpaceNode( nodeObject( node ), OUTPUT_COLOR_SPACE, WORKING_COLOR_SPACE ) ); +/** + * TSL function for converting a given color node from the current working color space to the given color space. + * + * @function + * @param {Node} node - Represents the node to convert. + * @param {String} colorSpace - The target color space. + * @returns {ColorSpaceNode} + */ const workingToColorSpace = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), WORKING_COLOR_SPACE, colorSpace ) ); + +/** + * TSL function for converting a given color node from the given color space to the current working color space. + * + * @function + * @param {Node} node - Represents the node to convert. + * @param {String} colorSpace - The source color space. + * @returns {ColorSpaceNode} + */ const colorSpaceToWorking = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), colorSpace, WORKING_COLOR_SPACE ) ); +/** + * TSL function for converting a given color node from one color space to another one. + * + * @function + * @param {Node} node - Represents the node to convert. + * @param {String} sourceColorSpace - The source color space. + * @param {String} targetColorSpace - The target color space. + * @returns {ColorSpaceNode} + */ const convertColorSpace = ( node, sourceColorSpace, targetColorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), sourceColorSpace, targetColorSpace ) ); addMethodChaining( 'toOutputColorSpace', toOutputColorSpace ); @@ -5526,6 +6916,17 @@ addMethodChaining( 'toWorkingColorSpace', toWorkingColorSpace ); addMethodChaining( 'workingToColorSpace', workingToColorSpace ); addMethodChaining( 'colorSpaceToWorking', colorSpaceToWorking ); +// TODO: Avoid duplicated code and ues only ReferenceBaseNode or ReferenceNode + +/** @module ReferenceBaseNode **/ + +/** + * This class is only relevant if the referenced property is array-like. + * In this case, `ReferenceElementNode` allows to refer to a specific + * element inside the data structure via an index. + * + * @augments ArrayElementNode + */ let ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode { static get type() { @@ -5534,16 +6935,43 @@ let ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode } + /** + * Constructs a new reference element node. + * + * @param {Node?} referenceNode - The reference node. + * @param {Node} indexNode - The index node that defines the element access. + */ constructor( referenceNode, indexNode ) { super( referenceNode, indexNode ); + /** + * Similar to {@link module:ReferenceBaseNode~ReferenceBaseNode#reference}, an additional + * property references to the current node. + * + * @type {Node?} + * @default null + */ this.referenceNode = referenceNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isReferenceElementNode = true; } + /** + * This method is overwritten since the node type is inferred from + * the uniform type of the reference node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType() { return this.referenceNode.uniformType; @@ -5562,6 +6990,14 @@ let ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode }; +/** + * Base class for nodes which establishes a reference to a property of another object. + * In this way, the value of the node is automatically linked to the value of + * referenced object. Reference nodes internally represent the linked value + * as a uniform. + * + * @augments Node + */ class ReferenceBaseNode extends Node { static get type() { @@ -5570,24 +7006,97 @@ class ReferenceBaseNode extends Node { } + /** + * Constructs a new reference base node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} uniformType - The uniform type that should be used to represent the property value. + * @param {Object?} [object=null] - The object the property belongs to. + * @param {Number?} [count=null] - When the linked property is an array-like, this parameter defines its length. + */ constructor( property, uniformType, object = null, count = null ) { super(); + /** + * The name of the property the node refers to. + * + * @type {String} + */ this.property = property; + + /** + * The uniform type that should be used to represent the property value. + * + * @type {String} + */ this.uniformType = uniformType; + + /** + * The object the property belongs to. + * + * @type {Object?} + * @default null + */ this.object = object; + + /** + * When the linked property is an array, this parameter defines its length. + * + * @type {Number?} + * @default null + */ this.count = count; + /** + * The property name might have dots so nested properties can be referred. + * The hierarchy of the names is stored inside this array. + * + * @type {Array} + */ this.properties = property.split( '.' ); + + /** + * Points to the current referred object. This property exists next to {@link module:ReferenceNode~ReferenceNode#object} + * since the final reference might be updated from calling code. + * + * @type {Object?} + * @default null + */ this.reference = object; + + /** + * The uniform node that holds the value of the reference node. + * + * @type {UniformNode} + * @default null + */ this.node = null; + + /** + * The uniform group of the internal uniform. + * + * @type {UniformGroupNode} + * @default null + */ this.group = null; + /** + * Overwritten since reference nodes are updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; } + /** + * Sets the uniform group for this reference node. + * + * @param {UniformGroupNode} group - The uniform group to set. + * @return {ReferenceBaseNode} A reference to this node. + */ setGroup( group ) { this.group = group; @@ -5596,12 +7105,25 @@ class ReferenceBaseNode extends Node { } + /** + * When the referred property is array-like, this method can be used + * to access elements via an index node. + * + * @param {IndexNode} indexNode - indexNode. + * @return {ReferenceElementNode} A reference to an element. + */ element( indexNode ) { return nodeObject( new ReferenceElementNode$1( this, nodeObject( indexNode ) ) ); } + /** + * Sets the node type which automatically defines the internal + * uniform type. + * + * @param {String} uniformType - The type to set. + */ setNodeType( uniformType ) { const node = uniform( null, uniformType ).getSelf(); @@ -5616,6 +7138,13 @@ class ReferenceBaseNode extends Node { } + /** + * This method is overwritten since the node type is inferred from + * the type of the reference node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( this.node === null ) { @@ -5629,6 +7158,12 @@ class ReferenceBaseNode extends Node { } + /** + * Returns the property value from the given referred object. + * + * @param {Object} [object=this.reference] - The object to retrieve the property value from. + * @return {Any} The value. + */ getValueFromReference( object = this.reference ) { const { properties } = this; @@ -5645,6 +7180,13 @@ class ReferenceBaseNode extends Node { } + /** + * Allows to update the reference based on the given state. The state is only + * evaluated {@link module:ReferenceBaseNode~ReferenceBaseNode#object} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.object !== null ? this.object : state.object; @@ -5653,6 +7195,12 @@ class ReferenceBaseNode extends Node { } + /** + * The output of the reference node is the internal uniform node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {UniformNode} The output node. + */ setup() { this.updateValue(); @@ -5661,12 +7209,21 @@ class ReferenceBaseNode extends Node { } + /** + * Overwritten to to update the internal uniform value. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( /*frame*/ ) { this.updateValue(); } + /** + * Retrieves the value from the referred object property and uses it + * to updated the internal uniform. + */ updateValue() { if ( this.node === null ) this.setNodeType( this.uniformType ); @@ -5687,8 +7244,30 @@ class ReferenceBaseNode extends Node { } +/** + * TSL function for creating a reference base node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Object} object - The object the property belongs to. + * @returns {ReferenceBaseNode} + */ const reference$1 = ( name, type, object ) => nodeObject( new ReferenceBaseNode( name, type, object ) ); +/** @module RendererReferenceNode **/ + +/** + * This node is a special type of reference node which is intended + * for linking renderer properties with node values. + * ```js + * const exposureNode = rendererReference( 'toneMappingExposure', 'float', renderer ); + * ``` + * When changing `renderer.toneMappingExposure`, the node value of `exposureNode` will + * automatically be updated. + * + * @augments ReferenceBaseNode + */ class RendererReferenceNode extends ReferenceBaseNode { static get type() { @@ -5697,16 +7276,38 @@ class RendererReferenceNode extends ReferenceBaseNode { } + /** + * Constructs a new renderer reference node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} inputType - The uniform type that should be used to represent the property value. + * @param {Renderer?} [renderer=null] - The renderer the property belongs to. When no renderer is set, + * the node refers to the renderer of the current state. + */ constructor( property, inputType, renderer = null ) { super( property, inputType, renderer ); + /** + * The renderer the property belongs to. When no renderer is set, + * the node refers to the renderer of the current state. + * + * @type {Renderer?} + * @default null + */ this.renderer = renderer; this.setGroup( renderGroup ); } + /** + * Updates the reference based on the given state. The state is only evaluated + * {@link module:RendererReferenceNode~RendererReferenceNode#renderer} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.renderer !== null ? this.renderer : state.renderer; @@ -5717,7 +7318,19 @@ class RendererReferenceNode extends ReferenceBaseNode { } -const rendererReference = ( name, type, renderer ) => nodeObject( new RendererReferenceNode( name, type, renderer ) ); +/** + * TSL function for creating a renderer reference node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Renderer?} [renderer=null] - The renderer the property belongs to. When no renderer is set, + * the node refers to the renderer of the current state. + * @returns {RendererReferenceNode} + */ +const rendererReference = ( name, type, renderer = null ) => nodeObject( new RendererReferenceNode( name, type, renderer ) ); + +/** @module ToneMappingNode **/ /** * This node represents a tone mapping operation. @@ -5761,7 +7374,7 @@ class ToneMappingNode extends TempNode { /** * Represents the color to process. * - * @type {Node} + * @type {Node?} * @default null */ this.colorNode = colorNode; @@ -5809,11 +7422,50 @@ class ToneMappingNode extends TempNode { } +/** + * TSL function for creating a tone mapping node. + * + * @function + * @param {Number} mapping - The tone mapping type. + * @param {Node | Number} exposure - The tone mapping exposure. + * @param {Node | Color} color - The color node to process. + * @returns {ToneMappingNode} + */ const toneMapping = ( mapping, exposure, color ) => nodeObject( new ToneMappingNode( mapping, nodeObject( exposure ), nodeObject( color ) ) ); + +/** + * TSL object that represents the global tone mapping exposure of the renderer. + * + * @type {RendererReferenceNode} + */ const toneMappingExposure = /*@__PURE__*/ rendererReference( 'toneMappingExposure', 'float' ); addMethodChaining( 'toneMapping', ( color, mapping, exposure ) => toneMapping( mapping, exposure, color ) ); +/** @module BufferAttributeNode **/ + +/** + * In earlier `three.js` versions it was only possible to define attribute data + * on geometry level. With `BufferAttributeNode`, it is also possible to do this + * on the node level. + * ```js + * const geometry = new THREE.PlaneGeometry(); + * const positionAttribute = geometry.getAttribute( 'position' ); + * + * const colors = []; + * for ( let i = 0; i < position.count; i ++ ) { + * colors.push( 1, 0, 0 ); + * } + * + * material.colorNode = bufferAttribute( new THREE.Float32BufferAttribute( colors, 3 ) ); + * ``` + * This new approach is especially interesting when geometry data are generated via + * compute shaders. The below line converts a storage buffer into an attribute node. + * ```js + * material.positionNode = positionBuffer.toAttribute(); + * ``` + * @augments InputNode + */ class BufferAttributeNode extends InputNode { static get type() { @@ -5822,21 +7474,82 @@ class BufferAttributeNode extends InputNode { } + /** + * Constructs a new buffer attribute node. + * + * @param {BufferAttribute|InterleavedBuffer|TypedArray} value - The attribute data. + * @param {String?} [bufferType=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [bufferStride=0] - The buffer stride. + * @param {Number} [bufferOffset=0] - The buffer offset. + */ constructor( value, bufferType = null, bufferStride = 0, bufferOffset = 0 ) { super( value, bufferType ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBufferNode = true; + /** + * The buffer type (e.g. `'vec3'`). + * + * @type {String} + * @default null + */ this.bufferType = bufferType; + + /** + * The buffer stride. + * + * @type {Number} + * @default 0 + */ this.bufferStride = bufferStride; + + /** + * The buffer offset. + * + * @type {Number} + * @default 0 + */ this.bufferOffset = bufferOffset; + /** + * The usage property. Set this to `THREE.DynamicDrawUsage` via `.setUsage()`, + * if you are planning to update the attribute data per frame. + * + * @type {Number} + * @default StaticDrawUsage + */ this.usage = StaticDrawUsage; + + /** + * Whether the attribute is instanced or not. + * + * @type {Boolean} + * @default false + */ this.instanced = false; + /** + * A reference to the buffer attribute. + * + * @type {BufferAttribute?} + * @default null + */ this.attribute = null; + /** + * `BufferAttributeNode` sets this property to `true` by default. + * + * @type {Boolean} + * @default true + */ this.global = true; if ( value && value.isBufferAttribute === true ) { @@ -5849,6 +7562,13 @@ class BufferAttributeNode extends InputNode { } + /** + * This method is overwritten since the attribute data might be shared + * and thus the hash should be shared as well. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The hash. + */ getHash( builder ) { if ( this.bufferStride === 0 && this.bufferOffset === 0 ) { @@ -5873,6 +7593,13 @@ class BufferAttributeNode extends InputNode { } + /** + * This method is overwritten since the node type is inferred from + * the buffer attribute. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( this.bufferType === null ) { @@ -5885,6 +7612,13 @@ class BufferAttributeNode extends InputNode { } + /** + * Depending on which value was passed to the node, `setup()` behaves + * differently. If no instance of `BufferAttribute` was passed, the method + * creates an internal attribute and configures it respectively. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { if ( this.attribute !== null ) return; @@ -5905,6 +7639,12 @@ class BufferAttributeNode extends InputNode { } + /** + * Generates the code snippet of the buffer attribute node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( builder ) { const nodeType = this.getNodeType( builder ); @@ -5932,12 +7672,24 @@ class BufferAttributeNode extends InputNode { } + /** + * Overwrites the default implementation to return a fixed value `'bufferAttribute'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'bufferAttribute'; } + /** + * Sets the `usage` property to the given value. + * + * @param {Number} value - The usage to set. + * @return {BufferAttributeNode} A reference to this node. + */ setUsage( value ) { this.usage = value; @@ -5952,6 +7704,12 @@ class BufferAttributeNode extends InputNode { } + /** + * Sets the `instanced` property to the given value. + * + * @param {Number} value - The value to set. + * @return {BufferAttributeNode} A reference to this node. + */ setInstanced( value ) { this.instanced = value; @@ -5962,14 +7720,64 @@ class BufferAttributeNode extends InputNode { } -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 ); +/** + * TSL function for creating a buffer attribute node. + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +const bufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) ); -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 ); +/** + * TSL function for creating a buffer attribute node but with dynamic draw usage. + * Use this function if attribute data are updated per frame. + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +const dynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage ); + +/** + * TSL function for creating a buffer attribute node but with enabled instancing + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +const instancedBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setInstanced( true ); + +/** + * TSL function for creating a buffer attribute node but with dynamic draw usage and enabled instancing + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +const instancedDynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true ); addMethodChaining( 'toAttribute', ( bufferNode ) => bufferAttribute( bufferNode.value ) ); +/** @module ComputeNode **/ + +/** + * TODO + * + * @augments Node + */ class ComputeNode extends Node { static get type() { @@ -5978,39 +7786,116 @@ class ComputeNode extends Node { } + /** + * Constructs a new compute node. + * + * @param {Node} computeNode - TODO + * @param {Number} count - TODO. + * @param {Array} [workgroupSize=[64]] - TODO. + */ constructor( computeNode, count, workgroupSize = [ 64 ] ) { super( 'void' ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isComputeNode = true; + /** + * TODO + * + * @type {Node} + */ this.computeNode = computeNode; + /** + * TODO + * + * @type {Number} + */ this.count = count; + + /** + * TODO + * + * @type {Array} + * @default [64] + */ this.workgroupSize = workgroupSize; + + /** + * TODO + * + * @type {Number} + */ this.dispatchCount = 0; + /** + * TODO + * + * @type {Number} + */ this.version = 1; + + /** + * The name or label of the uniform. + * + * @type {String} + * @default '' + */ + this.name = ''; + + /** + * The `updateBeforeType` is set to `NodeUpdateType.OBJECT` since {@link ComputeNode#updateBefore} + * is executed once per object by default. + * + * @type {String} + * @default 'object' + */ this.updateBeforeType = NodeUpdateType.OBJECT; + /** + * TODO + * + * @type {Function} + */ this.onInitFunction = null; this.updateDispatchCount(); } + /** + * Executes the `dispose` event for this node. + */ dispose() { this.dispatchEvent( { type: 'dispose' } ); } - set needsUpdate( value ) { + /** + * Sets the {@link ComputeNode#name} property. + * + * @param {String} name - The name of the uniform. + * @return {ComputeNode} A reference to this node. + */ + label( name ) { - if ( value === true ) this.version ++; + this.name = name; + + return this; } + /** + * TODO + */ updateDispatchCount() { const { count, workgroupSize } = this; @@ -6024,6 +7909,12 @@ class ComputeNode extends Node { } + /** + * TODO + * + * @param {Function} callback - TODO. + * @return {ComputeNode} A reference to this node. + */ onInit( callback ) { this.onInitFunction = callback; @@ -6032,6 +7923,11 @@ class ComputeNode extends Node { } + /** + * The method execute the compute for this node. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ updateBefore( { renderer } ) { renderer.compute( this ); @@ -6058,10 +7954,21 @@ class ComputeNode extends Node { } +/** + * TSL function for creating a compute node. + * + * @function + * @param {Node} node - TODO + * @param {Number} count - TODO. + * @param {Array} [workgroupSize=[64]] - TODO. + * @returns {AtomicFunctionNode} + */ const compute = ( node, count, workgroupSize ) => nodeObject( new ComputeNode( nodeObject( node ), count, workgroupSize ) ); addMethodChaining( 'compute', compute ); +/** @module CacheNode **/ + /** * This node can be used as a cache management component for another node. * Caching is in general used by default in {@link NodeBuilder} but this node @@ -6115,7 +8022,16 @@ class CacheNode extends Node { getNodeType( builder ) { - return this.node.getNodeType( builder ); + const previousCache = builder.getCache(); + const cache = builder.getCacheFromNode( this, this.parent ); + + builder.setCache( cache ); + + const nodeType = this.node.getNodeType( builder ); + + builder.setCache( previousCache ); + + return nodeType; } @@ -6136,10 +8052,20 @@ class CacheNode extends Node { } -const cache = ( node, ...params ) => nodeObject( new CacheNode( nodeObject( node ), ...params ) ); +/** + * TSL function for creating a cache node. + * + * @function + * @param {Node} node - The node that should be cached. + * @param {Boolean} parent - Whether this node refers to a shared parent cache or not. + * @returns {CacheNode} + */ +const cache = ( node, parent ) => nodeObject( new CacheNode( nodeObject( node ), parent ) ); addMethodChaining( 'cache', cache ); +/** @module BypassNode **/ + /** * The class generates the code of a given node but returns another node in the output. * This can be used to call a method or node that does not return a value, i.e. @@ -6216,10 +8142,20 @@ class BypassNode extends Node { } +/** + * TSL function for creating a bypass node. + * + * @function + * @param {Node} outputNode - The output node. + * @param {Node} callNode - The call node. + * @returns {BypassNode} + */ const bypass = /*@__PURE__*/ nodeProxy( BypassNode ); addMethodChaining( 'bypass', bypass ); +/** @module RemapNode **/ + /** * This node allows to remap a node value from one range into another. E.g a value of * `0.4` in the range `[ 0.3, 0.5 ]` should be remapped into the normalized range `[ 0, 1 ]`. @@ -6310,12 +8246,37 @@ class RemapNode extends Node { } +/** + * TSL function for creating a remap node. + * + * @function + * @param {Node} node - The node that should be remapped. + * @param {Node} inLowNode - The source or current lower bound of the range. + * @param {Node} inHighNode - The source or current upper bound of the range. + * @param {Node} [outLowNode=float(0)] - The target lower bound of the range. + * @param {Node} [outHighNode=float(1)] - The target upper bound of the range. + * @returns {RemapNode} + */ const remap = /*@__PURE__*/ nodeProxy( RemapNode, null, null, { doClamp: false } ); + +/** + * TSL function for creating a remap node, but with enabled clamping. + * + * @function + * @param {Node} node - The node that should be remapped. + * @param {Node} inLowNode - The source or current lower bound of the range. + * @param {Node} inHighNode - The source or current upper bound of the range. + * @param {Node} [outLowNode=float(0)] - The target lower bound of the range. + * @param {Node} [outHighNode=float(1)] - The target upper bound of the range. + * @returns {RemapNode} + */ const remapClamp = /*@__PURE__*/ nodeProxy( RemapNode ); addMethodChaining( 'remap', remap ); addMethodChaining( 'remapClamp', remapClamp ); +/** @module ExpressionNode **/ + /** * This class can be used to implement basic expressions in shader code. * Basic examples for that are `return`, `continue` or `discard` statements. @@ -6369,6 +8330,14 @@ class ExpressionNode extends Node { } +/** + * TSL function for creating an expression node. + * + * @function + * @param {String} [snippet=''] - The native code snippet. + * @param {String} [nodeType='void'] - The node type. + * @returns {ExpressionNode} + */ const expression = /*@__PURE__*/ nodeProxy( ExpressionNode ); /** @module Discard **/ @@ -6392,6 +8361,8 @@ const Return = () => expression( 'return' ).append(); addMethodChaining( 'discard', Discard ); +/** @module RenderOutputNode **/ + /** * Normally, tone mapping and color conversion happens automatically * before outputting pixel too the default (screen) framebuffer. In certain @@ -6427,7 +8398,7 @@ class RenderOutputNode extends TempNode { * Constructs a new render output node. * * @param {Node} colorNode - The color node to process. - * @param {String} toneMapping - The tone mapping type. + * @param {Number} toneMapping - The tone mapping type. * @param {String} outputColorSpace - The output color space. */ constructor( colorNode, toneMapping, outputColorSpace ) { @@ -6495,6 +8466,15 @@ class RenderOutputNode extends TempNode { } +/** + * TSL function for creating a posterize node. + * + * @function + * @param {Node} color - The color node to process. + * @param {Number?} [toneMapping=null] - The tone mapping type. + * @param {String?} [outputColorSpace=null] - The output color space. + * @returns {RenderOutputNode} + */ const renderOutput = ( color, toneMapping = null, outputColorSpace = null ) => nodeObject( new RenderOutputNode( nodeObject( color ), toneMapping, outputColorSpace ) ); addMethodChaining( 'renderOutput', renderOutput ); @@ -6509,6 +8489,8 @@ function addNodeElement( name/*, nodeElement*/ ) { } +/** @module AttributeNode **/ + /** * Base class for representing shader attributes as nodes. * @@ -6661,10 +8643,36 @@ class AttributeNode extends Node { } +/** + * TSL function for creating an attribute node. + * + * @function + * @param {String} name - The name of the attribute. + * @param {String?} nodeType - The node type. + * @returns {AttributeNode} + */ const attribute = ( name, nodeType ) => nodeObject( new AttributeNode( name, nodeType ) ); -const uv = ( index ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); +/** @module UV **/ + +/** + * TSL function for creating an uv attribute node with the given index. + * + * @function + * @param {Number} [index=0] - The uv index. + * @return {AttributeNode} The uv attribute node. + */ +const uv = ( index = 0 ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); +/** @module TextureSizeNode **/ + +/** + * A node that represents the dimensions of a texture. The texture size is + * retrieved in the shader via built-in shader functions like `textureDimensions()` + * or `textureSize()`. + * + * @augments Node + */ class TextureSizeNode extends Node { static get type() { @@ -6673,13 +8681,38 @@ class TextureSizeNode extends Node { } + /** + * Constructs a new texture size node. + * + * @param {TextureNode} textureNode - A texture node which size should be retrieved. + * @param {Node?} [levelNode=null] - A level node which defines the requested mip. + */ constructor( textureNode, levelNode = null ) { super( 'uvec2' ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isTextureSizeNode = true; + /** + * A texture node which size should be retrieved. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * A level node which defines the requested mip. + * + * @type {Node} + * @default null + */ this.levelNode = levelNode; } @@ -6695,8 +8728,18 @@ class TextureSizeNode extends Node { } +/** + * TSL function for creating a texture size node. + * + * @function + * @param {TextureNode} textureNode - A texture node which size should be retrieved. + * @param {Node?} [levelNode=null] - A level node which defines the requested mip. + * @returns {TextureSizeNode} + */ const textureSize = /*@__PURE__*/ nodeProxy( TextureSizeNode ); +/** @module MatcapUVNode **/ + /** * A special type of uniform node that computes the * maximum mipmap level for a given texture node. @@ -6705,7 +8748,7 @@ const textureSize = /*@__PURE__*/ nodeProxy( TextureSizeNode ); * const level = maxMipLevel( textureNode ); * ``` * - * @augments UniformNode + * @augments module:UniformNode~UniformNode */ class MaxMipLevelNode extends UniformNode { @@ -6785,8 +8828,22 @@ class MaxMipLevelNode extends UniformNode { } +/** + * TSL function for creating a max mip level node. + * + * @function + * @param {TextureNode} textureNode - The texture node to compute the max mip level for. + * @returns {MaxMipLevelNode} + */ const maxMipLevel = /*@__PURE__*/ nodeProxy( MaxMipLevelNode ); +/** @module TextureNode **/ + +/** + * This type of uniform node represents a 2D texture. + * + * @augments module:UniformNode~UniformNode + */ class TextureNode extends UniformNode { static get type() { @@ -6795,26 +8852,125 @@ class TextureNode extends UniformNode { } + /** + * Constructs a new texture node. + * + * @param {Texture} value - The texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + */ constructor( value, uvNode = null, levelNode = null, biasNode = null ) { super( value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isTextureNode = true; + /** + * Represents the texture coordinates. + * + * @type {Node?} + * @default null + */ this.uvNode = uvNode; + + /** + * Represents the mip level that should be selected. + * + * @type {Node?} + * @default null + */ this.levelNode = levelNode; + + /** + * Represents the bias to be applied during level-of-detail computation. + * + * @type {Node?} + * @default null + */ this.biasNode = biasNode; + + /** + * Represents a reference value a texture sample is compared to. + * + * @type {Node?} + * @default null + */ this.compareNode = null; + + /** + * When using texture arrays, the depth node defines the layer to select. + * + * @type {Node?} + * @default null + */ this.depthNode = null; + + /** + * When defined, a texture is sampled using explicit gradients. + * + * @type {Array>?} + * @default null + */ this.gradNode = null; + /** + * Whether texture values should be sampled or fetched. + * + * @type {Boolean} + * @default true + */ this.sampler = true; + + /** + * Whether the uv transformation matrix should be + * automatically updated or not. Use `setUpdateMatrix()` + * if you want to change the value of the property. + * + * @type {Boolean} + * @default false + */ this.updateMatrix = false; + + /** + * By default the `update()` method is not executed. `setUpdateMatrix()` + * sets the value to `frame` when the uv transformation matrix should + * automatically be updated. + * + * @type {String} + * @default 'none' + */ this.updateType = NodeUpdateType.NONE; + /** + * The reference node. + * + * @type {Node?} + * @default null + */ this.referenceNode = null; + /** + * The texture value is stored in a private property. + * + * @private + * @type {Texture} + */ this._value = value; + + /** + * The uniform node that represents the uv transformation matrix. + * + * @private + * @type {UniformNode?} + */ this._matrixUniform = null; this.setUpdateMatrix( uvNode === null ); @@ -6835,18 +8991,35 @@ class TextureNode extends UniformNode { } + /** + * The texture value. + * + * @type {Texture} + */ get value() { return this.referenceNode ? this.referenceNode.value : this._value; } + /** + * Overwritten since the uniform hash is defined by the texture's UUID. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The uniform hash. + */ getUniformHash( /*builder*/ ) { return this.value.uuid; } + /** + * Overwritten since the node type is inferred from the texture type. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( /*builder*/ ) { if ( this.value.isDepthTexture === true ) return 'float'; @@ -6865,24 +9038,47 @@ class TextureNode extends UniformNode { } + /** + * Overwrites the default implementation to return a fixed value `'texture'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'texture'; } + /** + * Returns a default uvs based on the current texture's channel. + * + * @return {AttributeNode} The default uvs. + */ getDefaultUV() { return uv( this.value.channel ); } + /** + * Overwritten to always return the texture reference of the node. + * + * @param {Any} state - This method can be invocated in different contexts so `state` can refer to any object type. + * @return {Texture} The texture reference. + */ updateReference( /*state*/ ) { return this.value; } + /** + * Transforms the given uv node with the texture transformation matrix. + * + * @param {Node} uvNode - The uv node to transform. + * @return {Node} The transformed uv node. + */ getTransformedUV( uvNode ) { if ( this._matrixUniform === null ) this._matrixUniform = uniform( this.value.matrix ); @@ -6891,15 +9087,29 @@ class TextureNode extends UniformNode { } + /** + * Defines whether the uv transformation matrix should automatically be updated or not. + * + * @param {Boolean} value - The update toggle. + * @return {TextureNode} A reference to this node. + */ setUpdateMatrix( value ) { this.updateMatrix = value; - this.updateType = value ? NodeUpdateType.FRAME : NodeUpdateType.NONE; + this.updateType = value ? NodeUpdateType.RENDER : NodeUpdateType.NONE; return this; } + /** + * Setups the uv node. Depending on the backend as well as texture's image and type, it might be necessary + * to modify the uv node for correct sampling. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to setup. + * @return {Node} The updated uv node. + */ setupUV( builder, uvNode ) { const texture = this.value; @@ -6922,6 +9132,11 @@ class TextureNode extends UniformNode { } + /** + * Setups texture node by preparing the internal nodes for code generation. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const properties = builder.getNodeProperties( this ); @@ -6929,6 +9144,16 @@ class TextureNode extends UniformNode { // + const texture = this.value; + + if ( ! texture || texture.isTexture !== true ) { + + throw new Error( 'THREE.TSL: `texture( value )` function expects a valid instance of THREE.Texture().' ); + + } + + // + let uvNode = this.uvNode; if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) { @@ -6968,12 +9193,32 @@ class TextureNode extends UniformNode { } + /** + * Generates the uv code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to generate code for. + * @return {String} The generated code snippet. + */ generateUV( builder, uvNode ) { return uvNode.build( builder, this.sampler === true ? 'vec2' : 'ivec2' ); } + /** + * Generates the snippet for the texture sampling. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} textureProperty - The texture property. + * @param {String} uvSnippet - The uv snippet. + * @param {String} levelSnippet - The level snippet. + * @param {String} biasSnippet - The bias snippet. + * @param {String} depthSnippet - The depth snippet. + * @param {String} compareSnippet - The compare snippet. + * @param {String} gradSnippet - The grad snippet. + * @return {String} The generated code snippet. + */ generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ) { const texture = this.value; @@ -7010,18 +9255,18 @@ class TextureNode extends UniformNode { } + /** + * Generates the code snippet of the texture node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output. + * @return {String} The generated code 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 properties = builder.getNodeProperties( this ); const textureProperty = super.generate( builder, 'property' ); if ( output === 'sampler' ) { @@ -7077,6 +9322,12 @@ class TextureNode extends UniformNode { } + /** + * Sets the sampler value. + * + * @param {Boolean} value - The sampler value to set. + * @return {TextureNode} A reference to this texture node. + */ setSampler( value ) { this.sampler = value; @@ -7085,6 +9336,11 @@ class TextureNode extends UniformNode { } + /** + * Returns the sampler value. + * + * @return {Boolean} The sampler value. + */ getSampler() { return this.sampler; @@ -7093,6 +9349,13 @@ class TextureNode extends UniformNode { // @TODO: Move to TSL + /** + * @function + * @deprecated since r172. Use {@link TextureNode#sample} instead. + * + * @param {Node} uvNode - The uv node. + * @return {TextureNode} A texture node representing the texture sample. + */ uv( uvNode ) { // @deprecated, r172 console.warn( 'THREE.TextureNode: .uv() has been renamed. Use .sample() instead.' ); @@ -7101,6 +9364,12 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture with the given uv node. + * + * @param {Node} uvNode - The uv node. + * @return {TextureNode} A texture node representing the texture sample. + */ sample( uvNode ) { const textureNode = this.clone(); @@ -7111,6 +9380,12 @@ class TextureNode extends UniformNode { } + /** + * Samples a blurred version of the texture by defining an internal bias. + * + * @param {Node} amountNode - How blurred the texture should be. + * @return {TextureNode} A texture node representing the texture sample. + */ blur( amountNode ) { const textureNode = this.clone(); @@ -7121,6 +9396,12 @@ class TextureNode extends UniformNode { } + /** + * Samples a specific mip of the texture. + * + * @param {Node} levelNode - The mip level to sample. + * @return {TextureNode} A texture node representing the texture sample. + */ level( levelNode ) { const textureNode = this.clone(); @@ -7131,12 +9412,24 @@ class TextureNode extends UniformNode { } + /** + * Returns the texture size of the requested level. + * + * @param {Node} levelNode - The level to compute the size for. + * @return {TextureSizeNode} The texture size. + */ size( levelNode ) { return textureSize( this, levelNode ); } + /** + * Samples the texture with the given bias. + * + * @param {Node} biasNode - The bias node. + * @return {TextureNode} A texture node representing the texture sample. + */ bias( biasNode ) { const textureNode = this.clone(); @@ -7147,6 +9440,12 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture by executing a compare operation. + * + * @param {Node} compareNode - The node that defines the compare value. + * @return {TextureNode} A texture node representing the texture sample. + */ compare( compareNode ) { const textureNode = this.clone(); @@ -7157,6 +9456,13 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture using an explicit gradient. + * + * @param {Node} gradNodeX - The gradX node. + * @param {Node} gradNodeY - The gradY node. + * @return {TextureNode} A texture node representing the texture sample. + */ grad( gradNodeX, gradNodeY ) { const textureNode = this.clone(); @@ -7167,6 +9473,12 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture by defining a depth node. + * + * @param {Node} depthNode - The depth node. + * @return {TextureNode} A texture node representing the texture sample. + */ depth( depthNode ) { const textureNode = this.clone(); @@ -7201,6 +9513,9 @@ class TextureNode extends UniformNode { } + /** + * The update is used to implement the update of the uv transformation matrix. + */ update() { const texture = this.value; @@ -7216,6 +9531,11 @@ class TextureNode extends UniformNode { } + /** + * Clones the texture node. + * + * @return {TextureNode} The cloned texture node. + */ clone() { const newNode = new this.constructor( this.value, this.uvNode, this.levelNode, this.biasNode ); @@ -7227,22 +9547,114 @@ class TextureNode extends UniformNode { } +/** + * TSL function for creating a texture node. + * + * @function + * @param {Texture} value - The texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + * @returns {TextureNode} + */ const texture = /*@__PURE__*/ nodeProxy( TextureNode ); + +/** + * TSL function for creating a texture node that fetches/loads texels without interpolation. + * + * @function + * @param {Texture} value - The texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + * @returns {TextureNode} + */ const textureLoad = ( ...params ) => texture( ...params ).setSampler( false ); //export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level ); +/** + * Converts a texture or texture node to a sampler. + * + * @function + * @param {TextureNode|Texture} aTexture - The texture or texture node to convert. + * @returns {Node} + */ const sampler = ( aTexture ) => ( aTexture.isNode === true ? aTexture : texture( aTexture ) ).convert( 'sampler' ); +/** @module Camera **/ + +/** + * TSL object that represents the `near` value of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraNear = /*@__PURE__*/ uniform( 'float' ).label( 'cameraNear' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.near ); + +/** + * TSL object that represents the `far` value of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraFar = /*@__PURE__*/ uniform( 'float' ).label( 'cameraFar' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.far ); + +/** + * TSL object that represents the projection matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraProjectionMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrix ); + +/** + * TSL object that represents the inverse projection matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraProjectionMatrixInverse = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrixInverse' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrixInverse ); + +/** + * TSL object that represents the view matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraViewMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraViewMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorldInverse ); + +/** + * TSL object that represents the world matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraWorldMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraWorldMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorld ); + +/** + * TSL object that represents the normal matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraNormalMatrix = /*@__PURE__*/ uniform( 'mat3' ).label( 'cameraNormalMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.normalMatrix ); + +/** + * TSL object that represents the position in world space of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraPosition = /*@__PURE__*/ uniform( new Vector3() ).label( 'cameraPosition' ).setGroup( renderGroup ).onRenderUpdate( ( { camera }, self ) => self.value.setFromMatrixPosition( camera.matrixWorld ) ); +/** @module Object3DNode **/ + +/** + * This node can be used to access transformation related metrics of 3D objects. + * Depending on the selected scope, a different metric is represented as a uniform + * in the shader. The following scopes are supported: + * + * - `POSITION`: The object's position in world space. + * - `VIEW_POSITION`: The object's position in view/camera space. + * - `DIRECTION`: The object's direction in world space. + * - `SCALE`: The object's scale in world space. + * - `WORLD_MATRIX`: The object's matrix in world space. + * + * @augments Node + */ class Object3DNode extends Node { static get type() { @@ -7251,19 +9663,55 @@ class Object3DNode extends Node { } + /** + * Constructs a new object 3D node. + * + * @param {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} scope - The node represents a different type of transformation depending on the scope. + * @param {Object3D?} [object3d=null] - The 3D object. + */ constructor( scope, object3d = null ) { super(); + /** + * The node reports a different type of transformation depending on the scope. + * + * @type {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} + */ this.scope = scope; + + /** + * The 3D object. + * + * @type {Object3D?} + * @default null + */ this.object3d = object3d; + /** + * Overwritten since this type of node is updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; + /** + * Holds the value of the node as a uniform. + * + * @private + * @type {UniformNode} + */ this._uniformNode = new UniformNode( null ); } + /** + * Overwritten since the node type is inferred from the scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType() { const scope = this.scope; @@ -7280,6 +9728,11 @@ class Object3DNode extends Node { } + /** + * Updates the uniform value depending on the scope. + * + * @param {NodeFrame} frame - The current node frame. + */ update( frame ) { const object = this.object3d; @@ -7321,6 +9774,13 @@ class Object3DNode extends Node { } + /** + * Generates the code snippet of the uniform node. The node type of the uniform + * node also depends on the selected scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( builder ) { const scope = this.scope; @@ -7363,12 +9823,61 @@ Object3DNode.SCALE = 'scale'; Object3DNode.VIEW_POSITION = 'viewPosition'; Object3DNode.DIRECTION = 'direction'; +/** + * TSL function for creating an object 3D node that represents the object's direction in world space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectDirection = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.DIRECTION ); + +/** + * TSL function for creating an object 3D node that represents the object's world matrix. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectWorldMatrix = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX ); + +/** + * TSL function for creating an object 3D node that represents the object's position in world space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.POSITION ); + +/** + * TSL function for creating an object 3D node that represents the object's scale in world space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectScale = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.SCALE ); + +/** + * TSL function for creating an object 3D node that represents the object's position in view/camera space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectViewPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION ); +/** @module ModelNode **/ + +/** + * This type of node is a specialized version of `Object3DNode` + * with larger set of model related metrics. Unlike `Object3DNode`, + * `ModelNode` extracts the reference to the 3D object from the + * current node frame state. + * + * @augments module:Object3DNode~Object3DNode + */ class ModelNode extends Object3DNode { static get type() { @@ -7377,12 +9886,23 @@ class ModelNode extends Object3DNode { } + /** + * Constructs a new object model node. + * + * @param {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} scope - The node represents a different type of transformation depending on the scope. + */ constructor( scope ) { super( scope ); } + /** + * Extracts the model reference from the frame state and then + * updates the uniform value depending on the scope. + * + * @param {NodeFrame} frame - The current node frame. + */ update( frame ) { this.object3d = frame.object; @@ -7393,16 +9913,84 @@ class ModelNode extends Object3DNode { } +/** + * TSL object that represents the object's direction in world space. + * + * @type {ModelNode} + */ const modelDirection = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.DIRECTION ); + +/** + * TSL object that represents the object's world matrix. + * + * @type {ModelNode} + */ const modelWorldMatrix = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX ); + +/** + * TSL object that represents the object's position in world space. + * + * @type {ModelNode} + */ const modelPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.POSITION ); + +/** + * TSL object that represents the object's scale in world space. + * + * @type {ModelNode} + */ const modelScale = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.SCALE ); + +/** + * TSL object that represents the object's position in view/camera space. + * + * @type {ModelNode} + */ const modelViewPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.VIEW_POSITION ); + +/** + * TSL object that represents the object's normal matrix. + * + * @type {UniformNode} + */ const modelNormalMatrix = /*@__PURE__*/ uniform( new Matrix3() ).onObjectUpdate( ( { object }, self ) => self.value.getNormalMatrix( object.matrixWorld ) ); + +/** + * TSL object that represents the object's inverse world matrix. + * + * @type {UniformNode} + */ 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 ) => { +/** + * TSL object that represents the object's model view matrix. + * + * @type {Node} + */ +const modelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { + + return builder.renderer.nodes.modelViewMatrix || mediumpModelViewMatrix; + +} ).once() )().toVar( 'modelViewMatrix' ); + +// GPU Precision + +/** + * TSL object that represents the object's model view in `mediump` precision. + * + * @type {Node} + */ +const mediumpModelViewMatrix = /*@__PURE__*/ cameraViewMatrix.mul( modelWorldMatrix ); + +// CPU Precision + +/** + * TSL object that represents the object's model view in `highp` precision + * which is achieved by computing the matrix in JS and not in the shader. + * + * @type {Node} + */ +const highpModelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { builder.context.isHighPrecisionModelViewMatrix = true; @@ -7412,9 +10000,15 @@ const highPrecisionModelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { } ); -} ).once() )().toVar( 'highPrecisionModelViewMatrix' ); +} ).once() )().toVar( 'highpModelViewMatrix' ); -const highPrecisionModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { +/** + * TSL object that represents the object's model normal view in `highp` precision + * which is achieved by computing the matrix in JS and not in the shader. + * + * @type {Node} + */ +const highpModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { const isHighPrecisionModelViewMatrix = builder.context.isHighPrecisionModelViewMatrix; @@ -7430,16 +10024,66 @@ const highPrecisionModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { } ); -} ).once() )().toVar( 'highPrecisionModelNormalMatrix' ); +} ).once() )().toVar( 'highpModelNormalViewMatrix' ); + +/** @module Position **/ +/** + * TSL object that represents the position attribute of the current rendered object. + * + * @type {AttributeNode} + */ const positionGeometry = /*@__PURE__*/ attribute( 'position', 'vec3' ); + +/** + * TSL object that represents the vertex position in local space of the current rendered object. + * + * @type {AttributeNode} + */ const positionLocal = /*@__PURE__*/ positionGeometry.varying( 'positionLocal' ); + +/** + * TSL object that represents the previous vertex position in local space of the current rendered object. + * Used in context of {@link module:VelocityNode~VelocityNode} for rendering motion vectors. + * + * @type {AttributeNode} + */ 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' ); + +/** + * TSL object that represents the vertex position in world space of the current rendered object. + * + * @type {VaryingNode} + */ +const positionWorld = /*@__PURE__*/ modelWorldMatrix.mul( positionLocal ).xyz.varying( 'v_positionWorld' ).context( { needsPositionReassign: true } ); + +/** + * TSL object that represents the position world direction of the current rendered object. + * + * @type {Node} + */ +const positionWorldDirection = /*@__PURE__*/ positionLocal.transformDirection( modelWorldMatrix ).varying( 'v_positionWorldDirection' ).normalize().toVar( 'positionWorldDirection' ).context( { needsPositionReassign: true } ); + +/** + * TSL object that represents the vertex position in view space of the current rendered object. + * + * @type {VaryingNode} + */ +const positionView = /*@__PURE__*/ ( Fn( ( builder ) => { + + return builder.context.setupPositionView(); + +}, 'vec3' ).once() )().varying( 'v_positionView' ).context( { needsPositionReassign: true } ); + +/** + * TSL object that represents the position view direction of the current rendered object. + * + * @type {VaryingNode} + */ const positionViewDirection = /*@__PURE__*/ positionView.negate().varying( 'v_positionViewDirection' ).normalize().toVar( 'positionViewDirection' ); +/** @module FrontFacingNode **/ + /** * This node can be used to evaluate whether a primitive is front or back facing. * @@ -7491,11 +10135,35 @@ class FrontFacingNode extends Node { } +/** + * TSL object that represents whether a primitive is front or back facing + * + * @type {FrontFacingNode} + */ const frontFacing = /*@__PURE__*/ nodeImmutable( FrontFacingNode ); + +/** + * TSL object that represents the front facing status as a number instead of a bool. + * `1` means front facing, `-1` means back facing. + * + * @type {Node} + */ const faceDirection = /*@__PURE__*/ float( frontFacing ).mul( 2.0 ).sub( 1.0 ); +/** @module Normal **/ + +/** + * TSL object that represents the normal attribute of the current rendered object. + * + * @type {Node} + */ const normalGeometry = /*@__PURE__*/ attribute( 'normal', 'vec3' ); +/** + * TSL object that represents the vertex normal in local space of the current rendered object. + * + * @type {Node} + */ const normalLocal = /*@__PURE__*/ ( Fn( ( builder ) => { if ( builder.geometry.hasAttribute( 'normal' ) === false ) { @@ -7510,8 +10178,18 @@ const normalLocal = /*@__PURE__*/ ( Fn( ( builder ) => { }, 'vec3' ).once() )().toVar( 'normalLocal' ); +/** + * TSL object that represents the flat vertex normal in view space of the current rendered object. + * + * @type {Node} + */ const normalFlat = /*@__PURE__*/ positionView.dFdx().cross( positionView.dFdy() ).normalize().toVar( 'normalFlat' ); +/** + * TSL object that represents the vertex normal in view space of the current rendered object. + * + * @type {Node} + */ const normalView = /*@__PURE__*/ ( Fn( ( builder ) => { let node; @@ -7530,23 +10208,54 @@ const normalView = /*@__PURE__*/ ( Fn( ( builder ) => { }, 'vec3' ).once() )().toVar( 'normalView' ); +/** + * TSL object that represents the vertex normal in world space of the current rendered object. + * + * @type {Node} + */ const normalWorld = /*@__PURE__*/ varying( normalView.transformDirection( cameraViewMatrix ), 'v_normalWorld' ).normalize().toVar( 'normalWorld' ); +/** + * TSL object that represents the transformed vertex normal in view space of the current rendered object. + * + * @type {Node} + */ const transformedNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { - return builder.context.setupNormal(); + // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode) -}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedNormalView' ); + return builder.context.setupNormal().context( { getUV: null } ); +}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedNormalView' ); +/** + * TSL object that represents the transformed vertex normal in world space of the current rendered object. + * + * @type {Node} + */ const transformedNormalWorld = /*@__PURE__*/ transformedNormalView.transformDirection( cameraViewMatrix ).toVar( 'transformedNormalWorld' ); +/** + * TSL object that represents the transformed clearcoat vertex normal in view space of the current rendered object. + * + * @type {Node} + */ const transformedClearcoatNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { - return builder.context.setupClearcoatNormal(); + // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode) + + return builder.context.setupClearcoatNormal().context( { getUV: null } ); }, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedClearcoatNormalView' ); +/** + * Transforms the normal with the given matrix. + * + * @function + * @param {Node} normal - The normal. + * @param {Node} [matrix=modelWorldMatrix] - The matrix. + * @return {Node} The transformed normal. + */ const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorldMatrix ] ) => { const m = mat3( matrix ); @@ -7557,6 +10266,14 @@ const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorldMatrix } ); +/** + * Transforms the given normal from local to view space. + * + * @function + * @param {Node} normal - The normal. + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The transformed normal. + */ const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => { const modelNormalViewMatrix = builder.renderer.nodes.modelNormalViewMatrix; @@ -7575,14 +10292,52 @@ const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => { } ); +/** @module MaterialProperties **/ + +/** + * TSL object that represents the refraction ratio of the material used for rendering the current object. + * + * @type {UniformNode} + */ const materialRefractionRatio = /*@__PURE__*/ uniform( 0 ).onReference( ( { material } ) => material ).onRenderUpdate( ( { material } ) => material.refractionRatio ); +/** @module ReflectVector **/ + +/** + * The reflect vector in view space. + * + * @type {Node} + */ const reflectView = /*@__PURE__*/ positionViewDirection.negate().reflect( transformedNormalView ); + +/** + * The refract vector in view space. + * + * @type {Node} + */ const refractView = /*@__PURE__*/ positionViewDirection.negate().refract( transformedNormalView, materialRefractionRatio ); +/** + * Used for sampling cube maps when using cube reflection mapping. + * + * @type {Node} + */ const reflectVector = /*@__PURE__*/ reflectView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); + +/** + * Used for sampling cube maps when using cube refraction mapping. + * + * @type {Node} + */ const refractVector = /*@__PURE__*/ refractView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); +/** @module CubeTextureNode **/ + +/** + * This type of uniform node represents a cube texture. + * + * @augments module:TextureNode~TextureNode + */ class CubeTextureNode extends TextureNode { static get type() { @@ -7591,20 +10346,46 @@ class CubeTextureNode extends TextureNode { } + /** + * Constructs a new cube texture node. + * + * @param {CubeTexture} value - The cube texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + */ constructor( value, uvNode = null, levelNode = null, biasNode = null ) { super( value, uvNode, levelNode, biasNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isCubeTextureNode = true; } + /** + * Overwrites the default implementation to return a fixed value `'cubeTexture'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'cubeTexture'; } + /** + * Returns a default uvs based on the mapping type of the cube texture. + * + * @return {Node} The default uv attribute. + */ getDefaultUV() { const texture = this.value; @@ -7627,8 +10408,22 @@ class CubeTextureNode extends TextureNode { } + /** + * Overwritten with an empty implementation since the `updateMatrix` flag is ignored + * for cube textures. The uv transformation matrix is not applied to cube textures. + * + * @param {Boolean} value - The update toggle. + */ setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for CubeTextureNode + /** + * Setups the uv node. Depending on the backend as well as the texture type, it might be necessary + * to modify the uv node for correct sampling. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to setup. + * @return {Node} The updated uv node. + */ setupUV( builder, uvNode ) { const texture = this.value; @@ -7645,6 +10440,13 @@ class CubeTextureNode extends TextureNode { } + /** + * Generates the uv code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} cubeUV - The uv node to generate code for. + * @return {String} The generated code snippet. + */ generateUV( builder, cubeUV ) { return cubeUV.build( builder, 'vec3' ); @@ -7653,8 +10455,34 @@ class CubeTextureNode extends TextureNode { } +/** + * TSL function for creating a cube texture node. + * + * @function + * @param {CubeTexture} value - The cube texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + * @returns {CubeTextureNode} + */ const cubeTexture = /*@__PURE__*/ nodeProxy( CubeTextureNode ); +/** @module BufferNode **/ + +/** + * A special type of uniform node which represents array-like data + * as uniform buffers. The access usually happens via `element()` + * which returns an instance of {@link ArrayElementNode}. For example: + * + * ```js + * const bufferNode = buffer( array, 'mat4', count ); + * const matrixNode = bufferNode.element( index ); // access a matrix from the buffer + * ``` + * In general, it is recommended to use the more managed {@link UniformArrayNode} + * since it handles more input types and automatically cares about buffer paddings. + * + * @augments module:UniformNode~UniformNode + */ class BufferNode extends UniformNode { static get type() { @@ -7663,23 +10491,61 @@ class BufferNode extends UniformNode { } + /** + * Constructs a new buffer node. + * + * @param {Array} value - Array-like buffer data. + * @param {String} bufferType - The data type of the buffer. + * @param {Number} [bufferCount=0] - The count of buffer elements. + */ constructor( value, bufferType, bufferCount = 0 ) { super( value, bufferType ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBufferNode = true; + /** + * The data type of the buffer. + * + * @type {String} + */ this.bufferType = bufferType; + + /** + * The uniform node that holds the value of the reference node. + * + * @type {Number} + * @default 0 + */ this.bufferCount = bufferCount; } + /** + * The data type of the buffer elements. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The element type. + */ getElementType( builder ) { return this.getNodeType( builder ); } + /** + * Overwrites the default implementation to return a fixed value `'buffer'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'buffer'; @@ -7688,8 +10554,24 @@ class BufferNode extends UniformNode { } +/** + * TSL function for creating a buffer node. + * + * @function + * @param {Array} value - Array-like buffer data. + * @param {String} type - The data type of a buffer element. + * @param {Number} count - The count of buffer elements. + * @returns {BufferNode} + */ const buffer = ( value, type, count ) => nodeObject( new BufferNode( value, type, count ) ); +/** @module UniformArrayNode **/ + +/** + * Represents the element access on uniform array nodes. + * + * @augments ArrayElementNode + */ class UniformArrayElementNode extends ArrayElementNode { static get type() { @@ -7698,10 +10580,23 @@ class UniformArrayElementNode extends ArrayElementNode { } - constructor( arrayBuffer, indexNode ) { + /** + * Constructs a new buffer node. + * + * @param {UniformArrayNode} uniformArrayNode - The uniform array node to access. + * @param {IndexNode} indexNode - The index data that define the position of the accessed element in the array. + */ + constructor( uniformArrayNode, indexNode ) { - super( arrayBuffer, indexNode ); + super( uniformArrayNode, indexNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isArrayBufferElementNode = true; } @@ -7718,6 +10613,23 @@ class UniformArrayElementNode extends ArrayElementNode { } +/** + * Similar to {@link module:BufferNode~BufferNode} this module represents array-like data as + * uniform buffers. Unlike {@link module:BufferNode~BufferNode}, it can handle more common + * data types in the array (e.g `three.js` primitives) and automatically + * manage buffer padding. It should be the first choice when working with + * uniforms buffers. + * ```js + * const tintColors = uniformArray( [ + * new Color( 1, 0, 0 ), + * new Color( 0, 1, 0 ), + * new Color( 0, 0, 1 ) + * ], 'color' ); + * + * const redColor = tintColors.element( 0 ); + * + * @augments module:BufferNode~BufferNode + */ class UniformArrayNode extends BufferNode { static get type() { @@ -7726,32 +10638,89 @@ class UniformArrayNode extends BufferNode { } + /** + * Constructs a new uniform array node. + * + * @param {Array} value - Array holding the buffer data. + * @param {String?} [elementType=null] - The data type of a buffer element. + */ constructor( value, elementType = null ) { super( null ); + /** + * Array holding the buffer data. Unlike {@link module:BufferNode~BufferNode}, the array can + * hold number primitives as well as three.js objects like vectors, matrices + * or colors. + * + * @type {Array} + */ this.array = value; + + /** + * The data type of an array element. + * + * @type {String} + */ this.elementType = elementType === null ? getValueType( value[ 0 ] ) : elementType; + + /** + * The padded type. Uniform buffers must conform to a certain buffer layout + * so a separate type is computed to ensure correct buffer size. + * + * @type {String} + */ this.paddedType = this.getPaddedType(); + /** + * Overwritten since uniform array nodes are updated per render. + * + * @type {String} + * @default 'render' + */ this.updateType = NodeUpdateType.RENDER; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isArrayBufferNode = true; } - getNodeType() { + /** + * This method is overwritten since the node type is inferred from the + * {@link module:UniformArrayNode~UniformArrayNode#paddedType}. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ + getNodeType( /*builder*/ ) { return this.paddedType; } + /** + * The data type of the array elements. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The element type. + */ getElementType() { return this.elementType; } + /** + * Returns the padded type based on the element type. + * + * @return {String} The padded type. + */ getPaddedType() { const elementType = this.elementType; @@ -7780,6 +10749,12 @@ class UniformArrayNode extends BufferNode { } + /** + * The update makes sure to correctly transfer the data from the (complex) objects + * in the array to the internal, correctly padded value buffer. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( /*frame*/ ) { const { array, value } = this; @@ -7880,6 +10855,12 @@ class UniformArrayNode extends BufferNode { } + /** + * Implement the value buffer creation based on the array data. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {null} + */ setup( builder ) { const length = this.array.length; @@ -7901,6 +10882,13 @@ class UniformArrayNode extends BufferNode { } + /** + * Overwrites the default `element()` method to provide element access + * based on {@link module:UniformArrayNode~UniformArrayNode}. + * + * @param {IndexNode} indexNode - The index node. + * @return {UniformArrayElementNode} + */ element( indexNode ) { return nodeObject( new UniformArrayElementNode( this, nodeObject( indexNode ) ) ); @@ -7909,10 +10897,24 @@ class UniformArrayNode extends BufferNode { } +/** + * TSL function for creating an uniform array node. + * + * @function + * @param {Array} values - Array-like data. + * @param {String} nodeType - The data type of the array elements. + * @returns {UniformArrayNode} + */ const uniformArray = ( values, nodeType ) => nodeObject( new UniformArrayNode( values, nodeType ) ); -// - +/** + * @function + * @deprecated since r168. Use {@link uniformArray} instead. + * + * @param {Array} values - Array-like data. + * @param {String} nodeType - The data type of the array elements. + * @returns {UniformArrayNode} + */ const uniforms = ( values, nodeType ) => { // @deprecated, r168 console.warn( 'TSL.UniformArrayNode: uniforms() has been renamed to uniformArray().' ); @@ -7920,6 +10922,17 @@ const uniforms = ( values, nodeType ) => { // @deprecated, r168 }; +// TODO: Avoid duplicated code and ues only ReferenceBaseNode or ReferenceNode + +/** @module ReferenceNode **/ + +/** + * This class is only relevant if the referenced property is array-like. + * In this case, `ReferenceElementNode` allows to refer to a specific + * element inside the data structure via an index. + * + * @augments ArrayElementNode + */ class ReferenceElementNode extends ArrayElementNode { static get type() { @@ -7928,16 +10941,43 @@ class ReferenceElementNode extends ArrayElementNode { } + /** + * Constructs a new reference element node. + * + * @param {Node?} referenceNode - The reference node. + * @param {Node} indexNode - The index node that defines the element access. + */ constructor( referenceNode, indexNode ) { super( referenceNode, indexNode ); + /** + * Similar to {@link module:ReferenceNode~ReferenceNode#reference}, an additional + * property references to the current node. + * + * @type {Node?} + * @default null + */ this.referenceNode = referenceNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isReferenceElementNode = true; } + /** + * This method is overwritten since the node type is inferred from + * the uniform type of the reference node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType() { return this.referenceNode.uniformType; @@ -7956,7 +10996,14 @@ class ReferenceElementNode extends ArrayElementNode { } -// TODO: Extends this from ReferenceBaseNode +/** + * This type of node establishes a reference to a property of another object. + * In this way, the value of the node is automatically linked to the value of + * referenced object. Reference nodes internally represent the linked value + * as a uniform. + * + * @augments Node + */ class ReferenceNode extends Node { static get type() { @@ -7965,31 +11012,118 @@ class ReferenceNode extends Node { } + /** + * Constructs a new reference node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} uniformType - The uniform type that should be used to represent the property value. + * @param {Object?} [object=null] - The object the property belongs to. + * @param {Number?} [count=null] - When the linked property is an array-like, this parameter defines its length. + */ constructor( property, uniformType, object = null, count = null ) { super(); + /** + * The name of the property the node refers to. + * + * @type {String} + */ this.property = property; + + /** + * The uniform type that should be used to represent the property value. + * + * @type {String} + */ this.uniformType = uniformType; + + /** + * The object the property belongs to. + * + * @type {Object?} + * @default null + */ this.object = object; + + /** + * When the linked property is an array, this parameter defines its length. + * + * @type {Number?} + * @default null + */ this.count = count; + /** + * The property name might have dots so nested properties can be referred. + * The hierarchy of the names is stored inside this array. + * + * @type {Array} + */ this.properties = property.split( '.' ); + + /** + * Points to the current referred object. This property exists next to {@link module:ReferenceNode~ReferenceNode#object} + * since the final reference might be updated from calling code. + * + * @type {Object?} + * @default null + */ this.reference = object; + + /** + * The uniform node that holds the value of the reference node. + * + * @type {UniformNode} + * @default null + */ this.node = null; + + /** + * The uniform group of the internal uniform. + * + * @type {UniformGroupNode} + * @default null + */ this.group = null; + + /** + * An optional label of the internal uniform node. + * + * @type {String?} + * @default null + */ this.name = null; + /** + * Overwritten since reference nodes are updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; } + /** + * When the referred property is array-like, this method can be used + * to access elements via an index node. + * + * @param {IndexNode} indexNode - indexNode. + * @return {ReferenceElementNode} A reference to an element. + */ element( indexNode ) { return nodeObject( new ReferenceElementNode( this, nodeObject( indexNode ) ) ); } + /** + * Sets the uniform group for this reference node. + * + * @param {UniformGroupNode} group - The uniform group to set. + * @return {ReferenceNode} A reference to this node. + */ setGroup( group ) { this.group = group; @@ -7998,6 +11132,12 @@ class ReferenceNode extends Node { } + /** + * Sets the label for the internal uniform. + * + * @param {String} name - The label to set. + * @return {ReferenceNode} A reference to this node. + */ label( name ) { this.name = name; @@ -8006,6 +11146,12 @@ class ReferenceNode extends Node { } + /** + * Sets the node type which automatically defines the internal + * uniform type. + * + * @param {String} uniformType - The type to set. + */ setNodeType( uniformType ) { let node = null; @@ -8044,6 +11190,13 @@ class ReferenceNode extends Node { } + /** + * This method is overwritten since the node type is inferred from + * the type of the reference node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( this.node === null ) { @@ -8057,6 +11210,12 @@ class ReferenceNode extends Node { } + /** + * Returns the property value from the given referred object. + * + * @param {Object} [object=this.reference] - The object to retrieve the property value from. + * @return {Any} The value. + */ getValueFromReference( object = this.reference ) { const { properties } = this; @@ -8073,6 +11232,13 @@ class ReferenceNode extends Node { } + /** + * Allows to update the reference based on the given state. The state is only + * evaluated {@link module:ReferenceNode~ReferenceNode#object} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.object !== null ? this.object : state.object; @@ -8081,7 +11247,13 @@ class ReferenceNode extends Node { } - setup() { + /** + * The output of the reference node is the internal uniform node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {UniformNode} The output node. + */ + setup( /* builder */ ) { this.updateValue(); @@ -8089,12 +11261,21 @@ class ReferenceNode extends Node { } + /** + * Overwritten to to update the internal uniform value. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( /*frame*/ ) { this.updateValue(); } + /** + * Retrieves the value from the referred object property and uses it + * to updated the internal uniform. + */ updateValue() { if ( this.node === null ) this.setNodeType( this.uniformType ); @@ -8115,9 +11296,43 @@ class ReferenceNode extends Node { } +/** + * TSL function for creating a reference node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Object} object - The object the property belongs to. + * @returns {ReferenceNode} + */ const reference = ( name, type, object ) => nodeObject( new ReferenceNode( name, type, object ) ); + +/** + * TSL function for creating a reference node. Use this function if you want need a reference + * to an array-like property that should be represented as a uniform buffer. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Number} count - The number of value inside the array-like object. + * @param {Object} object - An array-like object the property belongs to. + * @returns {ReferenceNode} + */ const referenceBuffer = ( name, type, count, object ) => nodeObject( new ReferenceNode( name, type, object, count ) ); +/** @module MaterialReferenceNode **/ + +/** + * This node is a special type of reference node which is intended + * for linking material properties with node values. + * ```js + * const opacityNode = materialReference( 'opacity', 'float', material ); + * ``` + * When changing `material.opacity`, the node value of `opacityNode` will + * automatically be updated. + * + * @augments module:ReferenceNode~ReferenceNode + */ class MaterialReferenceNode extends ReferenceNode { static get type() { @@ -8126,26 +11341,45 @@ class MaterialReferenceNode extends ReferenceNode { } + /** + * Constructs a new material reference node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} inputType - The uniform type that should be used to represent the property value. + * @param {Material?} [material=null] - The material the property belongs to. When no material is set, + * the node refers to the material of the current rendered object. + */ constructor( property, inputType, material = null ) { super( property, inputType, material ); + /** + * The material the property belongs to. When no material is set, + * the node refers to the material of the current rendered object. + * + * @type {Material?} + * @default null + */ this.material = material; - //this.updateType = NodeUpdateType.RENDER; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMaterialReferenceNode = true; } - /*setNodeType( node ) { - - super.setNodeType( node ); - - this.node.groupNode = renderGroup; - - }*/ - + /** + * Updates the reference based on the given state. The state is only evaluated + * {@link module:MaterialReferenceNode~MaterialReferenceNode#material} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.material !== null ? this.material : state.material; @@ -8156,8 +11390,25 @@ class MaterialReferenceNode extends ReferenceNode { } -const materialReference = ( name, type, material ) => nodeObject( new MaterialReferenceNode( name, type, material ) ); +/** + * TSL function for creating a material reference node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Material?} [material=null] - The material the property belongs to. + * When no material is set, the node refers to the material of the current rendered object. + * @returns {MaterialReferenceNode} + */ +const materialReference = ( name, type, material = null ) => nodeObject( new MaterialReferenceNode( name, type, material ) ); + +/** @module Tangent **/ +/** + * TSL object that represents the tangent attribute of the current rendered object. + * + * @type {Node} + */ const tangentGeometry = /*@__PURE__*/ Fn( ( builder ) => { if ( builder.geometry.hasAttribute( 'tangent' ) === false ) { @@ -8170,26 +11421,119 @@ const tangentGeometry = /*@__PURE__*/ Fn( ( builder ) => { } )(); +/** + * TSL object that represents the vertex tangent in local space of the current rendered object. + * + * @type {Node} + */ const tangentLocal = /*@__PURE__*/ tangentGeometry.xyz.toVar( 'tangentLocal' ); + +/** + * TSL object that represents the vertex tangent in view space of the current rendered object. + * + * @type {Node} + */ const tangentView = /*@__PURE__*/ modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.varying( 'v_tangentView' ).normalize().toVar( 'tangentView' ); + +/** + * TSL object that represents the vertex tangent in world space of the current rendered object. + * + * @type {Node} + */ const tangentWorld = /*@__PURE__*/ tangentView.transformDirection( cameraViewMatrix ).varying( 'v_tangentWorld' ).normalize().toVar( 'tangentWorld' ); + +/** + * TSL object that represents the transformed vertex tangent in view space of the current rendered object. + * + * @type {Node} + */ const transformedTangentView = /*@__PURE__*/ tangentView.toVar( 'transformedTangentView' ); + +/** + * TSL object that represents the transformed vertex tangent in world space of the current rendered object. + * + * @type {Node} + */ const transformedTangentWorld = /*@__PURE__*/ transformedTangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedTangentWorld' ); +/** @module Bitangent **/ + const getBitangent = ( crossNormalTangent ) => crossNormalTangent.mul( tangentGeometry.w ).xyz; +/** + * TSL object that represents the bitangent attribute of the current rendered object. + * + * @type {Node} + */ const bitangentGeometry = /*@__PURE__*/ varying( getBitangent( normalGeometry.cross( tangentGeometry ) ), 'v_bitangentGeometry' ).normalize().toVar( 'bitangentGeometry' ); + +/** + * TSL object that represents the vertex bitangent in local space of the current rendered object. + * + * @type {Node} + */ const bitangentLocal = /*@__PURE__*/ varying( getBitangent( normalLocal.cross( tangentLocal ) ), 'v_bitangentLocal' ).normalize().toVar( 'bitangentLocal' ); + +/** + * TSL object that represents the vertex bitangent in view space of the current rendered object. + * + * @type {Node} + */ const bitangentView = /*@__PURE__*/ varying( getBitangent( normalView.cross( tangentView ) ), 'v_bitangentView' ).normalize().toVar( 'bitangentView' ); + +/** + * TSL object that represents the vertex bitangent in world space of the current rendered object. + * + * @type {Node} + */ const bitangentWorld = /*@__PURE__*/ varying( getBitangent( normalWorld.cross( tangentWorld ) ), 'v_bitangentWorld' ).normalize().toVar( 'bitangentWorld' ); + +/** + * TSL object that represents the transformed vertex bitangent in view space of the current rendered object. + * + * @type {Node} + */ const transformedBitangentView = /*@__PURE__*/ getBitangent( transformedNormalView.cross( transformedTangentView ) ).normalize().toVar( 'transformedBitangentView' ); + +/** + * TSL object that represents the transformed vertex bitangent in world space of the current rendered object. + * + * @type {Node} + */ const transformedBitangentWorld = /*@__PURE__*/ transformedBitangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedBitangentWorld' ); +/** @module AccessorsUtils **/ + +/** + * TSL object that represents the TBN matrix in view space. + * + * @type {Node} + */ const TBNViewMatrix = /*@__PURE__*/ mat3( tangentView, bitangentView, normalView ); +/** + * TSL object that represents the parallax direction. + * + * @type {Node} + */ const parallaxDirection = /*@__PURE__*/ positionViewDirection.mul( TBNViewMatrix )/*.normalize()*/; + +/** + * TSL function for computing parallax uv coordinates. + * + * @function + * @param {Node} uv - A uv node. + * @param {Node} scale - A scale node. + * @returns {Node} Parallax uv coordinates. + */ const parallaxUV = ( uv, scale ) => uv.sub( parallaxDirection.mul( scale ) ); +/** + * TSL function for computing bent normals. + * + * @function + * @returns {Node} Bent normals. + */ const transformedBentNormalView = /*@__PURE__*/ ( () => { // https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/anisotropy @@ -8203,6 +11547,8 @@ const transformedBentNormalView = /*@__PURE__*/ ( () => { } )(); +/** @module NormalMapNode **/ + // Normal Mapping Without Precomputed Tangents // http://www.thetenthplanet.de/archives/1180 @@ -8250,8 +11596,8 @@ class NormalMapNode extends TempNode { /** * Constructs a new normal map node. * - * @param {Node} node - Represents the normal map data. - * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. + * @param {Node} node - Represents the normal map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. */ constructor( node, scaleNode = null ) { @@ -8260,14 +11606,14 @@ class NormalMapNode extends TempNode { /** * Represents the normal map data. * - * @type {Node} + * @type {Node} */ this.node = node; /** * Controls the intensity of the effect. * - * @type {Node?} + * @type {Node?} * @default null */ this.scaleNode = scaleNode; @@ -8327,8 +11673,18 @@ class NormalMapNode extends TempNode { } +/** + * TSL function for creating a normal map node. + * + * @function + * @param {Node} node - Represents the normal map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. + * @returns {NormalMapNode} + */ const normalMap = /*@__PURE__*/ nodeProxy( NormalMapNode ); +/** @module BumpMapNode **/ + // Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen // https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf @@ -8388,8 +11744,8 @@ class BumpMapNode extends TempNode { /** * Constructs a new bump map node. * - * @param {Node} textureNode - Represents the bump map data. - * @param {Node?} [scaleNode=null] - Controls the intensity of the bump effect. + * @param {Node} textureNode - Represents the bump map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the bump effect. */ constructor( textureNode, scaleNode = null ) { @@ -8398,14 +11754,14 @@ class BumpMapNode extends TempNode { /** * Represents the bump map data. * - * @type {Node} + * @type {Node} */ this.textureNode = textureNode; /** * Controls the intensity of the bump effect. * - * @type {Node?} + * @type {Node?} * @default null */ this.scaleNode = scaleNode; @@ -8427,10 +11783,28 @@ class BumpMapNode extends TempNode { } +/** + * TSL function for creating a bump map node. + * + * @function + * @param {Node} textureNode - Represents the bump map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the bump effect. + * @returns {BumpMapNode} + */ const bumpMap = /*@__PURE__*/ nodeProxy( BumpMapNode ); +/** @module MaterialNode **/ + const _propertyCache = new Map(); +/** + * This class should simplify the node access to material properties. + * It internal uses reference nodes to make sure changes to material + * properties are automatically reflected to predefined TSL objects + * like e.g. `materialColor`. + * + * @augments Node + */ class MaterialNode extends Node { static get type() { @@ -8439,14 +11813,31 @@ class MaterialNode extends Node { } + /** + * Constructs a new material node. + * + * @param {String} scope - The scope defines what kind of material property is referred by the node. + */ constructor( scope ) { super(); + /** + * The scope defines what material property is referred by the node. + * + * @type {String} + */ this.scope = scope; } + /** + * Returns a cached reference node for the given property and type. + * + * @param {String} property - The name of the material property. + * @param {String} type - The uniform type of the property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getCache( property, type ) { let node = _propertyCache.get( property ); @@ -8463,24 +11854,49 @@ class MaterialNode extends Node { } + /** + * Returns a float-typed material reference node for the given property name. + * + * @param {String} property - The name of the material property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getFloat( property ) { return this.getCache( property, 'float' ); } + /** + * Returns a color-typed material reference node for the given property name. + * + * @param {String} property - The name of the material property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getColor( property ) { return this.getCache( property, 'color' ); } + /** + * Returns a texture-typed material reference node for the given property name. + * + * @param {String} property - The name of the material property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getTexture( property ) { return this.getCache( property === 'map' ? 'map' : property + 'Map', 'texture' ); } + /** + * The node setup is done depending on the selected scope. Multiple material properties + * might be grouped into a single node composition if they logically belong together. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The node representing the selected scope. + */ setup( builder ) { const material = builder.context.material; @@ -8530,15 +11946,15 @@ class MaterialNode extends Node { } else if ( scope === MaterialNode.SPECULAR_INTENSITY ) { - const specularIntensity = this.getFloat( scope ); + const specularIntensityNode = this.getFloat( scope ); - if ( material.specularMap ) { + if ( material.specularIntensityMap && material.specularIntensityMap.isTexture === true ) { - node = specularIntensity.mul( this.getTexture( scope ).a ); + node = specularIntensityNode.mul( this.getTexture( scope ).a ); } else { - node = specularIntensity; + node = specularIntensityNode; } @@ -8753,7 +12169,7 @@ class MaterialNode extends Node { node = this.getTexture( scope ).rgb.mul( this.getFloat( 'lightMapIntensity' ) ); - } else if ( scope === MaterialNode.AO_MAP ) { + } else if ( scope === MaterialNode.AO ) { node = this.getTexture( scope ).r.sub( 1.0 ).mul( this.getFloat( 'aoMapIntensity' ) ).add( 1.0 ); @@ -8804,50 +12220,293 @@ MaterialNode.LINE_DASH_SIZE = 'dashSize'; MaterialNode.LINE_GAP_SIZE = 'gapSize'; MaterialNode.LINE_WIDTH = 'linewidth'; MaterialNode.LINE_DASH_OFFSET = 'dashOffset'; -MaterialNode.POINT_WIDTH = 'pointWidth'; +MaterialNode.POINT_SIZE = 'size'; MaterialNode.DISPERSION = 'dispersion'; MaterialNode.LIGHT_MAP = 'light'; -MaterialNode.AO_MAP = 'ao'; +MaterialNode.AO = 'ao'; +/** + * TSL object that represents alpha test of the current material. + * + * @type {Node} + */ const materialAlphaTest = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ALPHA_TEST ); + +/** + * TSL object that represents the diffuse color of the current material. + * The value is composed via `color` * `map`. + * + * @type {Node} + */ const materialColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.COLOR ); + +/** + * TSL object that represents the shininess of the current material. + * + * @type {Node} + */ const materialShininess = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHININESS ); + +/** + * TSL object that represents the emissive color of the current material. + * The value is composed via `emissive` * `emissiveIntensity` * `emissiveMap`. + * + * @type {Node} + */ const materialEmissive = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.EMISSIVE ); + +/** + * TSL object that represents the opacity of the current material. + * The value is composed via `opacity` * `alphaMap`. + * + * @type {Node} + */ const materialOpacity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.OPACITY ); + +/** + * TSL object that represents the specular of the current material. + * + * @type {Node} + */ const materialSpecular = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR ); +/** + * TSL object that represents the specular intensity of the current material. + * The value is composed via `specularIntensity` * `specularMap.a`. + * + * @type {Node} + */ const materialSpecularIntensity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_INTENSITY ); + +/** + * TSL object that represents the specular color of the current material. + * The value is composed via `specularColor` * `specularMap.rgb`. + * + * @type {Node} + */ const materialSpecularColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR ); +/** + * TSL object that represents the specular strength of the current material. + * The value is composed via `specularMap.r`. + * + * @type {Node} + */ const materialSpecularStrength = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_STRENGTH ); + +/** + * TSL object that represents the reflectivity of the current material. + * + * @type {Node} + */ const materialReflectivity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.REFLECTIVITY ); + +/** + * TSL object that represents the roughness of the current material. + * The value is composed via `roughness` * `roughnessMap.g`. + * + * @type {Node} + */ const materialRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS ); + +/** + * TSL object that represents the metalness of the current material. + * The value is composed via `metalness` * `metalnessMap.b`. + * + * @type {Node} + */ const materialMetalness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.METALNESS ); -const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.NORMAL ).context( { getUV: null } ); + +/** + * TSL object that represents the normal of the current material. + * The value will be either `normalMap` * `normalScale`, `bumpMap` * `bumpScale` or `normalView`. + * + * @type {Node} + */ +const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.NORMAL ); + +/** + * TSL object that represents the clearcoat of the current material. + * The value is composed via `clearcoat` * `clearcoatMap.r` + * + * @type {Node} + */ const materialClearcoat = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT ); + +/** + * TSL object that represents the clearcoat roughness of the current material. + * The value is composed via `clearcoatRoughness` * `clearcoatRoughnessMap.r`. + * + * @type {Node} + */ const materialClearcoatRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_ROUGHNESS ); -const materialClearcoatNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL ).context( { getUV: null } ); + +/** + * TSL object that represents the clearcoat normal of the current material. + * The value will be either `clearcoatNormalMap` or `normalView`. + * + * @type {Node} + */ +const materialClearcoatNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL ); + +/** + * TSL object that represents the rotation of the current sprite material. + * + * @type {Node} + */ const materialRotation = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROTATION ); + +/** + * TSL object that represents the sheen color of the current material. + * The value is composed via `sheen` * `sheenColor` * `sheenColorMap`. + * + * @type {Node} + */ const materialSheen = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN ); + +/** + * TSL object that represents the sheen roughness of the current material. + * The value is composed via `sheenRoughness` * `sheenRoughnessMap.a`. + * + * @type {Node} + */ const materialSheenRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN_ROUGHNESS ); + +/** + * TSL object that represents the anisotropy of the current material. + * + * @type {Node} + */ const materialAnisotropy = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ANISOTROPY ); + +/** + * TSL object that represents the iridescence of the current material. + * + * @type {Node} + */ const materialIridescence = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE ); + +/** + * TSL object that represents the iridescence IOR of the current material. + * + * @type {Node} + */ const materialIridescenceIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_IOR ); + +/** + * TSL object that represents the iridescence thickness of the current material. + * + * @type {Node} + */ const materialIridescenceThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_THICKNESS ); + +/** + * TSL object that represents the transmission of the current material. + * The value is composed via `transmission` * `transmissionMap.r`. + * + * @type {Node} + */ const materialTransmission = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.TRANSMISSION ); + +/** + * TSL object that represents the thickness of the current material. + * The value is composed via `thickness` * `thicknessMap.g`. + * + * @type {Node} + */ const materialThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.THICKNESS ); + +/** + * TSL object that represents the IOR of the current material. + * + * @type {Node} + */ const materialIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IOR ); + +/** + * TSL object that represents the attenuation distance of the current material. + * + * @type {Node} + */ const materialAttenuationDistance = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_DISTANCE ); + +/** + * TSL object that represents the attenuation color of the current material. + * + * @type {Node} + */ const materialAttenuationColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_COLOR ); + +/** + * TSL object that represents the scale of the current dashed line material. + * + * @type {Node} + */ const materialLineScale = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_SCALE ); + +/** + * TSL object that represents the dash size of the current dashed line material. + * + * @type {Node} + */ const materialLineDashSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_SIZE ); + +/** + * TSL object that represents the gap size of the current dashed line material. + * + * @type {Node} + */ const materialLineGapSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_GAP_SIZE ); + +/** + * TSL object that represents the line width of the current line material. + * + * @type {Node} + */ const materialLineWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_WIDTH ); + +/** + * TSL object that represents the dash offset of the current line material. + * + * @type {Node} + */ const materialLineDashOffset = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_OFFSET ); -const materialPointWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.POINT_WIDTH ); + +/** + * TSL object that represents the point size of the current points material. + * + * @type {Node} + */ +const materialPointSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.POINT_SIZE ); + +/** + * TSL object that represents the dispersion of the current material. + * + * @type {Node} + */ const materialDispersion = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.DISPERSION ); + +/** + * TSL object that represents the light map of the current material. + * The value is composed via `lightMapIntensity` * `lightMap.rgb`. + * + * @type {Node} + */ const materialLightMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LIGHT_MAP ); -const materialAOMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.AO_MAP ); + +/** + * TSL object that represents the ambient occlusion map of the current material. + * The value is composed via `aoMap.r` - 1 * `aoMapIntensity` + 1. + * + * @type {Node} + */ +const materialAO = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.AO ); + +/** + * TSL object that represents the anisotropy vector of the current material. + * + * @type {Node} + */ const materialAnisotropyVector = /*@__PURE__*/ uniform( new Vector2() ).onReference( function ( frame ) { return frame.material; @@ -8858,40 +12517,20 @@ const materialAnisotropyVector = /*@__PURE__*/ uniform( new Vector2() ).onRefere } ); -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 ); +/** @module ModelViewProjectionNode **/ - } - - const position = this.positionNode || positionLocal; - const viewMatrix = builder.renderer.nodes.modelViewMatrix || modelViewMatrix; - - return cameraProjectionMatrix.mul( viewMatrix ).mul( position ); +/** + * TSL object that represents the position in clip space after the model-view-projection transform of the current rendered object. + * + * @type {VaryingNode} + */ +const modelViewProjection = /*@__PURE__*/ ( Fn( ( builder ) => { - } + return builder.context.setupModelViewProjection(); -} +}, 'vec4' ).once() )().varying( 'v_modelViewProjection' ); -const modelViewProjection = /*@__PURE__*/ nodeProxy( ModelViewProjectionNode ); +/** @module IndexNode **/ /** * This class represents shader indices of different types. The following predefined node @@ -9005,13 +12644,58 @@ IndexNode.INVOCATION_LOCAL = 'invocationLocal'; IndexNode.INVOCATION_SUBGROUP = 'invocationSubgroup'; IndexNode.DRAW = 'draw'; +/** + * TSL object that represents the index of a vertex within a mesh. + * + * @type {IndexNode} + */ const vertexIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.VERTEX ); + +/** + * TSL object that represents the index of either a mesh instance or an invocation of a compute shader. + * + * @type {IndexNode} + */ const instanceIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INSTANCE ); + +/** + * TSL object that represents the index of the subgroup the current compute invocation belongs to. + * + * @type {IndexNode} + */ const subgroupIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.SUBGROUP ); + +/** + * TSL object that represents the index of a compute invocation within the scope of a subgroup. + * + * @type {IndexNode} + */ const invocationSubgroupIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INVOCATION_SUBGROUP ); + +/** + * TSL object that represents the index of a compute invocation within the scope of a workgroup load. + * + * @type {IndexNode} + */ const invocationLocalIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INVOCATION_LOCAL ); + +/** + * TSL object that represents the index of a draw call. + * + * @type {IndexNode} + */ const drawIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.DRAW ); +/** @module InstanceNode **/ + +/** + * This node implements the vertex shader logic which is required + * when rendering 3D objects via instancing. The code makes sure + * vertex positions, normals and colors can be modified via instanced + * data. + * + * @augments Node + */ class InstanceNode extends Node { static get type() { @@ -9020,25 +12704,84 @@ class InstanceNode extends Node { } + /** + * Constructs a new instance node. + * + * @param {Number} count - The number of instances. + * @param {InstancedBufferAttribute} instanceMatrix - Instanced buffer attribute representing the instance transformations. + * @param {InstancedBufferAttribute} instanceColor - Instanced buffer attribute representing the instance colors. + */ constructor( count, instanceMatrix, instanceColor ) { super( 'void' ); + /** + * The number of instances. + * + * @type {Number} + */ this.count = count; + + /** + * Instanced buffer attribute representing the transformation of instances. + * + * @type {InstancedBufferAttribute} + */ this.instanceMatrix = instanceMatrix; + + /** + * Instanced buffer attribute representing the color of instances. + * + * @type {InstancedBufferAttribute} + */ this.instanceColor = instanceColor; + /** + * The node that represents the instance matrix data. + * + * @type {Node} + */ this.instanceMatrixNode = null; + /** + * The node that represents the instance color data. + * + * @type {Node} + */ this.instanceColorNode = null; + /** + * The update type is set to `frame` since an update + * of instanced buffer data must be checked per frame. + * + * @type {String} + * @default 'frame' + */ this.updateType = NodeUpdateType.FRAME; + /** + * A reference to a buffer that is used by `instanceMatrixNode`. + * + * @type {InstancedInterleavedBuffer} + */ this.buffer = null; + + /** + * A reference to a buffer that is used by `instanceColorNode`. + * + * @type {InstancedInterleavedBuffer} + */ this.bufferColor = null; } + /** + * Setups the internal buffers and nodes and assigns the transformed vertex data + * to predefined node variables for accumulation. That follows the same patterns + * like with morph and skinning nodes. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const { count, instanceMatrix, instanceColor } = this; @@ -9118,6 +12861,11 @@ class InstanceNode extends Node { } + /** + * Checks if the internal buffers required an update. + * + * @param {NodeFrame} frame - The current node frame. + */ update( /*frame*/ ) { if ( this.instanceMatrix.usage !== DynamicDrawUsage && this.buffer !== null && this.instanceMatrix.version !== this.buffer.version ) { @@ -9136,8 +12884,25 @@ class InstanceNode extends Node { } +/** + * TSL function for creating an instance node. + * + * @function + * @param {Number} count - The number of instances. + * @param {InstancedBufferAttribute} instanceMatrix - Instanced buffer attribute representing the instance transformations. + * @param {InstancedBufferAttribute} instanceColor - Instanced buffer attribute representing the instance colors. + * @returns {InstanceNode} + */ const instance = /*@__PURE__*/ nodeProxy( InstanceNode ); +/** @module InstancedMeshNode **/ + +/** + * This is a special version of `InstanceNode` which requires the usage of {@link InstancedMesh}. + * It allows an easier setup of the instance node. + * + * @augments module:InstanceNode~InstanceNode + */ class InstancedMeshNode extends InstanceNode { static get type() { @@ -9146,20 +12911,46 @@ class InstancedMeshNode extends InstanceNode { } - constructor( instanceMesh ) { + /** + * Constructs a new instanced mesh node. + * + * @param {InstancedMesh} instancedMesh - The instanced mesh. + */ + constructor( instancedMesh ) { - const { count, instanceMatrix, instanceColor } = instanceMesh; + const { count, instanceMatrix, instanceColor } = instancedMesh; super( count, instanceMatrix, instanceColor ); - this.instanceMesh = instanceMesh; + /** + * A reference to the instanced mesh. + * + * @type {InstancedMesh} + */ + this.instancedMesh = instancedMesh; } } +/** + * TSL function for creating an instanced mesh node. + * + * @function + * @param {InstancedMesh} instancedMesh - The instancedMesh. + * @returns {InstancedMeshNode} + */ const instancedMesh = /*@__PURE__*/ nodeProxy( InstancedMeshNode ); +/** @module BatchNode **/ + +/** + * This node implements the vertex shader logic which is required + * when rendering 3D objects via batching. `BatchNode` must be used + * with instances of {@link BatchedMesh}. + * + * @augments Node + */ class BatchNode extends Node { static get type() { @@ -9168,21 +12959,41 @@ class BatchNode extends Node { } + /** + * Constructs a new batch node. + * + * @param {BatchedMesh} batchMesh - A reference to batched mesh. + */ constructor( batchMesh ) { super( 'void' ); + /** + * A reference to batched mesh. + * + * @type {BatchedMesh} + */ this.batchMesh = batchMesh; - + /** + * The batching index node. + * + * @type {IndexNode?} + * @default null + */ this.batchingIdNode = null; } + /** + * Setups the internal buffers and nodes and assigns the transformed vertex data + * to predefined node variables for accumulation. That follows the same patterns + * like with morph and skinning nodes. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { - // POSITION - if ( this.batchingIdNode === null ) { if ( builder.getDrawIndex() === null ) { @@ -9275,10 +13086,25 @@ class BatchNode extends Node { } +/** + * TSL function for creating a batch node. + * + * @function + * @param {BatchedMesh} batchMesh - A reference to batched mesh. + * @returns {BatchNode} + */ const batch = /*@__PURE__*/ nodeProxy( BatchNode ); +/** @module SkinningNode **/ + const _frameId = new WeakMap(); +/** + * This node implements the vertex transformation shader logic which is required + * for skinning/skeletal animation. + * + * @augments Node + */ class SkinningNode extends Node { static get type() { @@ -9287,18 +13113,52 @@ class SkinningNode extends Node { } + /** + * Constructs a new skinning node. + * + * @param {SkinnedMesh} skinnedMesh - The skinned mesh. + * @param {Boolean} [useReference=false] - Whether to use reference nodes for internal skinned mesh related data or not. + */ constructor( skinnedMesh, useReference = false ) { super( 'void' ); + /** + * The skinned mesh. + * + * @type {SkinnedMesh} + */ this.skinnedMesh = skinnedMesh; + + /** + * Whether to use reference nodes for internal skinned mesh related data or not. + * TODO: Explain the purpose of the property. + * + * @type {Boolean} + */ this.useReference = useReference; + /** + * The update type overwritten since skinning nodes are updated per object. + * + * @type {String} + */ this.updateType = NodeUpdateType.OBJECT; // + /** + * The skin index attribute. + * + * @type {AttributeNode} + */ this.skinIndexNode = attribute( 'skinIndex', 'uvec4' ); + + /** + * The skin weight attribute. + * + * @type {AttributeNode} + */ this.skinWeightNode = attribute( 'skinWeight', 'vec4' ); let bindMatrixNode, bindMatrixInverseNode, boneMatricesNode; @@ -9317,13 +13177,45 @@ class SkinningNode extends Node { } + /** + * The bind matrix node. + * + * @type {Node} + */ this.bindMatrixNode = bindMatrixNode; + + /** + * The bind matrix inverse node. + * + * @type {Node} + */ this.bindMatrixInverseNode = bindMatrixInverseNode; + + /** + * The bind matrices as a uniform buffer node. + * + * @type {Node} + */ this.boneMatricesNode = boneMatricesNode; + + /** + * The previous bind matrices as a uniform buffer node. + * Required for computing motion vectors. + * + * @type {Node?} + * @default null + */ this.previousBoneMatricesNode = null; } + /** + * Transforms the given vertex position via skinning. + * + * @param {Node} [boneMatrices=this.boneMatricesNode] - The bone matrices + * @param {Node} [position=positionLocal] - The vertex position in local space. + * @return {Node} The transformed vertex position. + */ getSkinnedPosition( boneMatrices = this.boneMatricesNode, position = positionLocal ) { const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; @@ -9348,6 +13240,13 @@ class SkinningNode extends Node { } + /** + * Transforms the given vertex normal via skinning. + * + * @param {Node} [boneMatrices=this.boneMatricesNode] - The bone matrices + * @param {Node} [normal=normalLocal] - The vertex normal in local space. + * @return {Node} The transformed vertex normal. + */ getSkinnedNormal( boneMatrices = this.boneMatricesNode, normal = normalLocal ) { const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; @@ -9372,6 +13271,12 @@ class SkinningNode extends Node { } + /** + * Transforms the given vertex normal via skinning. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The skinned position from the previous frame. + */ getPreviousSkinnedPosition( builder ) { const skinnedMesh = builder.object; @@ -9388,14 +13293,25 @@ class SkinningNode extends Node { } + /** + * Returns `true` if bone matrices from the previous frame are required. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Boolean} Whether bone matrices from the previous frame are required or not. + */ needsPreviousBoneMatrices( builder ) { const mrt = builder.renderer.getMRT(); - return mrt && mrt.has( 'velocity' ); + return ( mrt && mrt.has( 'velocity' ) ) || getDataFromObject( builder.object ).useVelocity === true; } + /** + * Setups the skinning node by assigning the transformed vertex data to predefined node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { if ( this.needsPreviousBoneMatrices( builder ) ) { @@ -9425,6 +13341,13 @@ class SkinningNode extends Node { } + /** + * Generates the code snippet of the skinning node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output. + * @return {String} The generated code snippet. + */ generate( builder, output ) { if ( output !== 'void' ) { @@ -9435,6 +13358,11 @@ class SkinningNode extends Node { } + /** + * Updates the state of the skinned mesh by updating the skeleton once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ update( frame ) { const object = this.useReference ? frame.object : this.skinnedMesh; @@ -9452,9 +13380,26 @@ class SkinningNode extends Node { } +/** + * TSL function for creating a skinning node. + * + * @function + * @param {SkinnedMesh} skinnedMesh - The skinned mesh. + * @returns {SkinningNode} + */ const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) ); + +/** + * TSL function for creating a skinning node with reference usage. + * + * @function + * @param {SkinnedMesh} skinnedMesh - The skinned mesh. + * @returns {SkinningNode} + */ const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) ); +/** @module LoopNode **/ + /** * This module offers a variety of ways to implement loops in TSL. In it's basic form it's: * ```js @@ -9468,7 +13413,7 @@ const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinn * * } ); *``` - * Nested loops can be definde in a compacted form: + * Nested loops can be defined in a compacted form: * ```js * Loop( 10, 5, ( { i, j } ) => { * @@ -9698,12 +13643,40 @@ class LoopNode extends Node { } +/** + * TSL function for creating a loop node. + * + * @function + * @param {...Any} params - A list of parameters. + * @returns {LoopNode} + */ const Loop = ( ...params ) => nodeObject( new LoopNode( nodeArray( params, 'int' ) ) ).append(); + +/** + * TSL function for creating a `Continue()` expression. + * + * @function + * @returns {ExpressionNode} + */ const Continue = () => expression( 'continue' ).append(); + +/** + * TSL function for creating a `Break()` expression. + * + * @function + * @returns {ExpressionNode} + */ const Break = () => expression( 'break' ).append(); -// +// deprecated +/** + * @function + * @deprecated since r168. Use {@link Loop} instead. + * + * @param {...any} params + * @returns {LoopNode} + */ const loop = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.LoopNode: loop() has been renamed to Loop().' ); @@ -9711,6 +13684,8 @@ const loop = ( ...params ) => { // @deprecated, r168 }; +/** @module MorphNode **/ + const _morphTextures = /*@__PURE__*/ new WeakMap(); const _morphVec4 = /*@__PURE__*/ new Vector4(); @@ -9853,7 +13828,12 @@ function getEntry( geometry ) { } - +/** + * This node implements the vertex transformation shader logic which is required + * for morph target animation. + * + * @augments Node + */ class MorphNode extends Node { static get type() { @@ -9862,17 +13842,43 @@ class MorphNode extends Node { } + /** + * Constructs a new morph node. + * + * @param {Mesh} mesh - The mesh holding the morph targets. + */ constructor( mesh ) { super( 'void' ); + /** + * The mesh holding the morph targets. + * + * @type {Mesh} + */ this.mesh = mesh; + + /** + * A uniform node which represents the morph base influence value. + * + * @type {UniformNode} + */ this.morphBaseInfluence = uniform( 1 ); + /** + * The update type overwritten since morph nodes are updated per object. + * + * @type {String} + */ this.updateType = NodeUpdateType.OBJECT; } + /** + * Setups the morph node by assigning the transformed vertex data to predefined node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const { geometry } = builder; @@ -9936,7 +13942,12 @@ class MorphNode extends Node { } - update() { + /** + * Updates the state of the morphed mesh by updating the base influence. + * + * @param {NodeFrame} frame - The current node frame. + */ + update( /*frame*/ ) { const morphBaseInfluence = this.morphBaseInfluence; @@ -9954,6 +13965,13 @@ class MorphNode extends Node { } +/** + * TSL function for creating a morph node. + * + * @function + * @param {Mesh} mesh - The mesh holding the morph targets. + * @returns {MorphNode} + */ const morphReference = /*@__PURE__*/ nodeProxy( MorphNode ); /** @@ -10007,7 +14025,7 @@ class AONode extends LightingNode { /** * Constructs a new AO node. * - * @param {Node} aoNode - The ambient occlusion node. + * @param {Node?} [aoNode=null] - The ambient occlusion node. */ constructor( aoNode = null ) { @@ -10016,7 +14034,8 @@ class AONode extends LightingNode { /** * The ambient occlusion node. * - * @type {Node} + * @type {Node?} + * @default null */ this.aoNode = aoNode; @@ -10031,7 +14050,7 @@ class AONode extends LightingNode { } /** - * `LightingContextNode` represents an extension of the {@link ContextNode} module + * `LightingContextNode` represents an extension of the {@link module:ContextNode~ContextNode} module * by adding lighting specific context data. It represents the runtime context of * {@link LightsNode}. * @@ -10049,9 +14068,9 @@ class LightingContextNode extends ContextNode { * Constructs a new lighting context node. * * @param {LightsNode} node - The lights node. - * @param {LightingModel} [lightingModel=null] - The current lighting model. - * @param {Node} [backdropNode=null] - A backdrop node. - * @param {Node} [backdropAlphaNode=null] - A backdrop alpha node. + * @param {LightingModel?} [lightingModel=null] - The current lighting model. + * @param {Node?} [backdropNode=null] - A backdrop node. + * @param {Node?} [backdropAlphaNode=null] - A backdrop alpha node. */ constructor( node, lightingModel = null, backdropNode = null, backdropAlphaNode = null ) { @@ -10060,7 +14079,7 @@ class LightingContextNode extends ContextNode { /** * The current lighting model. * - * @type {LightingModel} + * @type {LightingModel?} * @default null */ this.lightingModel = lightingModel; @@ -10068,7 +14087,7 @@ class LightingContextNode extends ContextNode { /** * A backdrop node. * - * @type {Node} + * @type {Node?} * @default null */ this.backdropNode = backdropNode; @@ -10076,7 +14095,7 @@ class LightingContextNode extends ContextNode { /** * A backdrop alpha node. * - * @type {Node} + * @type {Node?} * @default null */ this.backdropAlphaNode = backdropAlphaNode; @@ -10182,11 +14201,13 @@ class IrradianceNode extends LightingNode { } +/** @module ScreenNode **/ + let screenSizeVec, viewportVec; /** * This node provides a collection of screen related metrics. - * Depending on {@link ScreenNode#scope}, the nodes can represent + * Depending on {@link module:ScreenNode~ScreenNode#scope}, the nodes can represent * resolution or viewport data as well as fragment or uv coordinates. * * @augments Node @@ -10214,7 +14235,7 @@ class ScreenNode extends Node { * - `ScreenNode.COORDINATE`: Window-relative coordinates of the current fragment according to WebGPU standards. * - `ScreenNode.VIEWPORT`: The current viewport defined as a four-dimensional vector. * - `ScreenNode.SIZE`: The dimensions of the current bound framebuffer. - * - `ScreenNode.UV`: Normalized screen coordinates. + * - `ScreenNode.UV`: Normalized coordinates. * * @type {('coordinate'|'viewport'|'size'|'uv')} */ @@ -10362,19 +14383,62 @@ ScreenNode.UV = 'uv'; // Screen +/** + * TSL object that represents normalized screen coordinates, unitless in `[0, 1]`. + * + * @type {ScreenNode} + */ const screenUV = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.UV ); + +/** + * TSL object that represents the screen resolution in physical pixel units. + * + * @type {ScreenNode} + */ const screenSize = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.SIZE ); + +/** + * TSL object that represents the current `x`/`y` pixel position on the screen in physical pixel units. + * + * @type {ScreenNode} + */ const screenCoordinate = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.COORDINATE ); // Viewport +/** + * TSL object that represents the viewport rectangle as `x`, `y`, `width` and `height` in physical pixel units. + * + * @type {ScreenNode} + */ const viewport = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.VIEWPORT ); + +/** + * TSL object that represents the viewport resolution in physical pixel units. + * + * @type {ScreenNode} + */ const viewportSize = viewport.zw; + +/** + * TSL object that represents the current `x`/`y` pixel position on the viewport in physical pixel units. + * + * @type {ScreenNode} + */ const viewportCoordinate = /*@__PURE__*/ screenCoordinate.sub( viewport.xy ); + +/** + * TSL object that represents normalized viewport coordinates, unitless in `[0, 1]`. + * + * @type {ScreenNode} + */ const viewportUV = /*@__PURE__*/ viewportCoordinate.div( viewportSize ); // Deprecated +/** + * @deprecated since r169. Use {@link screenSize} instead. + */ const viewportResolution = /*@__PURE__*/ ( Fn( () => { // @deprecated, r169 console.warn( 'TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.' ); @@ -10383,6 +14447,9 @@ const viewportResolution = /*@__PURE__*/ ( Fn( () => { // @deprecated, r169 }, 'vec2' ).once() )(); +/** + * @deprecated since r168. Use {@link screenUV} instead. + */ const viewportTopLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 console.warn( 'TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.' ); @@ -10391,6 +14458,9 @@ const viewportTopLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 }, 'vec2' ).once() )(); +/** + * @deprecated since r168. Use `screenUV.flipY()` instead. + */ const viewportBottomLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 console.warn( 'TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.' ); @@ -10399,6 +14469,8 @@ const viewportBottomLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 }, 'vec2' ).once() )(); +/** @module ViewportTextureNode **/ + const _size$4 = /*@__PURE__*/ new Vector2(); /** @@ -10408,7 +14480,7 @@ const _size$4 = /*@__PURE__*/ new Vector2(); * (which is good for performance). `ViewportTextureNode` can be used as an input for a * variety of effects like refractive or transmissive materials. * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class ViewportTextureNode extends TextureNode { @@ -10503,9 +14575,30 @@ class ViewportTextureNode extends TextureNode { } +/** + * TSL function for creating a viewport texture node. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Texture?} [framebufferTexture=null] - A framebuffer texture holding the viewport data. If not provided, a framebuffer texture is created automatically. + * @returns {ViewportTextureNode} + */ const viewportTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode ); + +/** + * TSL function for creating a viewport texture node with enabled mipmap generation. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Texture?} [framebufferTexture=null] - A framebuffer texture holding the viewport data. If not provided, a framebuffer texture is created automatically. + * @returns {ViewportTextureNode} + */ const viewportMipTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode, null, null, { generateMipmaps: true } ); +/** @module ViewportDepthTextureNode **/ + let sharedDepthbuffer = null; /** @@ -10513,7 +14606,7 @@ let sharedDepthbuffer = null; * can be used in combination with viewport texture to achieve effects * that require depth evaluation. * - * @augments ViewportTextureNode + * @augments module:ViewportTextureNode~ViewportTextureNode */ class ViewportDepthTextureNode extends ViewportTextureNode { @@ -10524,7 +14617,7 @@ class ViewportDepthTextureNode extends ViewportTextureNode { } /** - * Constructs a new viewport shared texture node. + * Constructs a new viewport depth texture node. * * @param {Node} [uvNode=screenUV] - The uv node. * @param {Node?} [levelNode=null] - The level node. @@ -10543,8 +14636,18 @@ class ViewportDepthTextureNode extends ViewportTextureNode { } +/** + * TSL function for a viewport depth texture node. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @returns {ViewportDepthTextureNode} + */ const viewportDepthTexture = /*@__PURE__*/ nodeProxy( ViewportDepthTextureNode ); +/** @module ViewportDepthNode **/ + /** * This node offers a collection of features in context of the depth logic in the fragment shader. * Depending on {@link ViewportDepthNode#scope}, it can be used to define a depth value for the current @@ -10586,7 +14689,7 @@ class ViewportDepthNode extends Node { * Can be used to define a custom depth value. * The property is ignored in the `ViewportDepthNode.DEPTH` scope. * - * @type {Node} + * @type {Node?} * @default null */ this.valueNode = valueNode; @@ -10679,21 +14782,61 @@ 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 +/** + * TSL function for converting a viewZ value to an orthographic depth value. + * + * @function + * @param {Node} viewZ - The viewZ node. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const viewZToOrthographicDepth = ( viewZ, near, far ) => viewZ.add( near ).div( near.sub( far ) ); -// maps orthographic depth in [ 0, 1 ] to viewZ +/** + * TSL function for converting an orthographic depth value to a viewZ value. + * + * @function + * @param {Node} depth - The orthographic depth. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ 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 +/** + * TSL function for converting a viewZ value to a perspective depth value. + * + * Note: {link https://twitter.com/gonnavis/status/1377183786949959682}. + * + * @function + * @param {Node} viewZ - The viewZ node. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( far.sub( near ).mul( viewZ ) ); -// maps perspective depth in [ 0, 1 ] to viewZ +/** + * TSL function for converting a perspective depth value to a viewZ value. + * + * @function + * @param {Node} depth - The perspective depth. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) ); -// -near maps to 0; -far maps to 1 +/** + * TSL function for converting a viewZ value to a logarithmic depth value. + * + * @function + * @param {Node} viewZ - The viewZ node. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const viewZToLogarithmicDepth = ( viewZ, near, far ) => { // NOTE: viewZ must be negative--see explanation at the end of this comment block. @@ -10729,7 +14872,15 @@ const viewZToLogarithmicDepth = ( viewZ, near, far ) => { }; -// maps logarithmic depth in [ 0, 1 ] to viewZ +/** + * TSL function for converting a logarithmic depth value to a viewZ value. + * + * @function + * @param {Node} depth - The logarithmic depth. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const logarithmicDepthToViewZ = ( depth, near, far ) => { // NOTE: we add a 'negate()' call to the return value here to maintain consistency with @@ -10740,26 +14891,83 @@ const logarithmicDepthToViewZ = ( depth, near, far ) => { }; +/** + * TSL function for defining a value for the current fragment's depth. + * + * @function + * @param {Node} value - The depth value to set. + * @returns {ViewportDepthNode} + */ const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE ); +/** + * TSL object that represents the depth value for the current fragment. + * + * @type {ViewportDepthNode} + */ const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH ); + +/** + * TSL function for converting a perspective depth value to linear depth. + * + * @function + * @param {Node} value - The perspective depth. + * @returns {ViewportDepthNode} + */ const linearDepth = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.LINEAR_DEPTH ); + +/** + * TSL object that represents the linear (orthographic) depth value of the current fragment + * + * @type {ViewportDepthNode} + */ const viewportLinearDepth = /*@__PURE__*/ linearDepth( viewportDepthTexture() ); depth.assign = ( value ) => depthBase( value ); +/** @module BuiltinNode **/ + +/** + * The node allows to set values for built-in shader variables. That is + * required for features like hardware-accelerated vertex clipping. + * + * @augments Node + */ class BuiltinNode extends Node { + /** + * Constructs a new builtin node. + * + * @param {String} name - The name of the built-in shader variable. + */ constructor( name ) { super( 'float' ); + /** + * The name of the built-in shader variable. + * + * @type {String} + */ this.name = name; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBuiltinNode = true; } + /** + * Generates the code snippet of the builtin node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( /* builder */ ) { return this.name; @@ -10768,8 +14976,25 @@ class BuiltinNode extends Node { } +/** + * TSL function for creating a builtin node. + * + * @function + * @param {String} name - The name of the built-in shader variable. + * @returns {BuiltinNode} + */ const builtin = nodeProxy( BuiltinNode ); +/** @module ClippingNode **/ + +/** + * ``` + * This node is used in {@link NodeMaterial} to setup the clipping + * which can happen hardware-accelerated (if supported) and optionally + * use alpha-to-coverage for anti-aliasing clipped edges. + * ``` + * @augments Node + */ class ClippingNode extends Node { static get type() { @@ -10778,14 +15003,32 @@ class ClippingNode extends Node { } + /** + * Constructs a new clipping node. + * + * @param {('default'|'hardware'|'alphaToCoverage')} [scope='default'] - The node's scope. Similar to other nodes, + * the selected scope influences the behavior of the node and what type of code is generated. + */ constructor( scope = ClippingNode.DEFAULT ) { super(); + /** + * The node's scope. Similar to other nodes, the selected scope influences + * the behavior of the node and what type of code is generated. + * + * @type {('default'|'hardware'|'alphaToCoverage')} + */ this.scope = scope; } + /** + * Setups the node depending on the selected scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The result node. + */ setup( builder ) { super.setup( builder ); @@ -10811,6 +15054,13 @@ class ClippingNode extends Node { } + /** + * Setups alpha to coverage. + * + * @param {Array} intersectionPlanes - The intersection planes. + * @param {Array} unionPlanes - The union planes. + * @return {Node} The result node. + */ setupAlphaToCoverage( intersectionPlanes, unionPlanes ) { return Fn( () => { @@ -10822,7 +15072,7 @@ class ClippingNode extends Node { const numUnionPlanes = unionPlanes.length; - if ( ! this.hardwareClipping && numUnionPlanes > 0 ) { + if ( this.hardwareClipping === false && numUnionPlanes > 0 ) { const clippingPlanes = uniformArray( unionPlanes ); @@ -10869,13 +15119,20 @@ class ClippingNode extends Node { } + /** + * Setups the default clipping. + * + * @param {Array} intersectionPlanes - The intersection planes. + * @param {Array} unionPlanes - The union planes. + * @return {Node} The result node. + */ setupDefault( intersectionPlanes, unionPlanes ) { return Fn( () => { const numUnionPlanes = unionPlanes.length; - if ( ! this.hardwareClipping && numUnionPlanes > 0 ) { + if ( this.hardwareClipping === false && numUnionPlanes > 0 ) { const clippingPlanes = uniformArray( unionPlanes ); @@ -10910,6 +15167,13 @@ class ClippingNode extends Node { } + /** + * Setups hardware clipping. + * + * @param {Array} unionPlanes - The union planes. + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The result node. + */ setupHardwareClipping( unionPlanes, builder ) { const numUnionPlanes = unionPlanes.length; @@ -10940,8 +15204,28 @@ ClippingNode.ALPHA_TO_COVERAGE = 'alphaToCoverage'; ClippingNode.DEFAULT = 'default'; ClippingNode.HARDWARE = 'hardware'; +/** + * TSL function for setting up the default clipping logic. + * + * @function + * @returns {ClippingNode} + */ const clipping = () => nodeObject( new ClippingNode() ); + +/** + * TSL function for setting up alpha to coverage. + * + * @function + * @returns {ClippingNode} + */ const clippingAlpha = () => nodeObject( new ClippingNode( ClippingNode.ALPHA_TO_COVERAGE ) ); + +/** + * TSL function for setting up hardware-based clipping. + * + * @function + * @returns {ClippingNode} + */ const hardwareClipping = () => nodeObject( new ClippingNode( ClippingNode.HARDWARE ) ); // See: https://casual-effects.com/research/Wyman2017Hashed/index.html @@ -11009,6 +15293,11 @@ const getAlphaHashThreshold = /*@__PURE__*/ Fn( ( [ position ] ) => { ] } ); +/** + * Base class for all node materials. + * + * @augments Material + */ class NodeMaterial extends Material { static get type() { @@ -11017,6 +15306,11 @@ class NodeMaterial extends Material { } + /** + * Represents the type of the node material. + * + * @type {String} + */ get type() { return this.constructor.type; @@ -11025,66 +15319,364 @@ class NodeMaterial extends Material { set type( _value ) { /* */ } + /** + * Constructs a new node material. + */ constructor() { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isNodeMaterial = true; - this.forceSinglePass = false; - + /** + * Whether this material is affected by fog or not. + * + * @type {Boolean} + * @default true + */ this.fog = true; + + /** + * Whether this material is affected by lights or not. + * + * @type {Boolean} + * @default false + */ this.lights = false; + + /** + * Whether this material uses hardware clipping or not. + * This property is managed by the engine and should not be + * modified by apps. + * + * @type {Boolean} + * @default false + */ this.hardwareClipping = false; + /** + * Node materials which set their `lights` property to `true` + * are affected by all lights of the scene. Sometimes selective + * lighting is wanted which means only _some_ lights in the scene + * affect a material. This can be achieved by creating an instance + * of {@link module:LightsNode~LightsNode} with a list of selective + * lights and assign the node to this property. + * + * ```js + * const customLightsNode = lights( [ light1, light2 ] ); + * material.lightsNode = customLightsNode; + * ``` + * + * @type {LightsNode?} + * @default null + */ this.lightsNode = null; + + /** + * The environment of node materials can be defined by an environment + * map assigned to the `envMap` property or by `Scene.environment` + * if the node material is a PBR material. This node property allows to overwrite + * the default behavior and define the environment with a custom node. + * + * ```js + * material.envNode = pmremTexture( renderTarget.texture ); + * ``` + * + * @type {Node?} + * @default null + */ this.envNode = null; + + /** + * The lighting of node materials might be influenced by ambient occlusion. + * The default AO is inferred from an ambient occlusion map assigned to `aoMap` + * and the respective `aoMapIntensity`. This node property allows to overwrite + * the default and define the ambient occlusion with a custom node instead. + * + * If you don't want to overwrite the diffuse color but modify the existing + * values instead, use {@link module:MaterialNode.materialAO}. + * + * @type {Node?} + * @default null + */ this.aoNode = null; + /** + * The diffuse color of node materials is by default inferred from the + * `color` and `map` properties. This node property allows to overwrite the default + * and define the diffuse color with a node instead. + * + * ```js + * material.colorNode = color( 0xff0000 ); // define red color + * ``` + * + * If you don't want to overwrite the diffuse color but modify the existing + * values instead, use {@link module:MaterialNode.materialColor}. + * + * ```js + * material.colorNode = materialColor.mul( color( 0xff0000 ) ); // give diffuse colors a red tint + * ``` + * + * @type {Node?} + * @default null + */ this.colorNode = null; + + /** + * The normals of node materials are by default inferred from the `normalMap`/`normalScale` + * or `bumpMap`/`bumpScale` properties. This node property allows to overwrite the default + * and define the normals with a node instead. + * + * If you don't want to overwrite the normals but modify the existing values instead, + * use {@link module:MaterialNode.materialNormal}. + * + * @type {Node?} + * @default null + */ this.normalNode = null; + + /** + * The opacity of node materials is by default inferred from the `opacity` + * and `alphaMap` properties. This node property allows to overwrite the default + * and define the opacity with a node instead. + * + * If you don't want to overwrite the normals but modify the existing + * value instead, use {@link module:MaterialNode.materialOpacity}. + * + * @type {Node?} + * @default null + */ this.opacityNode = null; + + /** + * This node can be used to to implement a variety of filter-like effects. The idea is + * to store the current rendering into a texture e.g. via `viewportSharedTexture()`, use it + * to create an arbitrary effect and then assign the node composition to this property. + * Everything behind the object using this material will now be affected by a filter. + * + * ```js + * const material = new NodeMaterial() + * material.transparent = true; + * + * // everything behind the object will be monochromatic + * material.backdropNode = viewportSharedTexture().rgb.saturation( 0 ); + * ``` + * + * Backdrop computations are part of the lighting so only lit materials can use this property. + * + * @type {Node?} + * @default null + */ this.backdropNode = null; + + /** + * This node allows to modulate the influence of `backdropNode` to the outgoing light. + * + * @type {Node?} + * @default null + */ this.backdropAlphaNode = null; + + /** + * The alpha test of node materials is by default inferred from the `alphaTest` + * property. This node property allows to overwrite the default and define the + * alpha test with a node instead. + * + * If you don't want to overwrite the alpha test but modify the existing + * value instead, use {@link module:MaterialNode.materialAlphaTest}. + * + * @type {Node?} + * @default null + */ this.alphaTestNode = null; + /** + * The local vertex positions are computed based on multiple factors like the + * attribute data, morphing or skinning. This node property allows to overwrite + * the default and define local vertex positions with nodes instead. + * + * If you don't want to overwrite the vertex positions but modify the existing + * values instead, use {@link module:Position.positionLocal}. + * + *```js + * material.positionNode = positionLocal.add( displace ); + * ``` + * + * @type {Node?} + * @default null + */ this.positionNode = null; + + /** + * This node property is intended for logic which modifies geometry data once or per animation step. + * Apps usually place such logic randomly in initialization routines or in the animation loop. + * `geometryNode` is intended as a dedicated API so there is an intended spot where geometry modifications + * can be implemented. + * + * The idea is to assign a `Fn` definition that holds the geometry modification logic. A typical example + * would be a GPU based particle system that provides a node material for usage on app level. The particle + * simulation would be implemented as compute shaders and managed inside a `Fn` function. This function is + * eventually assigned to `geometryNode`. + * + * @type {Function} + * @default null + */ this.geometryNode = null; + /** + * Allows to overwrite depth values in the fragment shader. + * + * @type {Node?} + * @default null + */ this.depthNode = null; + + /** + * Allows to overwrite the position used for shadow map rendering which + * is by default {@link module:Position.positionWorld}, the vertex position + * in world space. + * + * @type {Node?} + * @default null + */ this.shadowPositionNode = null; + + /** + * This node can be used to influence how an object using this node material + * receive shadows. + * + * ```js + * const totalShadows = float( 1 ).toVar(); + * material.receivedShadowNode = Fn( ( [ shadow ] ) => { + * totalShadows.mulAssign( shadow ); + * //return float( 1 ); // bypass received shadows + * return shadow.mix( color( 0xff0000 ), 1 ); // modify shadow color + * } ); + * + * @type {Node?} + * @default null + */ this.receivedShadowNode = null; + + /** + * This node can be used to influence how an object using this node material + * casts shadows. To apply a color to shadows, you can simply do: + * + * ```js + * material.castShadowNode = vec4( 1, 0, 0, 1 ); + * ``` + * + * Which can be nice to fake colored shadows of semi-transparent objects. It + * is also common to use the property with `Fn` function so checks are performed + * per fragment. + * + * ```js + * materialCustomShadow.castShadowNode = Fn( () => { + * hash( vertexIndex ).greaterThan( 0.5 ).discard(); + * return materialColor; + * } )(); + * ``` + * + * @type {Node?} + * @default null + */ this.castShadowNode = null; + /** + * This node can be used to define the final output of the material. + * + * TODO: Explain the differences to `fragmentNode`. + * + * @type {Node?} + * @default null + */ this.outputNode = null; + + /** + * MRT configuration is done on renderer or pass level. This node allows to + * overwrite what values are written into MRT targets on material level. This + * can be useful for implementing selective FX features that should only affect + * specific objects. + * + * @type {MRTNode?} + * @default null + */ this.mrtNode = null; + /** + * This node property can be used if you need complete freedom in implementing + * the fragment shader. Assigning a node will replace the built-in material + * logic used in the fragment stage. + * + * @type {Node?} + * @default null + */ this.fragmentNode = null; + + /** + * This node property can be used if you need complete freedom in implementing + * the vertex shader. Assigning a node will replace the built-in material logic + * used in the vertex stage. + * + * @type {Node?} + * @default null + */ this.vertexNode = null; } + /** + * Allows to define a custom cache key that influence the material key computation + * for render objects. + * + * @return {String} The custom cache key. + */ customProgramCacheKey() { return this.type + getCacheKey$1( this ); } + /** + * Builds this material with the given node builder. + * + * @param {NodeBuilder} builder - The current node builder. + */ build( builder ) { this.setup( builder ); } + /** + * Setups a node material observer with the given builder. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {NodeMaterialObserver} The node material observer. + */ setupObserver( builder ) { return new NodeMaterialObserver( builder ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { builder.context.setupNormal = () => this.setupNormal( builder ); + builder.context.setupPositionView = () => this.setupPositionView( builder ); + builder.context.setupModelViewProjection = () => this.setupModelViewProjection( builder ); const renderer = builder.renderer; const renderTarget = renderer.getRenderTarget(); @@ -11093,7 +15685,11 @@ class NodeMaterial extends Material { builder.addStack(); - builder.stack.outputNode = this.vertexNode || this.setupPosition( builder ); + const vertexNode = this.vertexNode || this.setupVertex( builder ); + + builder.stack.outputNode = vertexNode; + + this.setupHardwareClipping( builder ); if ( this.geometryNode !== null ) { @@ -11111,7 +15707,7 @@ class NodeMaterial extends Material { const clippingNode = this.setupClipping( builder ); - if ( this.depthWrite === true ) { + if ( this.depthWrite === true || this.depthTest === true ) { // only write depth if depth buffer is configured @@ -11199,6 +15795,12 @@ class NodeMaterial extends Material { } + /** + * Setups the clipping node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ClippingNode} The clipping node. + */ setupClipping( builder ) { if ( builder.clippingContext === null ) return null; @@ -11228,6 +15830,11 @@ class NodeMaterial extends Material { } + /** + * Setups the hardware clipping if available on the current device. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupHardwareClipping( builder ) { this.hardwareClipping = false; @@ -11250,6 +15857,11 @@ class NodeMaterial extends Material { } + /** + * Setups the depth of this material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupDepth( builder ) { const { renderer, camera } = builder; @@ -11290,14 +15902,58 @@ class NodeMaterial extends Material { } - setupPosition( builder ) { + /** + * Setups the position node in view space. This method exists + * so derived node materials can modify the implementation e.g. sprite materials. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in view space. + */ + setupPositionView( /*builder*/ ) { - const { object } = builder; - const geometry = object.geometry; + return modelViewMatrix.mul( positionLocal ).xyz; + + } + + /** + * Setups the position in clip space. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in view space. + */ + setupModelViewProjection( /*builder*/ ) { + + return cameraProjectionMatrix.mul( positionView ); + + } + + /** + * Setups the logic for the vertex stage. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in clip space. + */ + setupVertex( builder ) { builder.addStack(); - // Vertex + this.setupPosition( builder ); + + builder.context.vertex = builder.removeStack(); + + return modelViewProjection; + + } + + /** + * Setups the computation of the position in local space. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in local space. + */ + setupPosition( builder ) { + + const { object, geometry } = builder; if ( geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color ) { @@ -11335,21 +15991,20 @@ class NodeMaterial extends Material { if ( this.positionNode !== null ) { - positionLocal.assign( this.positionNode ); + positionLocal.assign( this.positionNode.context( { isPositionNodeInput: true } ) ); } - this.setupHardwareClipping( builder ); - - const mvp = modelViewProjection(); - - builder.context.vertex = builder.removeStack(); - builder.context.mvp = mvp; - - return mvp; + return positionLocal; } + /** + * Setups the computation of the material's diffuse color. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {BufferGeometry} geometry - The geometry. + */ setupDiffuseColor( { object, geometry } ) { let colorNode = this.colorNode ? vec4( this.colorNode ) : materialColor; @@ -11416,24 +16071,47 @@ class NodeMaterial extends Material { } + /** + * Abstract interface method that can be implemented by derived materials + * to setup material-specific node variables. + * + * @abstract + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( /*builder*/ ) { // Interface function. } + /** + * Setups the outgoing light node variable + * + * @return {Node} The outgoing light node. + */ setupOutgoingLight() { return ( this.lights === true ) ? vec3( 0 ) : diffuseColor.rgb; } + /** + * Setups the normal node from the material. + * + * @return {Node} The normal node. + */ setupNormal() { return this.normalNode ? vec3( this.normalNode ) : materialNormal; } + /** + * Setups the environment node from the material. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The environment node. + */ setupEnvironment( /*builder*/ ) { let node = null; @@ -11452,6 +16130,12 @@ class NodeMaterial extends Material { } + /** + * Setups the light map node from the material. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The light map node. + */ setupLightMap( builder ) { let node = null; @@ -11466,6 +16150,12 @@ class NodeMaterial extends Material { } + /** + * Setups the lights node based on the scene, environment and material. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {LightsNode} The lights node. + */ setupLights( builder ) { const materialLightsNode = []; @@ -11490,7 +16180,7 @@ class NodeMaterial extends Material { if ( this.aoNode !== null || builder.material.aoMap ) { - const aoNode = this.aoNode !== null ? this.aoNode : materialAOMap; + const aoNode = this.aoNode !== null ? this.aoNode : materialAO; materialLightsNode.push( new AONode( aoNode ) ); @@ -11508,12 +16198,26 @@ class NodeMaterial extends Material { } + /** + * This method should be implemented by most derived materials + * since it defines the material's lighting model. + * + * @abstract + * @param {NodeBuilder} builder - The current node builder. + * @return {LightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { // Interface function. } + /** + * Setups the outgoing light node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The outgoing light node. + */ setupLighting( builder ) { const { material } = builder; @@ -11553,6 +16257,13 @@ class NodeMaterial extends Material { } + /** + * Setups the output node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} outputNode - The existing output node. + * @return {Node} The output node. + */ setupOutput( builder, outputNode ) { // FOG @@ -11561,7 +16272,13 @@ class NodeMaterial extends Material { const fogNode = builder.fogNode; - if ( fogNode ) outputNode = vec4( fogNode.mix( outputNode.rgb, fogNode.colorNode ), outputNode.a ); + if ( fogNode ) { + + output.assign( outputNode ); + + outputNode = vec4( fogNode ); + + } } @@ -11569,6 +16286,13 @@ class NodeMaterial extends Material { } + /** + * Most classic material types have a node pendant e.g. for `MeshBasicMaterial` + * there is `MeshBasicNodeMaterial`. This utility method is intended for + * defining all material properties of the classic type in the node type. + * + * @param {Material} material - The material to copy properties with their values to this node material. + */ setDefaultValues( material ) { // This approach is to reuse the native refreshUniforms* @@ -11603,6 +16327,12 @@ class NodeMaterial extends Material { } + /** + * Serializes this material to JSON. + * + * @param {(Object|String)?} meta - The meta information for serialization. + * @return {Object} The serialized node. + */ toJSON( meta ) { const isRoot = ( meta === undefined || typeof meta === 'string' ); @@ -11662,6 +16392,12 @@ class NodeMaterial extends Material { } + /** + * Copies the properties of the given node material to this instance. + * + * @param {NodeMaterial} source - The material to copy. + * @return {NodeMaterial} A reference to this node material. + */ copy( source ) { this.lightsNode = source.lightsNode; @@ -11694,150 +16430,13 @@ class NodeMaterial extends Material { } -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(); +/** + * Node material version of `LineBasicMaterial`. + * + * @augments NodeMaterial + */ class LineBasicNodeMaterial extends NodeMaterial { static get type() { @@ -11846,14 +16445,24 @@ class LineBasicNodeMaterial extends NodeMaterial { } + /** + * Constructs a new line basic node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isLineBasicNodeMaterial = true; - this.lights = false; - this.setDefaultValues( _defaultValues$d ); this.setValues( parameters ); @@ -11864,6 +16473,11 @@ class LineBasicNodeMaterial extends NodeMaterial { const _defaultValues$c = /*@__PURE__*/ new LineDashedMaterial(); +/** + * Node material version of `LineDashedMaterial`. + * + * @augments NodeMaterial + */ class LineDashedNodeMaterial extends NodeMaterial { static get type() { @@ -11872,33 +16486,101 @@ class LineDashedNodeMaterial extends NodeMaterial { } + /** + * Constructs a new line dashed node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isLineDashedNodeMaterial = true; - this.lights = false; - this.setDefaultValues( _defaultValues$c ); + /** + * The dash offset. + * + * @type {Number} + * @default 0 + */ this.dashOffset = 0; + /** + * The offset of dash materials is by default inferred from the `dashOffset` + * property. This node property allows to overwrite the default + * and define the offset with a node instead. + * + * If you don't want to overwrite the offset but modify the existing + * value instead, use {@link module:MaterialNode.materialLineDashOffset}. + * + * @type {Node?} + * @default null + */ this.offsetNode = null; + + /** + * The scale of dash materials is by default inferred from the `scale` + * property. This node property allows to overwrite the default + * and define the scale with a node instead. + * + * If you don't want to overwrite the scale but modify the existing + * value instead, use {@link module:MaterialNode.materialLineScale}. + * + * @type {Node?} + * @default null + */ this.dashScaleNode = null; + + /** + * The dash size of dash materials is by default inferred from the `dashSize` + * property. This node property allows to overwrite the default + * and define the dash size with a node instead. + * + * If you don't want to overwrite the dash size but modify the existing + * value instead, use {@link module:MaterialNode.materialLineDashSize}. + * + * @type {Node?} + * @default null + */ this.dashSizeNode = null; + + /** + * The gap size of dash materials is by default inferred from the `gapSize` + * property. This node property allows to overwrite the default + * and define the gap size with a node instead. + * + * If you don't want to overwrite the gap size but modify the existing + * value instead, use {@link module:MaterialNode.materialLineGapSize}. + * + * @type {Node?} + * @default null + */ this.gapSizeNode = null; this.setValues( parameters ); } - setupVariants() { + /** + * Setups the dash specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ + setupVariants( /* builder */ ) { - const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset; + const offsetNode = this.offsetNode ? float( this.offsetNode ) : 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; + const gapSizeNode = this.gapSizeNode ? float( this.gapSizeNode ) : materialLineGapSize; dashSize.assign( dashSizeNode ); gapSize.assign( gapSizeNode ); @@ -11912,6 +16594,8 @@ class LineDashedNodeMaterial extends NodeMaterial { } +/** @module ViewportSharedTextureNode **/ + let _sharedFramebuffer = null; /** @@ -11919,7 +16603,7 @@ let _sharedFramebuffer = null; * shares a texture across all instances of `ViewportSharedTextureNode`. It should * be the first choice when using data of the default/screen framebuffer for performance reasons. * - * @augments ViewportTextureNode + * @augments module:ViewportTextureNode~ViewportTextureNode */ class ViewportSharedTextureNode extends ViewportTextureNode { @@ -11955,10 +16639,24 @@ class ViewportSharedTextureNode extends ViewportTextureNode { } +/** + * TSL function for creating a shared viewport texture node. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @returns {ViewportSharedTextureNode} + */ const viewportSharedTexture = /*@__PURE__*/ nodeProxy( ViewportSharedTextureNode ); const _defaultValues$b = /*@__PURE__*/ new LineDashedMaterial(); +/** + * This node material can be used to render lines with a size larger than one + * by representing them as instanced meshes. + * + * @augments NodeMaterial + */ class Line2NodeMaterial extends NodeMaterial { static get type() { @@ -11967,49 +16665,120 @@ class Line2NodeMaterial extends NodeMaterial { } - constructor( params = {} ) { + /** + * Constructs a new node material for wide line rendering. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters = {} ) { super(); - this.lights = false; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isLine2NodeMaterial = true; this.setDefaultValues( _defaultValues$b ); - this.useAlphaToCoverage = true; - this.useColor = params.vertexColors; - this.useDash = params.dashed; - this.useWorldUnits = false; + /** + * Whether vertex colors should be used or not. + * + * @type {Boolean} + * @default false + */ + this.useColor = parameters.vertexColors; + /** + * The dash offset. + * + * @type {Number} + * @default 0 + */ this.dashOffset = 0; + + /** + * The line width. + * + * @type {Number} + * @default 0 + */ this.lineWidth = 1; + /** + * Defines the lines color. + * + * @type {Node?} + * @default null + */ this.lineColorNode = null; + /** + * Defines the offset. + * + * @type {Node?} + * @default null + */ this.offsetNode = null; + + /** + * Defines the dash scale. + * + * @type {Node?} + * @default null + */ this.dashScaleNode = null; + + /** + * Defines the dash size. + * + * @type {Node?} + * @default null + */ this.dashSizeNode = null; + + /** + * Defines the gap size. + * + * @type {Node?} + * @default null + */ this.gapSizeNode = null; + /** + * Blending is set to `NoBlending` since transparency + * is not supported, yet. + * + * @type {Number} + * @default 0 + */ this.blending = NoBlending; - this.setValues( params ); + this._useDash = parameters.dashed; + this._useAlphaToCoverage = true; + this._useWorldUnits = false; + + this.setValues( parameters ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { - this.setupShaders( builder ); - - super.setup( builder ); - - } - - setupShaders( { renderer } ) { + const { renderer } = builder; - const useAlphaToCoverage = this.alphaToCoverage; + const useAlphaToCoverage = this._useAlphaToCoverage; const useColor = this.useColor; - const useDash = this.dashed; - const useWorldUnits = this.worldUnits; + const useDash = this._useDash; + const useWorldUnits = this._useWorldUnits; const trimSegment = Fn( ( { start, end } ) => { @@ -12043,7 +16812,7 @@ class Line2NodeMaterial extends NodeMaterial { if ( useDash ) { const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale; - const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset; + const offsetNode = this.offsetNode ? float( this.offsetNode ) : materialLineDashOffset; const instanceDistanceStart = attribute( 'instanceDistanceStart' ); const instanceDistanceEnd = attribute( 'instanceDistanceEnd' ); @@ -12220,7 +16989,7 @@ class Line2NodeMaterial extends NodeMaterial { if ( useDash ) { const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize; - const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize; + const gapSizeNode = this.gapSizeNode ? float( this.gapSizeNode ) : materialLineGapSize; dashSize.assign( dashSizeNode ); gapSize.assign( gapSizeNode ); @@ -12337,56 +17106,74 @@ class Line2NodeMaterial extends NodeMaterial { } - } + super.setup( builder ); + } + /** + * Whether the lines should sized in world units or not. + * When set to `false` the unit is pixel. + * + * @type {Boolean} + * @default false + */ get worldUnits() { - return this.useWorldUnits; + return this._useWorldUnits; } set worldUnits( value ) { - if ( this.useWorldUnits !== value ) { + if ( this._useWorldUnits !== value ) { - this.useWorldUnits = value; + this._useWorldUnits = value; this.needsUpdate = true; } } - + /** + * Whether the lines should be dashed or not. + * + * @type {Boolean} + * @default false + */ get dashed() { - return this.useDash; + return this._useDash; } set dashed( value ) { - if ( this.useDash !== value ) { + if ( this._useDash !== value ) { - this.useDash = value; + this._useDash = value; this.needsUpdate = true; } } - + /** + * Whether alpha to coverage should be used or not. + * + * @type {Boolean} + * @default true + */ get alphaToCoverage() { - return this.useAlphaToCoverage; + return this._useAlphaToCoverage; } set alphaToCoverage( value ) { - if ( this.useAlphaToCoverage !== value ) { + if ( this._useAlphaToCoverage !== value ) { - this.useAlphaToCoverage = value; + this._useAlphaToCoverage = value; this.needsUpdate = true; } @@ -12417,6 +17204,11 @@ const colorToDirection = ( node ) => nodeObject( node ).mul( 2.0 ).sub( 1 ); const _defaultValues$a = /*@__PURE__*/ new MeshNormalMaterial(); +/** + * Node material version of `MeshNormalMaterial`. + * + * @augments NodeMaterial + */ class MeshNormalNodeMaterial extends NodeMaterial { static get type() { @@ -12425,12 +17217,22 @@ class MeshNormalNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh normal node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); - this.lights = false; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshNormalNodeMaterial = true; this.setDefaultValues( _defaultValues$a ); @@ -12439,6 +17241,10 @@ class MeshNormalNodeMaterial extends NodeMaterial { } + /** + * Overwrites the default implementation by computing the diffuse color + * based on the normal data. + */ setupDiffuseColor() { const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity; @@ -12449,6 +17255,8 @@ class MeshNormalNodeMaterial extends NodeMaterial { } +/** @module EquirectUVNode **/ + /** * Can be used to compute texture coordinates for projecting an * equirectangular texture onto a mesh for using it as the scene's @@ -12471,7 +17279,7 @@ class EquirectUVNode extends TempNode { /** * Constructs a new equirect uv node. * - * @param {Node} [dirNode=positionWorldDirection] - A direction vector for sampling why is by default `positionWorldDirection`. + * @param {Node} [dirNode=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`. */ constructor( dirNode = positionWorldDirection ) { @@ -12490,7 +17298,7 @@ class EquirectUVNode extends TempNode { const dir = this.dirNode; - const u = dir.z.atan2( dir.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 ); + const u = dir.z.atan( 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 ); @@ -12499,10 +17307,23 @@ class EquirectUVNode extends TempNode { } +/** + * TSL function for creating an equirect uv node. + * + * @function + * @param {Node} [dirNode=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`. + * @returns {EquirectUVNode} + */ const equirectUV = /*@__PURE__*/ nodeProxy( EquirectUVNode ); // @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget +/** + * This class represents a cube render target. It is a special version + * of `WebGLCubeRenderTarget` which is compatible with `WebGPURenderer`. + * + * @augments WebGLCubeRenderTarget + */ class CubeRenderTarget extends WebGLCubeRenderTarget { constructor( size = 1, options = {} ) { @@ -12513,6 +17334,13 @@ class CubeRenderTarget extends WebGLCubeRenderTarget { } + /** + * Converts the given equirectangular texture to a cube map. + * + * @param {Renderer} renderer - The renderer. + * @param {Texture} texture - The equirectangular texture. + * @return {CubeRenderTarget} A reference to this cube render target. + */ fromEquirectangularTexture( renderer, texture$1 ) { const currentMinFilter = texture$1.minFilter; @@ -12565,6 +17393,8 @@ class CubeRenderTarget extends WebGLCubeRenderTarget { } +/** @module CubeMapNode **/ + const _cache$1 = new WeakMap(); /** @@ -12783,11 +17613,18 @@ function mapTextureMapping( texture, mapping ) { } +/** + * TSL function for creating a cube map node. + * + * @function + * @param {Node} envNode - The node representing the environment map. + * @returns {CubeMapNode} + */ const cubeMapNode = /*@__PURE__*/ nodeProxy( CubeMapNode ); /** * Represents a basic model for Image-based lighting (IBL). The environment - * is defined via environment maps in the equirectanular or cube map format. + * is defined via environment maps in the equirectangular or cube map format. * `BasicEnvironmentNode` is intended for non-PBR materials like {@link MeshBasicNodeMaterial} * or {@link MeshPhongNodeMaterial}. * @@ -12848,7 +17685,7 @@ class BasicLightMapNode extends LightingNode { /** * Constructs a new basic light map node. * - * @param {Node} lightMapNode - The light map node. + * @param {Node?} [lightMapNode=null] - The light map node. */ constructor( lightMapNode = null ) { @@ -12857,7 +17694,7 @@ class BasicLightMapNode extends LightingNode { /** * The light map node. * - * @type {Node} + * @type {Node?} */ this.lightMapNode = lightMapNode; @@ -13047,6 +17884,11 @@ class BasicLightingModel extends LightingModel { const _defaultValues$9 = /*@__PURE__*/ new MeshBasicMaterial(); +/** + * Node material version of `MeshBasicMaterial`. + * + * @augments NodeMaterial + */ class MeshBasicNodeMaterial extends NodeMaterial { static get type() { @@ -13055,12 +17897,32 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh basic node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshBasicNodeMaterial = true; + /** + * Although the basic material is by definition unlit, we set + * this property to `true` since we use a lighting model to compute + * the outgoing light of the fragment shader. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues$9 ); @@ -13069,12 +17931,25 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * Basic materials are not affected by normal and bump maps so we + * return by default {@link module:Normal.normalView}. + * + * @return {Node} The normal node. + */ setupNormal() { return normalView; // see #28839 } + /** + * Overwritten since this type of material uses {@link BasicEnvironmentNode} + * to implement the default environment mapping. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicEnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { const envNode = super.setupEnvironment( builder ); @@ -13083,6 +17958,13 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * This method must be overwritten since light maps are evaluated + * with a special scaling factor for basic materials. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicLightMapNode?} The light map node. + */ setupLightMap( builder ) { let node = null; @@ -13097,12 +17979,23 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * The material overwrites this method because `lights` is set to `true` but + * we still want to return the diffuse color as the outgoing light. + * + * @return {Node} The outgoing light node. + */ setupOutgoingLight() { return diffuseColor.rgb; } + /** + * Setups the lighting model. + * + * @return {BasicLightingModel} The lighting model. + */ setupLightingModel() { return new BasicLightingModel(); @@ -13156,7 +18049,7 @@ const BRDF_BlinnPhong = /*@__PURE__*/ Fn( ( { lightDirection } ) => { /** * Represents the lighting model for a phong material. Used in {@link MeshPhongNodeMaterial}. * - * @augments LightingModel + * @augments BasicLightingModel */ class PhongLightingModel extends BasicLightingModel { @@ -13171,7 +18064,7 @@ class PhongLightingModel extends BasicLightingModel { /** * Whether specular is supported or not. Set this to `false` if you are - * lookking for a Lambert-like material meaning a material for non-shiny + * looking for a Lambert-like material meaning a material for non-shiny * surfaces, without specular highlights. * * @type {Boolean} @@ -13223,6 +18116,11 @@ class PhongLightingModel extends BasicLightingModel { const _defaultValues$8 = /*@__PURE__*/ new MeshLambertMaterial(); +/** + * Node material version of `MeshLambertMaterial`. + * + * @augments NodeMaterial + */ class MeshLambertNodeMaterial extends NodeMaterial { static get type() { @@ -13231,12 +18129,30 @@ class MeshLambertNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh lambert node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshLambertNodeMaterial = true; + /** + * Set to `true` because lambert materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues$8 ); @@ -13245,6 +18161,13 @@ class MeshLambertNodeMaterial extends NodeMaterial { } + /** + * Overwritten since this type of material uses {@link BasicEnvironmentNode} + * to implement the default environment mapping. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicEnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { const envNode = super.setupEnvironment( builder ); @@ -13253,6 +18176,11 @@ class MeshLambertNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhongLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhongLightingModel( false ); // ( specular ) -> force lambert @@ -13263,6 +18191,11 @@ class MeshLambertNodeMaterial extends NodeMaterial { const _defaultValues$7 = /*@__PURE__*/ new MeshPhongMaterial(); +/** + * Node material version of `MeshPhongMaterial`. + * + * @augments NodeMaterial + */ class MeshPhongNodeMaterial extends NodeMaterial { static get type() { @@ -13271,15 +18204,56 @@ class MeshPhongNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh lambert node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshPhongNodeMaterial = true; + /** + * Set to `true` because phong materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; + /** + * The shininess of phong materials is by default inferred from the `shininess` + * property. This node property allows to overwrite the default + * and define the shininess with a node instead. + * + * If you don't want to overwrite the shininess but modify the existing + * value instead, use {@link module:MaterialNode.materialShininess}. + * + * @type {Node?} + * @default null + */ this.shininessNode = null; + + /** + * The specular color of phong materials is by default inferred from the + * `specular` property. This node property allows to overwrite the default + * and define the specular color with a node instead. + * + * If you don't want to overwrite the specular color but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecular}. + * + * @type {Node?} + * @default null + */ this.specularNode = null; this.setDefaultValues( _defaultValues$7 ); @@ -13288,6 +18262,13 @@ class MeshPhongNodeMaterial extends NodeMaterial { } + /** + * Overwritten since this type of material uses {@link BasicEnvironmentNode} + * to implement the default environment mapping. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicEnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { const envNode = super.setupEnvironment( builder ); @@ -13296,13 +18277,23 @@ class MeshPhongNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhongLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhongLightingModel(); } - setupVariants() { + /** + * Setups the phong specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ + setupVariants( /*builder*/ ) { // SHININESS @@ -13728,6 +18719,8 @@ const LTC_Evaluate = /*@__PURE__*/ Fn( ( { N, V, P, mInv, p0, p1, p2, p3 } ) => ] } ); +/** @module TextureBicubic **/ + // Mipped Bicubic Texture Filtering by N8 // https://www.shadertoy.com/view/Dl2SDW @@ -13777,6 +18770,14 @@ const bicubic = ( textureNode, texelSize, lod ) => { }; +/** + * Applies mipped bicubic texture filtering to the given texture node. + * + * @method + * @param {TextureNode} textureNode - The texture node that should be filtered. + * @param {Node} [lodNode=float(3)] - Defines the LOD to sample from. + * @return {Node} The filtered texture sample. + */ const textureBicubic = /*@__PURE__*/ Fn( ( [ textureNode, lodNode = float( 3 ) ] ) => { const fLodSize = vec2( textureNode.size( int( lodNode ) ) ); @@ -14846,6 +19847,8 @@ const blur = /*@__PURE__*/ Fn( ( { n, latitudinal, poleAxis, outputDirection, we } ); +/** @module PMREMNode **/ + let _generator = null; const _cache = new WeakMap(); @@ -15195,13 +20198,22 @@ function isEquirectangularMapReady( image ) { } +/** + * TSL function for creating a PMREM node. + * + * @function + * @param {Texture} value - The input texture. + * @param {Node} [uvNode=null] - The uv node. + * @param {Node} [levelNode=null] - The level node. + * @returns {PMREMNode} + */ const pmremTexture = /*@__PURE__*/ nodeProxy( PMREMNode ); const _envNodeCache = new WeakMap(); /** * Represents a physical model for Image-based lighting (IBL). The environment - * is defined via environment maps in the equirectanular, cube map or cubeUV (PMREM) format. + * is defined via environment maps in the equirectangular, cube map or cubeUV (PMREM) format. * `EnvironmentNode` is intended for PBR materials like {@link MeshStandardNodeMaterial}. * * @augments LightingNode @@ -15226,7 +20238,7 @@ class EnvironmentNode extends LightingNode { /** * A node representing the environment. * - * @type {Node} + * @type {Node?} * @default null */ this.envNode = envNode; @@ -15343,6 +20355,11 @@ const createIrradianceContext = ( normalWorldNode ) => { const _defaultValues$6 = /*@__PURE__*/ new MeshStandardMaterial(); +/** + * Node material version of `MeshStandardMaterial`. + * + * @augments NodeMaterial + */ class MeshStandardNodeMaterial extends NodeMaterial { static get type() { @@ -15351,17 +20368,69 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh standard node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshStandardNodeMaterial = true; + /** + * Set to `true` because standard materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; + /** + * The emissive color of standard materials is by default inferred from the `emissive`, + * `emissiveIntensity` and `emissiveMap` properties. This node property allows to + * overwrite the default and define the emissive color with a node instead. + * + * If you don't want to overwrite the emissive color but modify the existing + * value instead, use {@link module:MaterialNode.materialEmissive}. + * + * @type {Node?} + * @default null + */ this.emissiveNode = null; + /** + * The metalness of standard materials is by default inferred from the `metalness`, + * and `metalnessMap` properties. This node property allows to + * overwrite the default and define the metalness with a node instead. + * + * If you don't want to overwrite the metalness but modify the existing + * value instead, use {@link module:MaterialNode.materialMetalness}. + * + * @type {Node?} + * @default null + */ this.metalnessNode = null; + + /** + * The roughness of standard materials is by default inferred from the `roughness`, + * and `roughnessMap` properties. This node property allows to + * overwrite the default and define the roughness with a node instead. + * + * If you don't want to overwrite the roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialRoughness}. + * + * @type {Node?} + * @default null + */ this.roughnessNode = null; this.setDefaultValues( _defaultValues$6 ); @@ -15370,6 +20439,14 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Overwritten since this type of material uses {@link EnvironmentNode} + * to implement the PBR (PMREM based) environment mapping. Besides, the + * method honors `Scene.environment`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {EnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { let envNode = super.setupEnvironment( builder ); @@ -15384,12 +20461,20 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhysicalLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhysicalLightingModel(); } + /** + * Setups the specular related node variables. + */ setupSpecular() { const specularColorNode = mix( vec3( 0.04 ), diffuseColor.rgb, metalness ); @@ -15399,6 +20484,11 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Setups the standard specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants() { // METALNESS @@ -15439,6 +20529,11 @@ class MeshStandardNodeMaterial extends NodeMaterial { const _defaultValues$5 = /*@__PURE__*/ new MeshPhysicalMaterial(); +/** + * Node material version of `MeshPhysicalMaterial`. + * + * @augments MeshStandardNodeMaterial + */ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { static get type() { @@ -15447,33 +20542,243 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Constructs a new mesh physical node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshPhysicalNodeMaterial = true; + /** + * The clearcoat of physical materials is by default inferred from the `clearcoat` + * and `clearcoatMap` properties. This node property allows to overwrite the default + * and define the clearcoat with a node instead. + * + * If you don't want to overwrite the clearcoat but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoat}. + * + * @type {Node?} + * @default null + */ this.clearcoatNode = null; + + /** + * The clearcoat roughness of physical materials is by default inferred from the `clearcoatRoughness` + * and `clearcoatRoughnessMap` properties. This node property allows to overwrite the default + * and define the clearcoat roughness with a node instead. + * + * If you don't want to overwrite the clearcoat roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoatRoughness}. + * + * @type {Node?} + * @default null + */ this.clearcoatRoughnessNode = null; + + /** + * The clearcoat normal of physical materials is by default inferred from the `clearcoatNormalMap` + * property. This node property allows to overwrite the default + * and define the clearcoat normal with a node instead. + * + * If you don't want to overwrite the clearcoat normal but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoatNormal}. + * + * @type {Node?} + * @default null + */ this.clearcoatNormalNode = null; + /** + * The sheen of physical materials is by default inferred from the `sheen`, `sheenColor` + * and `sheenColorMap` properties. This node property allows to overwrite the default + * and define the sheen with a node instead. + * + * If you don't want to overwrite the sheen but modify the existing + * value instead, use {@link module:MaterialNode.materialSheen}. + * + * @type {Node?} + * @default null + */ this.sheenNode = null; + + /** + * The sheen roughness of physical materials is by default inferred from the `sheenRoughness` and + * `sheenRoughnessMap` properties. This node property allows to overwrite the default + * and define the sheen roughness with a node instead. + * + * If you don't want to overwrite the sheen roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialSheenRoughness}. + * + * @type {Node?} + * @default null + */ this.sheenRoughnessNode = null; + /** + * The iridescence of physical materials is by default inferred from the `iridescence` + * property. This node property allows to overwrite the default + * and define the iridescence with a node instead. + * + * If you don't want to overwrite the iridescence but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescence}. + * + * @type {Node?} + * @default null + */ this.iridescenceNode = null; + + /** + * The iridescence IOR of physical materials is by default inferred from the `iridescenceIOR` + * property. This node property allows to overwrite the default + * and define the iridescence IOR with a node instead. + * + * If you don't want to overwrite the iridescence IOR but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescenceIOR}. + * + * @type {Node?} + * @default null + */ this.iridescenceIORNode = null; + + /** + * The iridescence thickness of physical materials is by default inferred from the `iridescenceThicknessRange` + * and `iridescenceThicknessMap` properties. This node property allows to overwrite the default + * and define the iridescence thickness with a node instead. + * + * If you don't want to overwrite the iridescence thickness but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescenceThickness}. + * + * @type {Node?} + * @default null + */ this.iridescenceThicknessNode = null; + /** + * The specular intensity of physical materials is by default inferred from the `specularIntensity` + * and `specularIntensityMap` properties. This node property allows to overwrite the default + * and define the specular intensity with a node instead. + * + * If you don't want to overwrite the specular intensity but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecularIntensity}. + * + * @type {Node?} + * @default null + */ this.specularIntensityNode = null; + + /** + * The specular color of physical materials is by default inferred from the `specularColor` + * and `specularColorMap` properties. This node property allows to overwrite the default + * and define the specular color with a node instead. + * + * If you don't want to overwrite the specular color but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecularColor}. + * + * @type {Node?} + * @default null + */ this.specularColorNode = null; + /** + * The ior of physical materials is by default inferred from the `ior` + * property. This node property allows to overwrite the default + * and define the ior with a node instead. + * + * If you don't want to overwrite the ior but modify the existing + * value instead, use {@link module:MaterialNode.materialIOR}. + * + * @type {Node?} + * @default null + */ this.iorNode = null; + + /** + * The transmission of physical materials is by default inferred from the `transmission` and + * `transmissionMap` properties. This node property allows to overwrite the default + * and define the transmission with a node instead. + * + * If you don't want to overwrite the transmission but modify the existing + * value instead, use {@link module:MaterialNode.materialTransmission}. + * + * @type {Node?} + * @default null + */ this.transmissionNode = null; + + /** + * The thickness of physical materials is by default inferred from the `thickness` and + * `thicknessMap` properties. This node property allows to overwrite the default + * and define the thickness with a node instead. + * + * If you don't want to overwrite the thickness but modify the existing + * value instead, use {@link module:MaterialNode.materialThickness}. + * + * @type {Node?} + * @default null + */ this.thicknessNode = null; + + /** + * The attenuation distance of physical materials is by default inferred from the + * `attenuationDistance` property. This node property allows to overwrite the default + * and define the attenuation distance with a node instead. + * + * If you don't want to overwrite the attenuation distance but modify the existing + * value instead, use {@link module:MaterialNode.materialAttenuationDistance}. + * + * @type {Node?} + * @default null + */ this.attenuationDistanceNode = null; + + /** + * The attenuation color of physical materials is by default inferred from the + * `attenuationColor` property. This node property allows to overwrite the default + * and define the attenuation color with a node instead. + * + * If you don't want to overwrite the attenuation color but modify the existing + * value instead, use {@link module:MaterialNode.materialAttenuationColor}. + * + * @type {Node?} + * @default null + */ this.attenuationColorNode = null; + + /** + * The dispersion of physical materials is by default inferred from the + * `dispersion` property. This node property allows to overwrite the default + * and define the dispersion with a node instead. + * + * If you don't want to overwrite the dispersion but modify the existing + * value instead, use {@link module:MaterialNode.materialDispersion}. + * + * @type {Node?} + * @default null + */ this.dispersionNode = null; + /** + * The anisotropy of physical materials is by default inferred from the + * `anisotropy` property. This node property allows to overwrite the default + * and define the anisotropy with a node instead. + * + * If you don't want to overwrite the anisotropy but modify the existing + * value instead, use {@link module:MaterialNode.materialAnisotropy}. + * + * @type {Node?} + * @default null + */ this.anisotropyNode = null; this.setDefaultValues( _defaultValues$5 ); @@ -15482,42 +20787,81 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Whether the lighting model should use clearcoat or not. + * + * @type {Boolean} + * @default true + */ get useClearcoat() { return this.clearcoat > 0 || this.clearcoatNode !== null; } + /** + * Whether the lighting model should use iridescence or not. + * + * @type {Boolean} + * @default true + */ get useIridescence() { return this.iridescence > 0 || this.iridescenceNode !== null; } + /** + * Whether the lighting model should use sheen or not. + * + * @type {Boolean} + * @default true + */ get useSheen() { return this.sheen > 0 || this.sheenNode !== null; } + /** + * Whether the lighting model should use anisotropy or not. + * + * @type {Boolean} + * @default true + */ get useAnisotropy() { return this.anisotropy > 0 || this.anisotropyNode !== null; } + /** + * Whether the lighting model should use transmission or not. + * + * @type {Boolean} + * @default true + */ get useTransmission() { return this.transmission > 0 || this.transmissionNode !== null; } + /** + * Whether the lighting model should use dispersion or not. + * + * @type {Boolean} + * @default true + */ get useDispersion() { return this.dispersion > 0 || this.dispersionNode !== null; } + /** + * Setups the specular related node variables. + */ setupSpecular() { const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; @@ -15528,12 +20872,22 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhysicalLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhysicalLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion ); } + /** + * Setups the physical specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( builder ) { super.setupVariants( builder ); @@ -15629,6 +20983,11 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Setups the clearcoat normal node. + * + * @return {Node} The clearcoat normal. + */ setupClearcoatNormal() { return this.clearcoatNormalNode ? vec3( this.clearcoatNormalNode ) : materialClearcoatNormal; @@ -15673,16 +21032,49 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } +/** @module MeshSSSNodeMaterial **/ + +/** + * Represents the lighting model for {@link MeshSSSNodeMaterial}. + * + * @augments PhysicalLightingModel + */ class SSSLightingModel extends PhysicalLightingModel { - constructor( useClearcoat, useSheen, useIridescence, useSSS ) { + /** + * Constructs a new physical lighting model. + * + * @param {Boolean} [clearcoat=false] - Whether clearcoat is supported or not. + * @param {Boolean} [sheen=false] - Whether sheen is supported or not. + * @param {Boolean} [iridescence=false] - Whether iridescence is supported or not. + * @param {Boolean} [anisotropy=false] - Whether anisotropy is supported or not. + * @param {Boolean} [transmission=false] - Whether transmission is supported or not. + * @param {Boolean} [dispersion=false] - Whether dispersion is supported or not. + * @param {Boolean} [sss=false] - Whether SSS is supported or not. + */ + constructor( clearcoat = false, sheen = false, iridescence = false, anisotropy = false, transmission = false, dispersion = false, sss = false ) { - super( useClearcoat, useSheen, useIridescence ); + super( clearcoat, sheen, iridescence, anisotropy, transmission, dispersion ); - this.useSSS = useSSS; + /** + * Whether the lighting model should use SSS or not. + * + * @type {Boolean} + * @default false + */ + this.useSSS = sss; } + /** + * Extends the default implementation with a SSS term. + * + * Reference: [Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look]{@link https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/} + * + * @param {Object} input - The input data. + * @param {StackNode} stack - The current stack. + * @param {NodeBuilder} builder - The current node builder. + */ direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { if ( this.useSSS === true ) { @@ -15705,6 +21097,12 @@ class SSSLightingModel extends PhysicalLightingModel { } +/** + * This node material is an experimental extension of {@link MeshPhysicalNodeMaterial} + * that implements a Subsurface scattering (SSS) term. + * + * @augments MeshPhysicalNodeMaterial + */ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { static get type() { @@ -15713,28 +21111,80 @@ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { } + /** + * Constructs a new mesh SSS node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super( parameters ); + /** + * Represents the thickness color. + * + * @type {Node?} + * @default null + */ this.thicknessColorNode = null; + + /** + * Represents the distortion factor. + * + * @type {Node?} + */ this.thicknessDistortionNode = float( 0.1 ); + + /** + * Represents the thickness ambient factor. + * + * @type {Node?} + */ this.thicknessAmbientNode = float( 0.0 ); + + /** + * Represents the thickness attenuation. + * + * @type {Node?} + */ this.thicknessAttenuationNode = float( .1 ); + + /** + * Represents the thickness power. + * + * @type {Node?} + */ this.thicknessPowerNode = float( 2.0 ); + + /** + * Represents the thickness scale. + * + * @type {Node?} + */ this.thicknessScaleNode = float( 10.0 ); } + /** + * Whether the lighting model should use SSS or not. + * + * @type {Boolean} + * @default true + */ get useSSS() { return this.thicknessColorNode !== null; } + /** + * Setups the lighting model. + * + * @return {SSSLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { - return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useSSS ); + return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion, this.useSSS ); } @@ -15817,6 +21267,11 @@ class ToonLightingModel extends LightingModel { const _defaultValues$4 = /*@__PURE__*/ new MeshToonMaterial(); +/** + * Node material version of `MeshToonMaterial`. + * + * @augments NodeMaterial + */ class MeshToonNodeMaterial extends NodeMaterial { static get type() { @@ -15825,12 +21280,30 @@ class MeshToonNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh toon node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshToonNodeMaterial = true; + /** + * Set to `true` because toon materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues$4 ); @@ -15839,6 +21312,11 @@ class MeshToonNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {ToonLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new ToonLightingModel(); @@ -15847,6 +21325,8 @@ class MeshToonNodeMaterial extends NodeMaterial { } +/** @module MatcapUVNode **/ + /** * Can be used to compute texture coordinates for projecting a * matcap onto a mesh. Used by {@link MeshMatcapNodeMaterial}. @@ -15881,10 +21361,21 @@ class MatcapUVNode extends TempNode { } +/** + * TSL function for creating a matcap uv node. + * + * @function + * @returns {MatcapUVNode} + */ const matcapUV = /*@__PURE__*/ nodeImmutable( MatcapUVNode ); const _defaultValues$3 = /*@__PURE__*/ new MeshMatcapMaterial(); +/** + * Node material version of `MeshMatcapMaterial`. + * + * @augments NodeMaterial + */ class MeshMatcapNodeMaterial extends NodeMaterial { static get type() { @@ -15893,12 +21384,22 @@ class MeshMatcapNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh normal node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); - this.lights = false; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshMatcapNodeMaterial = true; this.setDefaultValues( _defaultValues$3 ); @@ -15907,6 +21408,11 @@ class MeshMatcapNodeMaterial extends NodeMaterial { } + /** + * Setups the matcap specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( builder ) { const uv = matcapUV; @@ -15929,42 +21435,7 @@ class MeshMatcapNodeMaterial extends NodeMaterial { } -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 ); - - } - -} +/** @module RotateNode **/ /** * Applies a rotation to the given position node. @@ -16052,10 +21523,24 @@ class RotateNode extends TempNode { } +/** + * TSL function for creating a rotate node. + * + * @function + * @param {Node} positionNode - The position node. + * @param {Node} rotationNode - Represents the rotation that is applied to the position node. Depending + * on whether the position data are 2D or 3D, the rotation is expressed a single float value or an Euler value. + * @returns {RotateNode} + */ const rotate = /*@__PURE__*/ nodeProxy( RotateNode ); -const _defaultValues$1 = /*@__PURE__*/ new SpriteMaterial(); +const _defaultValues$2 = /*@__PURE__*/ new SpriteMaterial(); +/** + * Node material version of `SpriteMaterial`. + * + * @augments NodeMaterial + */ class SpriteNodeMaterial extends NodeMaterial { static get type() { @@ -16064,47 +21549,100 @@ class SpriteNodeMaterial extends NodeMaterial { } + /** + * Constructs a new sprite node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSpriteNodeMaterial = true; - this.lights = false; this._useSizeAttenuation = true; + /** + * This property makes it possible to define the position of the sprite with a + * node. That can be useful when the material is used with instanced rendering + * and node data are defined with an instanced attribute node: + * ```js + * const positionAttribute = new InstancedBufferAttribute( new Float32Array( positions ), 3 ); + * material.positionNode = instancedBufferAttribute( positionAttribute ); + * ``` + * Another possibility is to compute the instanced data with a compute shader: + * ```js + * const positionBuffer = instancedArray( particleCount, 'vec3' ); + * particleMaterial.positionNode = positionBuffer.toAttribute(); + * ``` + * + * @type {Node?} + * @default null + */ this.positionNode = null; + + /** + * The rotation of sprite materials is by default inferred from the `rotation`, + * property. This node property allows to overwrite the default and define + * the rotation with a node instead. + * + * If you don't want to overwrite the rotation but modify the existing + * value instead, use {@link module:MaterialNode.materialRotation}. + * + * @type {Node?} + * @default null + */ this.rotationNode = null; + + /** + * This node property provides an additional way to scale sprites next to + * `Object3D.scale`. The scale transformation based in `Object3D.scale` + * is multiplied with the scale value of this node in the vertex shader. + * + * @type {Node?} + * @default null + */ this.scaleNode = null; - this.setDefaultValues( _defaultValues$1 ); + this.setDefaultValues( _defaultValues$2 ); this.setValues( parameters ); } - setupPosition( { object, camera, context } ) { + /** + * Setups the position node in view space. This method implements + * the sprite specific vertex shader. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in view space. + */ + setupPositionView( builder ) { + + const { object, camera } = builder; const sizeAttenuation = this.sizeAttenuation; - // < VERTEX STAGE > - const { positionNode, rotationNode, scaleNode } = this; - const vertex = positionLocal; - - let mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) ); + const mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) ); let scale = vec2( modelWorldMatrix[ 0 ].xyz.length(), modelWorldMatrix[ 1 ].xyz.length() ); if ( scaleNode !== null ) { - scale = scale.mul( scaleNode ); + scale = scale.mul( float( scaleNode ) ); } - - if ( ! sizeAttenuation ) { + if ( sizeAttenuation === false ) { if ( camera.isPerspectiveCamera ) { @@ -16119,11 +21657,11 @@ class SpriteNodeMaterial extends NodeMaterial { } - let alignedPosition = vertex.xy; + let alignedPosition = positionGeometry.xy; if ( object.center && object.center.isVector2 === true ) { - const center = reference$1( 'center', 'vec2' ); + const center = reference$1( 'center', 'vec2', object ); alignedPosition = alignedPosition.sub( center.sub( 0.5 ) ); @@ -16135,13 +21673,7 @@ class SpriteNodeMaterial extends NodeMaterial { const rotatedPosition = rotate( alignedPosition, rotation ); - mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw ); - - const modelViewProjection = cameraProjectionMatrix.mul( mvPosition ); - - context.vertex = vertex; - - return modelViewProjection; + return vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw ); } @@ -16155,6 +21687,12 @@ class SpriteNodeMaterial extends NodeMaterial { } + /** + * Whether to use size attenuation or not. + * + * @type {Boolean} + * @default true + */ get sizeAttenuation() { return this._useSizeAttenuation; @@ -16174,6 +21712,148 @@ class SpriteNodeMaterial extends NodeMaterial { } +const _defaultValues$1 = /*@__PURE__*/ new PointsMaterial(); + +/** + * Node material version of `PointsMaterial`. + * + * @augments NodeMaterial + */ +class PointsNodeMaterial extends SpriteNodeMaterial { + + static get type() { + + return 'PointsNodeMaterial'; + + } + + /** + * Constructs a new points node material. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters ) { + + super(); + + /** + * This node property provides an additional way to set the point size. + * + * @type {Node?} + * @default null + */ + this.sizeNode = null; + + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isPointsNodeMaterial = true; + + this.setDefaultValues( _defaultValues$1 ); + + this.setValues( parameters ); + + } + + setupPositionView() { + + const { positionNode } = this; + + return modelViewMatrix.mul( vec3( positionNode || positionLocal ) ).xyz; + + } + + setupVertex( builder ) { + + const mvp = super.setupVertex( builder ); + + // skip further processing if the material is not a node material + + if ( builder.material.isNodeMaterial !== true ) { + + return mvp; + + } + + // ndc space + + const { rotationNode, scaleNode, sizeNode } = this; + + const alignedPosition = positionGeometry.xy.toVar(); + const aspect = viewport.z.div( viewport.w ); + + // rotation + + if ( rotationNode && rotationNode.isNode ) { + + const rotation = float( rotationNode ); + + alignedPosition.assign( rotate( alignedPosition, rotation ) ); + + } + + // point size + + let pointSize = sizeNode !== null ? vec2( sizeNode ) : materialPointSize; + + if ( this.sizeAttenuation === true ) { + + pointSize = pointSize.mul( pointSize.div( positionView.z.negate() ) ); + + } + + // scale + + if ( scaleNode && scaleNode.isNode ) { + + pointSize = pointSize.mul( vec2( scaleNode ) ); + + } + + alignedPosition.mulAssign( pointSize.mul( 2 ) ); + + alignedPosition.assign( alignedPosition.div( viewport.z ) ); + alignedPosition.y.assign( alignedPosition.y.mul( aspect ) ); + + // back to clip space + alignedPosition.assign( alignedPosition.mul( mvp.w ) ); + + //clipPos.xy += offset; + mvp.addAssign( vec4( alignedPosition, 0, 0 ) ); + + return mvp; + + } + + /** + * Whether alpha to coverage should be used or not. + * + * @type {Boolean} + * @default true + */ + get alphaToCoverage() { + + return this._useAlphaToCoverage; + + } + + set alphaToCoverage( value ) { + + if ( this._useAlphaToCoverage !== value ) { + + this._useAlphaToCoverage = value; + this.needsUpdate = true; + + } + + } + +} + /** * Represents lighting model for a shadow material. Used in {@link ShadowNodeMaterial}. * @@ -16225,6 +21905,11 @@ class ShadowMaskModel extends LightingModel { const _defaultValues = /*@__PURE__*/ new ShadowMaterial(); +/** + * Node material version of `ShadowMaterial`. + * + * @augments NodeMaterial + */ class ShadowNodeMaterial extends NodeMaterial { static get type() { @@ -16233,12 +21918,31 @@ class ShadowNodeMaterial extends NodeMaterial { } + /** + * Constructs a new shadow node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isShadowNodeMaterial = true; + /** + * Set to `true` because so it's possible to implement + * the shadow mask effect. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues ); @@ -16247,6 +21951,11 @@ class ShadowNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {ShadowMaskModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new ShadowMaskModel(); @@ -16255,6 +21964,8 @@ class ShadowNodeMaterial extends NodeMaterial { } +/** @module Texture3DNode **/ + const normal = Fn( ( { texture, uv } ) => { const epsilon = 0.0001; @@ -16301,7 +22012,11 @@ const normal = Fn( ( { texture, uv } ) => { } ); - +/** + * This type of uniform node represents a 3D texture. + * + * @augments module:TextureNode~TextureNode + */ class Texture3DNode extends TextureNode { static get type() { @@ -16310,40 +22025,108 @@ class Texture3DNode extends TextureNode { } + /** + * Constructs a new 3D texture node. + * + * @param {Data3DTexture} value - The 3D texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + */ constructor( value, uvNode = null, levelNode = null ) { super( value, uvNode, levelNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isTexture3DNode = true; } + /** + * Overwrites the default implementation to return a fixed value `'texture3D'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'texture3D'; } + /** + * Returns a default uv node which is in context of 3D textures a three-dimensional + * uv node. + * + * @return {Node} The default uv node. + */ getDefaultUV() { return vec3( 0.5, 0.5, 0.5 ); } + /** + * Overwritten with an empty implementation since the `updateMatrix` flag is ignored + * for 3D textures. The uv transformation matrix is not applied to 3D textures. + * + * @param {Boolean} value - The update toggle. + */ setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for 3d TextureNode + /** + * Overwrites the default implementation to return the unmodified uv node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to setup. + * @return {Node} The unmodified uv node. + */ setupUV( builder, uvNode ) { + const texture = this.value; + + if ( builder.isFlipY() && ( texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true ) ) { + + if ( this.sampler ) { + + uvNode = uvNode.flipY(); + + } else { + + uvNode = uvNode.setY( int( textureSize( this, this.levelNode ).y ).sub( uvNode.y ).sub( 1 ) ); + + } + + } + return uvNode; } + /** + * Generates the uv code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to generate code for. + * @return {String} The generated code snippet. + */ generateUV( builder, uvNode ) { return uvNode.build( builder, 'vec3' ); } + /** + * TODO. + * + * @param {Node} uvNode - The uv node . + * @return {Node} TODO. + */ normal( uvNode ) { return normal( { texture: this, uv: uvNode } ); @@ -16352,8 +22135,25 @@ class Texture3DNode extends TextureNode { } +/** + * TSL function for creating a 3D texture node. + * + * @function + * @param {Data3DTexture} value - The 3D texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @returns {Texture3DNode} + */ const texture3D = /*@__PURE__*/ nodeProxy( Texture3DNode ); +/** @module VolumeNodeMaterial **/ + +/** + * Node material intended for volume rendering. The volumetric data are + * defined with an instance of {@link Data3DTexture}. + * + * @augments NodeMaterial + */ class VolumeNodeMaterial extends NodeMaterial { static get type() { @@ -16362,18 +22162,85 @@ class VolumeNodeMaterial extends NodeMaterial { } - constructor( params = {} ) { + /** + * Constructs a new volume node material. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters ) { super(); - this.lights = false; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVolumeNodeMaterial = true; + + /** + * The base color of the volume. + * + * @type {Color} + * @default 100 + */ + this.base = new Color( 0xffffff ); + + /** + * A 3D data texture holding the volumetric data. + * + * @type {Data3DTexture?} + * @default null + */ + this.map = null; + + /** + * This number of samples for each ray that hits the mesh's surface + * and travels through the volume. + * + * @type {Number} + * @default 100 + */ + this.steps = 100; + + /** + * Callback for {@link VolumeNodeMaterial#testNode}. + * + * @callback testNodeCallback + * @param {Data3DTexture} map - The 3D texture. + * @param {Node} mapValue - The sampled value inside the volume. + * @param {Node} probe - The probe which is the entry point of the ray on the mesh's surface. + * @param {Node} finalColor - The final color. + */ + + /** + * The volume rendering of this material works by shooting rays + * from the camera position through each fragment of the mesh's + * surface and sample the inner volume in a raymarching fashion + * multiple times. + * + * This node can be used to assign a callback function of type `Fn` + * that will be executed per sample. The callback receives the + * texture, the sampled texture value as well as position on the surface + * where the rays enters the volume. The last parameter is a color + * that allows the callback to determine the final color. + * + * @type {testNodeCallback?} + * @default null + */ this.testNode = null; - this.setValues( params ); + this.setValues( parameters ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const map = texture3D( this.map, null, 0 ); @@ -16450,19 +22317,65 @@ class VolumeNodeMaterial extends NodeMaterial { } +/** + * This module manages the internal animation loop of the renderer. + * + * @private + */ class Animation { + /** + * Constructs a new animation loop management component. + * + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( nodes, info ) { + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; + /** + * A reference to the context from `requestAnimationFrame()` can + * be called (usually `window`). + * + * @type {Window|XRSession} + */ this._context = self; + + /** + * The user-defined animation loop. + * + * @type {Function?} + * @default null + */ this._animationLoop = null; + + /** + * The requestId which is returned from the `requestAnimationFrame()` call. + * Can be used to cancel the stop the animation loop. + * + * @type {Number?} + * @default null + */ this._requestId = null; } + /** + * Starts the internal animation loop. + */ start() { const update = ( time, frame ) => { @@ -16483,6 +22396,9 @@ class Animation { } + /** + * Stops the internal animation loop. + */ stop() { this._context.cancelAnimationFrame( this._requestId ); @@ -16491,18 +22407,31 @@ class Animation { } + /** + * Defines the user-level animation loop. + * + * @param {Function} callback - The animation loop. + */ setAnimationLoop( callback ) { this._animationLoop = callback; } + /** + * Defines the context in which `requestAnimationFrame()` is executed. + * + * @param {Window|XRSession} context - The context to set. + */ setContext( context ) { this._context = context; } + /** + * Frees all internal resources and stops the animation loop. + */ dispose() { this.stop(); @@ -16511,19 +22440,41 @@ class Animation { } +/** + * Data structure for the renderer. It allows defining values + * with chained, hierarchical keys. Keys are meant to be + * objects since the module internally works with Weak Maps + * for performance reasons. + * + * @private + */ class ChainMap { + /** + * Constructs a new Chain Map. + */ constructor() { + /** + * The root Weak Map. + * + * @type {WeakMap} + */ this.weakMap = new WeakMap(); } + /** + * Returns the value for the given array of keys. + * + * @param {Array} keys - List of keys. + * @return {Any} The value. Returns `undefined` if no value was found. + */ get( keys ) { let map = this.weakMap; - for ( let i = 0; i < keys.length; i ++ ) { + for ( let i = 0; i < keys.length - 1; i ++ ) { map = map.get( keys[ i ] ); @@ -16535,11 +22486,18 @@ class ChainMap { } + /** + * Sets the value for the given keys. + * + * @param {Array} keys - List of keys. + * @param {Any} value - The value to set. + * @return {ChainMap} A reference to this Chain Map. + */ set( keys, value ) { let map = this.weakMap; - for ( let i = 0; i < keys.length; i ++ ) { + for ( let i = 0; i < keys.length - 1; i ++ ) { const key = keys[ i ]; @@ -16549,15 +22507,23 @@ class ChainMap { } - return map.set( keys[ keys.length - 1 ], value ); + map.set( keys[ keys.length - 1 ], value ); + + return this; } + /** + * Deletes a value for the given keys. + * + * @param {Array} keys - The keys. + * @return {Boolean} Returns `true` if the value has been removed successfully and `false` if the value has not be found. + */ delete( keys ) { let map = this.weakMap; - for ( let i = 0; i < keys.length; i ++ ) { + for ( let i = 0; i < keys.length - 1; i ++ ) { map = map.get( keys[ i ] ); @@ -16571,7 +22537,7 @@ class ChainMap { } -let _id$8 = 0; +let _id$9 = 0; function getKeys( obj ) { @@ -16607,49 +22573,264 @@ function getKeys( obj ) { } +/** + * A render object is the renderer's representation of single entity that gets drawn + * with a draw command. There is no unique mapping of render objects to 3D objects in the + * scene since render objects also depend from the used material, the current render context + * and the current scene's lighting. + * + * In general, the basic process of the renderer is: + * + * - Analyze the 3D objects in the scene and generate render lists containing render items. + * - Process the render lists by calling one or more render commands for each render item. + * - For each render command, request a render object and perform the draw. + * + * The module provides an interface to get data required for the draw command like the actual + * draw parameters or vertex buffers. It also holds a series of caching related methods since + * creating render objects should only be done when necessary. + * + * @private + */ class RenderObject { + /** + * Constructs a new render object. + * + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Geometries} geometries - Renderer component for managing geometries. + * @param {Renderer} renderer - The renderer. + * @param {Object3D} object - The 3D object. + * @param {Material} material - The 3D object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The lights node. + * @param {RenderContext} renderContext - The render context. + * @param {ClippingContext} clippingContext - The clipping context. + */ constructor( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext ) { + this.id = _id$9 ++; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + * @private + */ this._nodes = nodes; - this._geometries = geometries; - this.id = _id$8 ++; + /** + * Renderer component for managing geometries. + * + * @type {Geometries} + * @private + */ + this._geometries = geometries; + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * The 3D object. + * + * @type {Object3D} + */ this.object = object; + + /** + * The 3D object's material. + * + * @type {Material} + */ this.material = material; + + /** + * The scene the 3D object belongs to. + * + * @type {Scene} + */ this.scene = scene; + + /** + * The camera the 3D object should be rendered with. + * + * @type {Camera} + */ this.camera = camera; + + /** + * The lights node. + * + * @type {LightsNode} + */ this.lightsNode = lightsNode; + + /** + * The render context. + * + * @type {RenderContext} + */ this.context = renderContext; + /** + * The 3D object's geometry. + * + * @type {BufferGeometry} + */ this.geometry = object.geometry; + + /** + * The render object's version. + * + * @type {Number} + */ this.version = material.version; + /** + * The draw range of the geometry. + * + * @type {Object?} + * @default null + */ this.drawRange = null; + /** + * An array holding the buffer attributes + * of the render object. This entails attribute + * definitions on geometry and node level. + * + * @type {Array?} + * @default null + */ this.attributes = null; + + /** + * A reference to a render pipeline the render + * object is processed with. + * + * @type {RenderPipeline} + * @default null + */ this.pipeline = null; + + /** + * Only relevant for objects using + * multiple materials. This represents a group entry + * from the respective `BufferGeometry`. + * + * @type {{start: Number, count: Number}?} + * @default null + */ + this.group = null; + + /** + * An array holding the vertex buffers which can + * be buffer attributes but also interleaved buffers. + * + * @type {Array?} + * @default null + */ this.vertexBuffers = null; + + /** + * The parameters for the draw command. + * + * @type {Object?} + * @default null + */ this.drawParams = null; + /** + * If this render object is used inside a render bundle, + * this property points to the respective bundle group. + * + * @type {BundleGroup?} + * @default null + */ this.bundle = null; + /** + * The clipping context. + * + * @type {ClippingContext} + */ this.clippingContext = clippingContext; + + /** + * The clipping context's cache key. + * + * @type {String} + */ this.clippingContextCacheKey = clippingContext !== null ? clippingContext.cacheKey : ''; + /** + * The initial node cache key. + * + * @type {Number} + */ this.initialNodesCacheKey = this.getDynamicCacheKey(); + + /** + * The initial cache key. + * + * @type {Number} + */ this.initialCacheKey = this.getCacheKey(); + /** + * The node builder state. + * + * @type {NodeBuilderState?} + * @private + * @default null + */ this._nodeBuilderState = null; + + /** + * An array of bindings. + * + * @type {Array?} + * @private + * @default null + */ this._bindings = null; + + /** + * Reference to the node material observer. + * + * @type {NodeMaterialObserver?} + * @private + * @default null + */ this._monitor = null; + /** + * An event listener which is defined by `RenderObjects`. It performs + * clean up tasks when `dispose()` on this render object. + * + * @method + */ this.onDispose = null; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isRenderObject = true; + /** + * An event listener which is executed when `dispose()` is called on + * the render object's material. + * + * @method + */ this.onMaterialDispose = () => { this.dispose(); @@ -16660,12 +22841,23 @@ class RenderObject { } - updateClipping( parent ) { + /** + * Updates the clipping context. + * + * @param {ClippingContext} context - The clipping context to set. + */ + updateClipping( context ) { - this.clippingContext = parent; + this.clippingContext = context; } + /** + * Whether the clipping requires an update or not. + * + * @type {Boolean} + * @readonly + */ get clippingNeedsUpdate() { if ( this.clippingContext === null || this.clippingContext.cacheKey === this.clippingContextCacheKey ) return false; @@ -16676,48 +22868,90 @@ class RenderObject { } + /** + * The number of clipping planes defined in context of hardware clipping. + * + * @type {Number} + * @readonly + */ get hardwareClippingPlanes() { return this.material.hardwareClipping === true ? this.clippingContext.unionClippingCount : 0; } + /** + * Returns the node builder state of this render object. + * + * @return {NodeBuilderState} The node builder state. + */ getNodeBuilderState() { return this._nodeBuilderState || ( this._nodeBuilderState = this._nodes.getForRender( this ) ); } + /** + * Returns the node material observer of this render object. + * + * @return {NodeMaterialObserver} The node material observer. + */ getMonitor() { return this._monitor || ( this._monitor = this.getNodeBuilderState().monitor ); } + /** + * Returns an array of bind groups of this render object. + * + * @return {Array} The bindings. + */ getBindings() { return this._bindings || ( this._bindings = this.getNodeBuilderState().createBindings() ); } + /** + * Returns the index of the render object's geometry. + * + * @return {BufferAttribute?} The index. Returns `null` for non-indexed geometries. + */ getIndex() { return this._geometries.getIndex( this ); } + /** + * Returns the indirect buffer attribute. + * + * @return {BufferAttribute?} The indirect attribute. `null` if no indirect drawing is used. + */ getIndirect() { return this._geometries.getIndirect( this ); } + /** + * Returns an array that acts as a key for identifying the render object in a chain map. + * + * @return {Array} An array with object references. + */ getChainArray() { return [ this.object, this.material, this.context, this.lightsNode ]; } + /** + * This method is used when the geometry of a 3D object has been exchanged and the + * respective render object now requires an update. + * + * @param {BufferGeometry} geometry - The geometry to set. + */ setGeometry( geometry ) { this.geometry = geometry; @@ -16725,6 +22959,12 @@ class RenderObject { } + /** + * Returns the buffer attributes of the render object. The returned array holds + * attribute definitions on geometry and node level. + * + * @return {Array} An array with buffer attributes. + */ getAttributes() { if ( this.attributes !== null ) return this.attributes; @@ -16755,6 +22995,11 @@ class RenderObject { } + /** + * Returns the vertex buffers of the render object. + * + * @return {Array} An array with buffer attribute or interleaved buffers. + */ getVertexBuffers() { if ( this.vertexBuffers === null ) this.getAttributes(); @@ -16763,6 +23008,11 @@ class RenderObject { } + /** + * Returns the draw parameters for the render object. + * + * @return {{vertexCount: Number, firstVertex: Number, instanceCount: Number, firstInstance: Number}} The draw parameters. + */ getDrawParameters() { const { object, material, geometry, group, drawRange } = this; @@ -16829,6 +23079,13 @@ class RenderObject { } + /** + * Returns the render object's geometry cache key. + * + * The geometry cache key is part of the material cache key. + * + * @return {String} The geometry cache key. + */ getGeometryCacheKey() { const { geometry } = this; @@ -16848,6 +23105,26 @@ class RenderObject { } + // structural equality isn't sufficient for morph targets since the + // data are maintained in textures. only if the targets are all equal + // the texture and thus the instance of `MorphNode` can be shared. + + for ( const name of Object.keys( geometry.morphAttributes ).sort() ) { + + const targets = geometry.morphAttributes[ name ]; + + cacheKey += 'morph-' + name + ','; + + for ( let i = 0, l = targets.length; i < l; i ++ ) { + + const attribute = targets[ i ]; + + cacheKey += attribute.id + ','; + + } + + } + if ( geometry.index ) { cacheKey += 'index,'; @@ -16858,6 +23135,13 @@ class RenderObject { } + /** + * Returns the render object's material cache key. + * + * The material cache key is part of the render object cache key. + * + * @return {Number} The material cache key. + */ getMaterialCacheKey() { const { object, material } = this; @@ -16924,12 +23208,6 @@ class RenderObject { } - if ( object.morphTargetInfluences ) { - - cacheKey += object.morphTargetInfluences.length + ','; - - } - if ( object.isBatchedMesh ) { cacheKey += object._matricesTexture.uuid + ','; @@ -16956,23 +23234,58 @@ class RenderObject { } + /** + * Whether the geometry requires an update or not. + * + * @type {Boolean} + * @readonly + */ get needsGeometryUpdate() { return this.geometry.id !== this.object.geometry.id; } + /** + * Whether the render object requires an update or not. + * + * Note: There are two distinct places where render objects are checked for an update. + * + * 1. In `RenderObjects.get()` which is executed when the render object is request. This + * method checks the `needsUpdate` flag and recreates the render object if necessary. + * 2. In `Renderer._renderObjectDirect()` right after getting the render object via + * `RenderObjects.get()`. The render object's NodeMaterialObserver is then used to detect + * a need for a refresh due to material, geometry or object related value changes. + * + * TODO: Investigate if it's possible to merge both steps so there is only a single place + * that performs the 'needsUpdate' check. + * + * @type {Boolean} + * @readonly + */ get needsUpdate() { return /*this.object.static !== true &&*/ ( this.initialNodesCacheKey !== this.getDynamicCacheKey() || this.clippingNeedsUpdate ); } + /** + * Returns the dynamic cache key which represents a key that is computed per draw command. + * + * @return {Number} The cache key. + */ getDynamicCacheKey() { - // Environment Nodes Cache Key + let cacheKey = 0; - let cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); + // `Nodes.getCacheKey()` returns an environment cache key which is not relevant when + // the renderer is inside a shadow pass. + + if ( this.material.isShadowPassMaterial !== true ) { + + cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); + + } if ( this.object.receiveShadow ) { @@ -16984,12 +23297,20 @@ class RenderObject { } + /** + * Returns the render object's cache key. + * + * @return {Number} The cache key. + */ getCacheKey() { return this.getMaterialCacheKey() + this.getDynamicCacheKey(); } + /** + * Frees internal resources. + */ dispose() { this.material.removeEventListener( 'dispose', this.onMaterialDispose ); @@ -17000,40 +23321,109 @@ class RenderObject { } -const chainArray = []; +const _chainKeys$5 = []; +/** + * This module manages the render objects of the renderer. + * + * @private + */ class RenderObjects { + /** + * Constructs a new render object management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Geometries} geometries - Renderer component for managing geometries. + * @param {Pipelines} pipelines - Renderer component for managing pipelines. + * @param {Bindings} bindings - Renderer component for managing bindings. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( renderer, nodes, geometries, pipelines, bindings, info ) { + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; + + /** + * Renderer component for managing geometries. + * + * @type {Geometries} + */ this.geometries = geometries; + + /** + * Renderer component for managing pipelines. + * + * @type {Pipelines} + */ this.pipelines = pipelines; + + /** + * Renderer component for managing bindings. + * + * @type {Bindings} + */ this.bindings = bindings; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; + /** + * A dictionary that manages render contexts in chain maps + * for each pass ID. + * + * @type {Object} + */ this.chainMaps = {}; } + /** + * Returns a render object for the given object and state data. + * + * @param {Object3D} object - The 3D object. + * @param {Material} material - The 3D object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the 3D object should be rendered with. + * @param {LightsNode} lightsNode - The lights node. + * @param {RenderContext} renderContext - The render context. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} passId - An optional ID for identifying the pass. + * @return {RenderObject} The render object. + */ get( object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ) { const chainMap = this.getChainMap( passId ); // reuse chainArray - chainArray[ 0 ] = object; - chainArray[ 1 ] = material; - chainArray[ 2 ] = renderContext; - chainArray[ 3 ] = lightsNode; + _chainKeys$5[ 0 ] = object; + _chainKeys$5[ 1 ] = material; + _chainKeys$5[ 2 ] = renderContext; + _chainKeys$5[ 3 ] = lightsNode; - let renderObject = chainMap.get( chainArray ); + let renderObject = chainMap.get( _chainKeys$5 ); if ( renderObject === undefined ) { renderObject = this.createRenderObject( this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ); - chainMap.set( chainArray, renderObject ); + chainMap.set( _chainKeys$5, renderObject ); } else { @@ -17063,22 +23453,49 @@ class RenderObjects { } + _chainKeys$5.length = 0; + return renderObject; } + /** + * Returns a chain map for the given pass ID. + * + * @param {String} [passId='default'] - The pass ID. + * @return {ChainMap} The chain map. + */ getChainMap( passId = 'default' ) { return this.chainMaps[ passId ] || ( this.chainMaps[ passId ] = new ChainMap() ); } + /** + * Frees internal resources. + */ dispose() { this.chainMaps = {}; } + /** + * Factory method for creating render objects with the given list of parameters. + * + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Geometries} geometries - Renderer component for managing geometries. + * @param {Renderer} renderer - The renderer. + * @param {Object3D} object - The 3D object. + * @param {Material} material - The object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The lights node. + * @param {RenderContext} renderContext - The render context. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} passId - An optional ID for identifying the pass. + * @return {RenderObject} The render object. + */ createRenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ) { const chainMap = this.getChainMap( passId ); @@ -17102,14 +23519,35 @@ class RenderObjects { } +/** + * Data structure for the renderer. It is intended to manage + * data of objects in dictionaries. + * + * @private + */ class DataMap { + /** + * Constructs a new data map. + */ constructor() { + /** + * `DataMap` internally uses a weak map + * to manage its data. + * + * @type {WeakMap} + */ this.data = new WeakMap(); } + /** + * Returns the dictionary for the given object. + * + * @param {Object} object - The object. + * @return {Object} The dictionary. + */ get( object ) { let map = this.data.get( object ); @@ -17125,9 +23563,15 @@ class DataMap { } + /** + * Deletes the dictionary for the given object. + * + * @param {Object} object - The object. + * @return {Object?} The deleted dictionary. + */ delete( object ) { - let map; + let map = null; if ( this.data.has( object ) ) { @@ -17141,12 +23585,21 @@ class DataMap { } + /** + * Returns `true` if the given object has a dictionary defined. + * + * @param {Object} object - The object to test. + * @return {Boolean} Whether a dictionary is defined or not. + */ has( object ) { return this.data.has( object ); } + /** + * Frees internal resources. + */ dispose() { this.data = new WeakMap(); @@ -17171,16 +23624,38 @@ const GPU_CHUNK_BYTES = 16; const BlendColorFactor = 211; const OneMinusBlendColorFactor = 212; +/** + * This renderer module manages geometry attributes. + * + * @private + * @augments DataMap + */ class Attributes extends DataMap { + /** + * Constructs a new attribute management component. + * + * @param {Backend} backend - The renderer's backend. + */ constructor( backend ) { super(); + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; } + /** + * Deletes the data for the given attribute. + * + * @param {BufferAttribute} attribute - The attribute. + * @return {Object} The deleted attribute data. + */ delete( attribute ) { const attributeData = super.delete( attribute ); @@ -17195,6 +23670,13 @@ class Attributes extends DataMap { } + /** + * Updates the given attribute. This method creates attribute buffers + * for new attributes and updates data for existing ones. + * + * @param {BufferAttribute} attribute - The attribute to update. + * @param {Number} type - The attribute type. + */ update( attribute, type ) { const data = this.get( attribute ); @@ -17237,6 +23719,13 @@ class Attributes extends DataMap { } + /** + * Utility method for handling interleaved buffer attributes correctly. + * To process them, their `InterleavedBuffer` is returned. + * + * @param {BufferAttribute} attribute - The attribute. + * @return {BufferAttribute|InterleavedBuffer} + */ _getBufferAttribute( attribute ) { if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; @@ -17247,6 +23736,14 @@ class Attributes extends DataMap { } +/** + * Returns `true` if the given array has values that require an Uint32 array type. + * + * @private + * @function + * @param {Array} array - The array to test. + * @return {Boolean} Whether the given array has values that require an Uint32 array type or not. + */ function arrayNeedsUint32( array ) { // assumes larger values usually on last @@ -17261,12 +23758,28 @@ function arrayNeedsUint32( array ) { } +/** + * Returns the wireframe version for the given geometry. + * + * @private + * @function + * @param {BufferGeometry} geometry - The geometry. + * @return {Number} The version. + */ function getWireframeVersion( geometry ) { return ( geometry.index !== null ) ? geometry.index.version : geometry.attributes.position.version; } +/** + * Returns a wireframe index attribute for the given geometry. + * + * @private + * @function + * @param {BufferGeometry} geometry - The geometry. + * @return {BufferAttribute} The wireframe index attribute. + */ function getWireframeIndex( geometry ) { const indices = []; @@ -17311,21 +23824,61 @@ function getWireframeIndex( geometry ) { } +/** + * This renderer module manages geometries. + * + * @private + * @augments DataMap + */ class Geometries extends DataMap { + /** + * Constructs a new geometry management component. + * + * @param {Attributes} attributes - Renderer component for managing attributes. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( attributes, info ) { super(); + /** + * Renderer component for managing attributes. + * + * @type {Attributes} + */ this.attributes = attributes; - this.info = info; - this.wireframes = new WeakMap(); + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ + this.info = info; + /** + * Weak Map for managing attributes for wireframe rendering. + * + * @type {WeakMap} + */ + this.wireframes = new WeakMap(); + + /** + * This Weak Map is used to make sure buffer attributes are + * updated only once per render call. + * + * @type {WeakMap} + */ this.attributeCall = new WeakMap(); } + /** + * Returns `true` if the given render object has an initialized geometry. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether if the given render object has an initialized geometry or not. + */ has( renderObject ) { const geometry = renderObject.geometry; @@ -17334,6 +23887,11 @@ class Geometries extends DataMap { } + /** + * Prepares the geometry of the given render object for rendering. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { if ( this.has( renderObject ) === false ) this.initGeometry( renderObject ); @@ -17342,6 +23900,11 @@ class Geometries extends DataMap { } + /** + * Initializes the geometry of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ initGeometry( renderObject ) { const geometry = renderObject.geometry; @@ -17386,6 +23949,11 @@ class Geometries extends DataMap { } + /** + * Updates the geometry attributes of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateAttributes( renderObject ) { // attributes @@ -17428,6 +23996,12 @@ class Geometries extends DataMap { } + /** + * Updates the given attribute. + * + * @param {BufferAttribute} attribute - The attribute to update. + * @param {Number} type - The attribute type. + */ updateAttribute( attribute, type ) { const callId = this.info.render.calls; @@ -17464,12 +24038,25 @@ class Geometries extends DataMap { } + /** + * Returns the indirect buffer attribute of the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {BufferAttribute?} The indirect attribute. `null` if no indirect drawing is used. + */ getIndirect( renderObject ) { return renderObject.geometry.indirect; } + /** + * Returns the index of the given render object's geometry. This is implemented + * in a method to return a wireframe index if necessary. + * + * @param {RenderObject} renderObject - The render object. + * @return {BufferAttribute?} The index. Returns `null` for non-indexed geometries. + */ getIndex( renderObject ) { const { geometry, material } = renderObject; @@ -17508,15 +24095,64 @@ class Geometries extends DataMap { } +/** + * This renderer module provides a series of statistical information + * about the GPU memory and the rendering process. Useful for debugging + * and monitoring. + */ class Info { + /** + * Constructs a new info component. + */ constructor() { + /** + * Whether frame related metrics should automatically + * be resetted or not. This property should be set to `false` + * by apps which manage their own animation loop. They must + * then call `renderer.info.reset()` once per frame manually. + * + * @type {Boolean} + * @default true + */ this.autoReset = true; + /** + * The current frame ID. This ID is managed + * by `NodeFrame`. + * + * @type {Number} + * @readonly + * @default 0 + */ this.frame = 0; + + /** + * The number of render calls since the + * app has been started. + * + * @type {Number} + * @readonly + * @default 0 + */ this.calls = 0; + /** + * Render related metrics. + * + * @type {Object} + * @readonly + * @property {Number} calls - The number of render calls since the app has been started. + * @property {Number} frameCalls - The number of render calls of the current frame. + * @property {Number} drawCalls - The number of draw calls of the current frame. + * @property {Number} triangles - The number of rendered triangle primitives of the current frame. + * @property {Number} points - The number of rendered point primitives of the current frame. + * @property {Number} lines - The number of rendered line primitives of the current frame. + * @property {Number} previousFrameCalls - The number of render calls of the previous frame. + * @property {Number} timestamp - The timestamp of the frame when using `renderer.renderAsync()`. + * @property {Number} timestampCalls - The number of render calls using `renderer.renderAsync()`. + */ this.render = { calls: 0, frameCalls: 0, @@ -17529,6 +24165,17 @@ class Info { timestampCalls: 0 }; + /** + * Compute related metrics. + * + * @type {Object} + * @readonly + * @property {Number} calls - The number of compute calls since the app has been started. + * @property {Number} frameCalls - The number of compute calls of the current frame. + * @property {Number} previousFrameCalls - The number of compute calls of the previous frame. + * @property {Number} timestamp - The timestamp of the frame when using `renderer.computeAsync()`. + * @property {Number} timestampCalls - The number of render calls using `renderer.computeAsync()`. + */ this.compute = { calls: 0, frameCalls: 0, @@ -17537,6 +24184,14 @@ class Info { timestampCalls: 0 }; + /** + * Memory related metrics. + * + * @type {Object} + * @readonly + * @property {Number} geometries - The number of active geometries. + * @property {Number} frameCalls - The number of active textures. + */ this.memory = { geometries: 0, textures: 0 @@ -17544,6 +24199,13 @@ class Info { } + /** + * This method should be executed per draw call and updates the corresponding metrics. + * + * @param {Object3D} object - The 3D object that is going to be rendered. + * @param {Number} count - The vertex or index count. + * @param {Number} instanceCount - The instance count. + */ update( object, count, instanceCount ) { this.render.drawCalls ++; @@ -17572,6 +24234,12 @@ class Info { } + /** + * Used by async render methods to updated timestamp metrics. + * + * @param {('render'|'compute')} type - The type of render call. + * @param {Number} time - The duration of the compute/render call in milliseconds. + */ updateTimestamp( type, time ) { if ( this[ type ].timestampCalls === 0 ) { @@ -17595,6 +24263,9 @@ class Info { } + /** + * Resets frame related metrics. + */ reset() { const previousRenderFrameCalls = this.render.frameCalls; @@ -17615,6 +24286,9 @@ class Info { } + /** + * Performs a complete reset of the object. + */ dispose() { this.reset(); @@ -17633,76 +24307,249 @@ class Info { } +/** + * Abstract class for representing pipelines. + * + * @private + * @abstract + */ class Pipeline { + /** + * Constructs a new pipeline. + * + * @param {String} cacheKey - The pipeline's cache key. + */ constructor( cacheKey ) { + /** + * The pipeline's cache key. + * + * @type {String} + */ this.cacheKey = cacheKey; + /** + * How often the pipeline is currently in use. + * + * @type {Number} + * @default 0 + */ this.usedTimes = 0; } } +/** + * Class for representing render pipelines. + * + * @private + * @augments Pipeline + */ class RenderPipeline extends Pipeline { + /** + * Constructs a new render pipeline. + * + * @param {String} cacheKey - The pipeline's cache key. + * @param {ProgrammableStage} vertexProgram - The pipeline's vertex shader. + * @param {ProgrammableStage} fragmentProgram - The pipeline's fragment shader. + */ constructor( cacheKey, vertexProgram, fragmentProgram ) { super( cacheKey ); + /** + * The pipeline's vertex shader. + * + * @type {ProgrammableStage} + */ this.vertexProgram = vertexProgram; + + /** + * The pipeline's fragment shader. + * + * @type {ProgrammableStage} + */ this.fragmentProgram = fragmentProgram; } } +/** + * Class for representing compute pipelines. + * + * @private + * @augments Pipeline + */ class ComputePipeline extends Pipeline { + /** + * Constructs a new render pipeline. + * + * @param {String} cacheKey - The pipeline's cache key. + * @param {ProgrammableStage} computeProgram - The pipeline's compute shader. + */ constructor( cacheKey, computeProgram ) { super( cacheKey ); + /** + * The pipeline's compute shader. + * + * @type {ProgrammableStage} + */ this.computeProgram = computeProgram; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isComputePipeline = true; } } -let _id$7 = 0; +let _id$8 = 0; +/** + * Class for representing programmable stages which are vertex, + * fragment or compute shaders. Unlike fixed-function states (like blending), + * they represent the programmable part of a pipeline. + * + * @private + */ class ProgrammableStage { - constructor( code, type, transforms = null, attributes = null ) { + /** + * Constructs a new programmable stage. + * + * @param {String} code - The shader code. + * @param {('vertex'|'fragment'|'compute')} stage - The type of stage. + * @param {String} name - The name of the shader. + * @param {Array?} [transforms=null] - The transforms (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + * @param {Array?} [attributes=null] - The attributes (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + */ + constructor( code, stage, name, transforms = null, attributes = null ) { - this.id = _id$7 ++; + /** + * The id of the programmable stage. + * + * @type {Number} + */ + this.id = _id$8 ++; + /** + * The shader code. + * + * @type {String} + */ this.code = code; - this.stage = type; + + /** + * The type of stage. + * + * @type {String} + */ + this.stage = stage; + + /** + * The name of the stage. + * This is used for debugging purposes. + * + * @type {String} + */ + this.name = name; + + /** + * The transforms (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + * + * @type {Array?} + */ this.transforms = transforms; + + /** + * The attributes (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + * + * @type {Array?} + */ this.attributes = attributes; + /** + * How often the programmable stage is currently in use. + * + * @type {Number} + * @default 0 + */ this.usedTimes = 0; } } +/** + * This renderer module manages the pipelines of the renderer. + * + * @private + * @augments DataMap + */ class Pipelines extends DataMap { + /** + * Constructs a new pipeline management component. + * + * @param {Backend} backend - The renderer's backend. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + */ constructor( backend, nodes ) { super(); + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; - this.bindings = null; // set by the bindings + /** + * A references to the bindings management component. + * This reference will be set inside the `Bindings` + * constructor. + * + * @type {Bindings?} + * @default null + */ + this.bindings = null; + /** + * Internal cache for maintaining pipelines. + * The key of the map is a cache key, the value the pipeline. + * + * @type {Map} + */ this.caches = new Map(); + + /** + * This dictionary maintains for each shader stage type (vertex, + * fragment and compute) the programmable stage objects which + * represent the actual shader code. + * + * @type {Object} + */ this.programs = { vertex: new Map(), fragment: new Map(), @@ -17711,6 +24558,13 @@ class Pipelines extends DataMap { } + /** + * Returns a compute pipeline for the given compute node. + * + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @return {ComputePipeline} The compute pipeline. + */ getForCompute( computeNode, bindings ) { const { backend } = this; @@ -17740,7 +24594,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.computeProgram ); - stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); + stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', computeNode.name, nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); this.programs.compute.set( nodeBuilderState.computeShader, stageCompute ); backend.createProgram( stageCompute ); @@ -17777,6 +24631,13 @@ class Pipelines extends DataMap { } + /** + * Returns a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array?} [promises=null] - An array of compilation promises which is only relevant in context of `Renderer.compileAsync()`. + * @return {RenderPipeline} The render pipeline. + */ getForRender( renderObject, promises = null ) { const { backend } = this; @@ -17799,6 +24660,8 @@ class Pipelines extends DataMap { const nodeBuilderState = renderObject.getNodeBuilderState(); + const name = renderObject.material ? renderObject.material.name : ''; + // programmable stages let stageVertex = this.programs.vertex.get( nodeBuilderState.vertexShader ); @@ -17807,7 +24670,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.vertexProgram ); - stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex' ); + stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex', name ); this.programs.vertex.set( nodeBuilderState.vertexShader, stageVertex ); backend.createProgram( stageVertex ); @@ -17820,7 +24683,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.fragmentProgram ); - stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment' ); + stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment', name ); this.programs.fragment.set( nodeBuilderState.fragmentShader, stageFragment ); backend.createProgram( stageFragment ); @@ -17861,6 +24724,12 @@ class Pipelines extends DataMap { } + /** + * Deletes the pipeline for the given render object. + * + * @param {RenderObject} object - The render object. + * @return {Object?} The deleted dictionary. + */ delete( object ) { const pipeline = this.get( object ).pipeline; @@ -17897,6 +24766,9 @@ class Pipelines extends DataMap { } + /** + * Frees internal resources. + */ dispose() { super.dispose(); @@ -17910,12 +24782,27 @@ class Pipelines extends DataMap { } + /** + * Updates the pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { this.getForRender( renderObject ); } + /** + * Returns a compute pipeline for the given parameters. + * + * @private + * @param {Node} computeNode - The compute node. + * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. + * @param {String} cacheKey - The cache key. + * @param {Array} bindings - The bindings. + * @return {ComputePipeline} The compute pipeline. + */ _getComputePipeline( computeNode, stageCompute, cacheKey, bindings ) { // check for existing pipeline @@ -17938,6 +24825,17 @@ class Pipelines extends DataMap { } + /** + * Returns a render pipeline for the given parameters. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @param {ProgrammableStage} stageVertex - The programmable stage representing the vertex shader. + * @param {ProgrammableStage} stageFragment - The programmable stage representing the fragment shader. + * @param {String} cacheKey - The cache key. + * @param {Array?} promises - An array of compilation promises which is only relevant in context of `Renderer.compileAsync()`. + * @return {ComputePipeline} The compute pipeline. + */ _getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ) { // check for existing pipeline @@ -17954,6 +24852,10 @@ class Pipelines extends DataMap { renderObject.pipeline = pipeline; + // The `promises` array is `null` by default and only set to an empty array when + // `Renderer.compileAsync()` is used. The next call actually fills the array with + // pending promises that resolve when the render pipelines are ready for rendering. + this.backend.createRenderPipeline( renderObject, promises ); } @@ -17962,24 +24864,53 @@ class Pipelines extends DataMap { } + /** + * Computes a cache key representing a compute pipeline. + * + * @private + * @param {Node} computeNode - The compute node. + * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. + * @return {String} The cache key. + */ _getComputeCacheKey( computeNode, stageCompute ) { return computeNode.id + ',' + stageCompute.id; } + /** + * Computes a cache key representing a render pipeline. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @param {ProgrammableStage} stageVertex - The programmable stage representing the vertex shader. + * @param {ProgrammableStage} stageFragment - The programmable stage representing the fragment shader. + * @return {String} The cache key. + */ _getRenderCacheKey( renderObject, stageVertex, stageFragment ) { return stageVertex.id + ',' + stageFragment.id + ',' + this.backend.getRenderCacheKey( renderObject ); } + /** + * Releases the given pipeline. + * + * @private + * @param {Pipeline} pipeline - The pipeline to release. + */ _releasePipeline( pipeline ) { this.caches.delete( pipeline.cacheKey ); } + /** + * Releases the shader program. + * + * @private + * @param {Object} program - The shader program to release. + */ _releaseProgram( program ) { const code = program.code; @@ -17989,6 +24920,13 @@ class Pipelines extends DataMap { } + /** + * Returns `true` if the compute pipeline for the given compute node requires an update. + * + * @private + * @param {Node} computeNode - The compute node. + * @return {Boolean} Whether the compute pipeline for the given compute node requires an update or not. + */ _needsComputeUpdate( computeNode ) { const data = this.get( computeNode ); @@ -17997,6 +24935,13 @@ class Pipelines extends DataMap { } + /** + * Returns `true` if the render pipeline for the given render object requires an update. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render object for the given render object requires an update or not. + */ _needsRenderUpdate( renderObject ) { const data = this.get( renderObject ); @@ -18007,23 +24952,80 @@ class Pipelines extends DataMap { } +/** + * This renderer module manages the bindings of the renderer. + * + * @private + * @augments DataMap + */ class Bindings extends DataMap { + /** + * Constructs a new bindings management component. + * + * @param {Backend} backend - The renderer's backend. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Textures} textures - Renderer component for managing textures. + * @param {Attributes} attributes - Renderer component for managing attributes. + * @param {Pipelines} pipelines - Renderer component for managing pipelines. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( backend, nodes, textures, attributes, pipelines, info ) { super(); + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * Renderer component for managing textures. + * + * @type {Textures} + */ this.textures = textures; + + /** + * Renderer component for managing pipelines. + * + * @type {Pipelines} + */ this.pipelines = pipelines; + + /** + * Renderer component for managing attributes. + * + * @type {Attributes} + */ this.attributes = attributes; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; this.pipelines.bindings = this; // assign bindings to pipelines } + /** + * Returns the bind groups for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Array} The bind groups. + */ getForRender( renderObject ) { const bindings = renderObject.getBindings(); @@ -18050,6 +25052,12 @@ class Bindings extends DataMap { } + /** + * Returns the bind groups for the given compute node. + * + * @param {Node} computeNode - The compute node. + * @return {Array} The bind groups. + */ getForCompute( computeNode ) { const bindings = this.nodes.getForCompute( computeNode ).bindings; @@ -18074,18 +25082,33 @@ class Bindings extends DataMap { } + /** + * Updates the bindings for the given compute node. + * + * @param {Node} computeNode - The compute node. + */ updateForCompute( computeNode ) { this._updateBindings( this.getForCompute( computeNode ) ); } + /** + * Updates the bindings for the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { this._updateBindings( this.getForRender( renderObject ) ); } + /** + * Updates the given array of bindings. + * + * @param {Array} bindings - The bind groups. + */ _updateBindings( bindings ) { for ( const bindGroup of bindings ) { @@ -18096,6 +25119,11 @@ class Bindings extends DataMap { } + /** + * Initializes the given bind group. + * + * @param {BindGroup} bindGroup - The bind group to initialize. + */ _init( bindGroup ) { for ( const binding of bindGroup.bindings ) { @@ -18117,6 +25145,12 @@ class Bindings extends DataMap { } + /** + * Updates the given bind group. + * + * @param {BindGroup} bindGroup - The bind group to update. + * @param {Array} bindings - The bind groups. + */ _update( bindGroup, bindings ) { const { backend } = this; @@ -18134,7 +25168,10 @@ class Bindings extends DataMap { const updated = this.nodes.updateGroup( binding ); - if ( ! updated ) continue; + // every uniforms group is a uniform buffer. So if no update is required, + // we move one with the next binding. Otherwise the next if block will update the group. + + if ( updated === false ) continue; } @@ -18223,6 +25260,15 @@ class Bindings extends DataMap { } +/** + * Default sorting function for opaque render items. + * + * @private + * @function + * @param {Object} a - The first render item. + * @param {Object} b - The second render item. + * @return {Number} A numeric value which defines the sort order. + */ function painterSortStable( a, b ) { if ( a.groupOrder !== b.groupOrder ) { @@ -18249,6 +25295,15 @@ function painterSortStable( a, b ) { } +/** + * Default sorting function for transparent render items. + * + * @private + * @function + * @param {Object} a - The first render item. + * @param {Object} b - The second render item. + * @return {Number} A numeric value which defines the sort order. + */ function reversePainterSortStable( a, b ) { if ( a.groupOrder !== b.groupOrder ) { @@ -18271,6 +25326,14 @@ function reversePainterSortStable( a, b ) { } +/** + * Returns `true` if the given transparent material requires a double pass. + * + * @private + * @function + * @param {Material} material - The transparent material. + * @return {Boolean} Whether the given material requires a double pass or not. + */ function needsDoublePass( material ) { const hasTransmission = material.transmission > 0 || material.transmissionNode; @@ -18279,28 +25342,120 @@ function needsDoublePass( material ) { } +/** + * When the renderer analyzes the scene at the beginning of a render call, + * it stores 3D object for further processing in render lists. Depending on the + * properties of a 3D objects (like their transformation or material state), the + * objects are maintained in ordered lists for the actual rendering. + * + * Render lists are unique per scene and camera combination. + * + * @private + * @augments Pipeline + */ class RenderList { + /** + * Constructs a render list. + * + * @param {Lighting} lighting - The lighting management component. + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera the scene is rendered with. + */ constructor( lighting, scene, camera ) { + /** + * 3D objects are transformed into render items and stored in this array. + * + * @type {Array} + */ this.renderItems = []; + + /** + * The current render items index. + * + * @type {Number} + * @default 0 + */ this.renderItemsIndex = 0; + /** + * A list with opaque render items. + * + * @type {Array} + */ this.opaque = []; + + /** + * A list with transparent render items which require + * double pass rendering (e.g. transmissive objects). + * + * @type {Array} + */ this.transparentDoublePass = []; + + /** + * A list with transparent render items. + * + * @type {Array} + */ this.transparent = []; + + /** + * A list with transparent render bundle data. + * + * @type {Array} + */ this.bundles = []; + /** + * The render list's lights node. This node is later + * relevant for the actual analytical light nodes which + * compute the scene's lighting in the shader. + * + * @type {LightsNode} + */ this.lightsNode = lighting.getNode( scene, camera ); + + /** + * The scene's lights stored in an array. This array + * is used to setup the lights node. + * + * @type {Array} + */ this.lightsArray = []; + /** + * The scene. + * + * @type {Scene} + */ this.scene = scene; + + /** + * The camera the scene is rendered with. + * + * @type {Camera} + */ this.camera = camera; + /** + * How many objects perform occlusion query tests. + * + * @type {Number} + * @default 0 + */ this.occlusionQueryCount = 0; } + /** + * This method is called right at the beginning of a render call + * before the scene is analyzed. It prepares the internal data + * structures for the upcoming render lists generation. + * + * @return {RenderList} A reference to this render list. + */ begin() { this.renderItemsIndex = 0; @@ -18318,6 +25473,22 @@ class RenderList { } + /** + * Returns a render item for the giving render item state. The state is defined + * by a series of object-related parameters. + * + * The method avoids object creation by holding render items and reusing them in + * subsequent render calls (just with different property values). + * + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The 3D object's geometry. + * @param {Material} material - The 3D object's material. + * @param {Number} groupOrder - The current group order. + * @param {Number} z - Th 3D object's depth value (z value in clip space). + * @param {Number?} group - {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The current clipping context. + * @return {Object} The render item. + */ getNextRenderItem( object, geometry, material, groupOrder, z, group, clippingContext ) { let renderItem = this.renderItems[ this.renderItemsIndex ]; @@ -18358,6 +25529,18 @@ class RenderList { } + /** + * Pushes the given object as a render item to the internal render lists. + * The selected lists depend on the object properties. + * + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The 3D object's geometry. + * @param {Material} material - The 3D object's material. + * @param {Number} groupOrder - The current group order. + * @param {Number} z - Th 3D object's depth value (z value in clip space). + * @param {Number?} group - {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The current clipping context. + */ push( object, geometry, material, groupOrder, z, group, clippingContext ) { const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group, clippingContext ); @@ -18378,6 +25561,18 @@ class RenderList { } + /** + * Inserts the given object as a render item at the start of the internal render lists. + * The selected lists depend on the object properties. + * + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The 3D object's geometry. + * @param {Material} material - The 3D object's material. + * @param {Number} groupOrder - The current group order. + * @param {Number} z - Th 3D object's depth value (z value in clip space). + * @param {Number?} group - {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The current clipping context. + */ unshift( object, geometry, material, groupOrder, z, group, clippingContext ) { const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group, clippingContext ); @@ -18396,18 +25591,34 @@ class RenderList { } + /** + * Pushes render bundle group data into the render list. + * + * @param {Object} group - Bundle group data. + */ pushBundle( group ) { this.bundles.push( group ); } + /** + * Pushes a light into the render list. + * + * @param {Light} light - The light. + */ pushLight( light ) { this.lightsArray.push( light ); } + /** + * Sorts the internal render lists. + * + * @param {Function} customOpaqueSort - A custom sort function for opaque objects. + * @param {Function} customTransparentSort - A custom sort function for transparent objects. + */ sort( customOpaqueSort, customTransparentSort ) { if ( this.opaque.length > 1 ) this.opaque.sort( customOpaqueSort || painterSortStable ); @@ -18416,6 +25627,10 @@ class RenderList { } + /** + * This method performs finalizing tasks right after the render lists + * have been generated. + */ finish() { // update lights @@ -18446,34 +25661,71 @@ class RenderList { } +const _chainKeys$4 = []; + +/** + * This renderer module manages the render lists which are unique + * per scene and camera combination. + * + * @private + */ class RenderLists { + /** + * Constructs a render lists management component. + * + * @param {Lighting} lighting - The lighting management component. + */ constructor( lighting ) { + /** + * The lighting management component. + * + * @type {Lighting} + */ this.lighting = lighting; + /** + * The internal chain map which holds the render lists. + * + * @type {ChainMap} + */ this.lists = new ChainMap(); } + /** + * Returns a render list for the given scene and camera. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera. + * @return {RenderList} The render list. + */ get( scene, camera ) { const lists = this.lists; - const keys = [ scene, camera ]; - let list = lists.get( keys ); + _chainKeys$4[ 0 ] = scene; + _chainKeys$4[ 1 ] = camera; + + let list = lists.get( _chainKeys$4 ); if ( list === undefined ) { list = new RenderList( this.lighting, scene, camera ); - lists.set( keys, list ); + lists.set( _chainKeys$4, list ); } + _chainKeys$4.length = 0; + return list; } + /** + * Frees all internal resources. + */ dispose() { this.lists = new ChainMap(); @@ -18482,44 +25734,235 @@ class RenderLists { } -let id = 0; +let _id$7 = 0; +/** + * Any render or compute command is executed in a specific context that defines + * the state of the renderer and its backend. Typical examples for such context + * data are the current clear values or data from the active framebuffer. This + * module is used to represent these contexts as objects. + * + * @private + */ class RenderContext { + /** + * Constructs a new render context. + */ constructor() { - this.id = id ++; + /** + * The context's ID. + * + * @type {Number} + */ + this.id = _id$7 ++; + /** + * Whether the current active framebuffer has a color attachment. + * + * @type {Boolean} + * @default true + */ this.color = true; + + /** + * Whether the color attachment should be cleared or not. + * + * @type {Boolean} + * @default true + */ this.clearColor = true; + + /** + * The clear color value. + * + * @type {Object} + * @default true + */ this.clearColorValue = { r: 0, g: 0, b: 0, a: 1 }; + /** + * Whether the current active framebuffer has a depth attachment. + * + * @type {Boolean} + * @default true + */ this.depth = true; + + /** + * Whether the depth attachment should be cleared or not. + * + * @type {Boolean} + * @default true + */ this.clearDepth = true; + + /** + * The clear depth value. + * + * @type {Number} + * @default 1 + */ this.clearDepthValue = 1; + /** + * Whether the current active framebuffer has a stencil attachment. + * + * @type {Boolean} + * @default false + */ this.stencil = false; + + /** + * Whether the stencil attachment should be cleared or not. + * + * @type {Boolean} + * @default true + */ this.clearStencil = true; + + /** + * The clear stencil value. + * + * @type {Number} + * @default 1 + */ this.clearStencilValue = 1; + /** + * By default the viewport encloses the entire framebuffer If a smaller + * viewport is manually defined, this property is to `true` by the renderer. + * + * @type {Boolean} + * @default false + */ this.viewport = false; + + /** + * The viewport value. This value is in physical pixels meaning it incorporates + * the renderer's pixel ratio. The viewport property of render targets or + * the renderer is in logical pixels. + * + * @type {Vector4} + */ this.viewportValue = new Vector4(); + /** + * When the scissor test is active and scissor rectangle smaller than the + * framebuffers dimensions, this property is to `true` by the renderer. + * + * @type {Boolean} + * @default false + */ this.scissor = false; + + /** + * The scissor rectangle. + * + * @type {Vector4} + */ this.scissorValue = new Vector4(); + /** + * The active render target. + * + * @type {RenderTarget?} + * @default null + */ + this.renderTarget = null; + + /** + * The textures of the active render target. + * `null` when no render target is set. + * + * @type {Array?} + * @default null + */ this.textures = null; + + /** + * The depth texture of the active render target. + * `null` when no render target is set. + * + * @type {DepthTexture?} + * @default null + */ this.depthTexture = null; + + /** + * The active cube face. + * + * @type {Number} + * @default 0 + */ this.activeCubeFace = 0; + + /** + * The active mipmap level. + * + * @type {Number} + * @default 0 + */ + this.activeMipmapLevel = 0; + + /** + * The number of MSAA samples. This value is always `1` when + * MSAA isn't used. + * + * @type {Number} + * @default 1 + */ this.sampleCount = 1; + /** + * The active render target's width in physical pixels. + * + * @type {Number} + * @default 0 + */ this.width = 0; + + /** + * The active render target's height in physical pixels. + * + * @type {Number} + * @default 0 + */ this.height = 0; + /** + * The occlusion query count. + * + * @type {Number} + * @default 0 + */ + this.occlusionQueryCount = 0; + + /** + * The current clipping context. + * + * @type {ClippingContext?} + * @default null + */ + this.clippingContext = null; + + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isRenderContext = true; } + /** + * Returns the cache key of this render context. + * + * @return {Number} The cache key. + */ getCacheKey() { return getCacheKey( this ); @@ -18528,6 +25971,14 @@ class RenderContext { } +/** + * Computes a cache key for the given render context. This key + * should identify the render target state so it is possible to + * configure the correct attachments in the respective backend. + * + * @param {RenderContext} renderContext - The render context. + * @return {Number} The cache key. + */ function getCacheKey( renderContext ) { const { textures, activeCubeFace } = renderContext; @@ -18544,17 +25995,44 @@ function getCacheKey( renderContext ) { } +const _chainKeys$3 = []; +const _defaultScene = /*@__PURE__*/ new Scene(); +const _defaultCamera = /*@__PURE__*/ new Camera(); + +/** + * This module manages the render contexts of the renderer. + * + * @private + */ class RenderContexts { + /** + * Constructs a new render context management component. + */ constructor() { + /** + * A dictionary that manages render contexts in chain maps + * for each attachment state. + * + * @type {Object} + */ this.chainMaps = {}; } + /** + * Returns a render context for the given scene, camera and render target. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera that is used to render the scene. + * @param {RenderTarget?} [renderTarget=null] - The active render target. + * @return {RenderContext} The render context. + */ get( scene, camera, renderTarget = null ) { - const chainKey = [ scene, camera ]; + _chainKeys$3[ 0 ] = scene; + _chainKeys$3[ 1 ] = camera; let attachmentState; @@ -18571,30 +26049,54 @@ class RenderContexts { } - const chainMap = this.getChainMap( attachmentState ); + const chainMap = this._getChainMap( attachmentState ); - let renderState = chainMap.get( chainKey ); + let renderState = chainMap.get( _chainKeys$3 ); if ( renderState === undefined ) { renderState = new RenderContext(); - chainMap.set( chainKey, renderState ); + chainMap.set( _chainKeys$3, renderState ); } + _chainKeys$3.length = 0; + if ( renderTarget !== null ) renderState.sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; return renderState; } - getChainMap( attachmentState ) { + /** + * Returns a render context intended for clear operations. + * + * @param {RenderTarget?} [renderTarget=null] - The active render target. + * @return {RenderContext} The render context. + */ + getForClear( renderTarget = null ) { + + return this.get( _defaultScene, _defaultCamera, renderTarget ); + + } + + /** + * Returns a chain map for the given attachment state. + * + * @private + * @param {String} attachmentState - The attachment state. + * @return {ChainMap} The chain map. + */ + _getChainMap( attachmentState ) { return this.chainMaps[ attachmentState ] || ( this.chainMaps[ attachmentState ] = new ChainMap() ); } + /** + * Frees internal resources. + */ dispose() { this.chainMaps = {}; @@ -18605,18 +26107,55 @@ class RenderContexts { const _size$3 = /*@__PURE__*/ new Vector3(); +/** + * This module manages the textures of the renderer. + * + * @private + * @augments DataMap + */ class Textures extends DataMap { + /** + * Constructs a new texture management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Backend} backend - The renderer's backend. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( renderer, backend, info ) { super(); + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * The backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; } + /** + * Updates the given render target. Based on the given render target configuration, + * it updates the texture states representing the attachments of the framebuffer. + * + * @param {RenderTarget} renderTarget - The render target to update. + * @param {Number} [activeMipmapLevel=0] - The active mipmap level. + */ updateRenderTarget( renderTarget, activeMipmapLevel = 0 ) { const renderTargetData = this.get( renderTarget ); @@ -18738,6 +26277,14 @@ class Textures extends DataMap { } + /** + * Updates the given texture. Depending on the texture state, this method + * triggers the upload of texture data to the GPU memory. If the texture data are + * not yet ready for the upload, it uses default texture data for as a placeholder. + * + * @param {Texture} texture - The texture to update. + * @param {Object} [options={}] - The options. + */ updateTexture( texture, options = {} ) { const textureData = this.get( texture ); @@ -18891,6 +26438,18 @@ class Textures extends DataMap { } + /** + * Computes the size of the given texture and writes the result + * into the target vector. This vector is also returned by the + * method. + * + * If no texture data are available for the compute yet, the method + * returns default size values. + * + * @param {Texture} texture - The texture to compute the size for. + * @param {Vector3} target - The target vector. + * @return {Vector3} The target vector. + */ getSize( texture, target = _size$3 ) { let image = texture.images ? texture.images[ 0 ] : texture.image; @@ -18913,6 +26472,14 @@ class Textures extends DataMap { } + /** + * Computes the number of mipmap levels for the given texture. + * + * @param {Texture} texture - The texture. + * @param {Number} width - The texture's width. + * @param {Number} height - The texture's height. + * @return {Number} The number of mipmap levels. + */ getMipLevels( texture, width, height ) { let mipLevelCount; @@ -18939,12 +26506,24 @@ class Textures extends DataMap { } + /** + * Returns `true` if the given texture requires mipmaps. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether mipmaps are required or not. + */ needsMipmaps( texture ) { return this.isEnvironmentTexture( texture ) || texture.isCompressedTexture === true || texture.generateMipmaps; } + /** + * Returns `true` if the given texture is an environment map. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the given texture is an environment map or not. + */ isEnvironmentTexture( texture ) { const mapping = texture.mapping; @@ -18953,6 +26532,12 @@ class Textures extends DataMap { } + /** + * Frees internal resource when the given texture isn't + * required anymore. + * + * @param {Texture} texture - The texture to destroy. + */ _destroyTexture( texture ) { this.backend.destroySampler( texture ); @@ -18964,8 +26549,24 @@ class Textures extends DataMap { } +/** + * A four-component version of {@link Color} which is internally + * used by the renderer to represents clear color with alpha as + * one object. + * + * @private + * @augments Color + */ class Color4 extends Color { + /** + * Constructs a new four-component color. + * + * @param {Number|String} r - The red value. + * @param {Number} g - The green value. + * @param {Number} b - The blue value. + * @param {Number} [a=1] - The alpha value. + */ constructor( r, g, b, a = 1 ) { super( r, g, b ); @@ -18974,6 +26575,17 @@ class Color4 extends Color { } + /** + * Overwrites the default to honor alpha. + * You can also passed a single THREE.Color, hex or + * string argument to this method. + * + * @param {Number|String} r - The red value. + * @param {Number} g - The green value. + * @param {Number} b - The blue value. + * @param {Number} [a=1] - The alpha value. + * @return {Color4} A reference to this object. + */ set( r, g, b, a = 1 ) { this.a = a; @@ -18982,6 +26594,12 @@ class Color4 extends Color { } + /** + * Overwrites the default to honor alpha. + * + * @param {Color4} color - The color to copy. + * @return {Color4} A reference to this object. + */ copy( color ) { if ( color.a !== undefined ) this.a = color.a; @@ -18990,6 +26608,11 @@ class Color4 extends Color { } + /** + * Overwrites the default to honor alpha. + * + * @return {Color4} The cloned color. + */ clone() { return new this.constructor( this.r, this.g, this.b, this.a ); @@ -18998,6 +26621,8 @@ class Color4 extends Color { } +/** @module ParameterNode **/ + /** * Special version of {@link PropertyNode} which is used for parameters. * @@ -19047,13 +26672,17 @@ class ParameterNode extends PropertyNode { } /** + * TSL function for creating a parameter node. * - * @param {string} type - * @param {string?} [name=null] - * @returns {ShaderNodeObject} + * @function + * @param {String} type - The type of the node. + * @param {String?} name - The name of the parameter in the shader. + * @returns {ParameterNode} */ const parameter = ( type, name ) => nodeObject( new ParameterNode( type, name ) ); +/** @module StackNode **/ + /** * Stack is a helper for Nodes that need to produce stack-based code instead of continuous flow. * They are usually needed in cases like `If`, `Else`. @@ -19207,8 +26836,15 @@ class StackNode extends Node { } - // + // deprecated + /** + * @function + * @deprecated since r168. Use {@link StackNode#Else} instead. + * + * @param {...any} params + * @returns {StackNode} + */ else( ...params ) { // @deprecated, r168 console.warn( 'TSL.StackNode: .else() has been renamed to .Else().' ); @@ -19216,6 +26852,12 @@ class StackNode extends Node { } + /** + * @deprecated since r168. Use {@link StackNode#ElseIf} instead. + * + * @param {...any} params + * @returns {StackNode} + */ elseif( ...params ) { // @deprecated, r168 console.warn( 'TSL.StackNode: .elseif() has been renamed to .ElseIf().' ); @@ -19225,8 +26867,17 @@ class StackNode extends Node { } +/** + * TSL function for creating a stack node. + * + * @function + * @param {StackNode?} [parent=null] - The parent stack node. + * @returns {StackNode} + */ const stack = /*@__PURE__*/ nodeProxy( StackNode ); +/** @module OutputStructNode **/ + /** * This node can be used to define multiple outputs in a shader programs. * @@ -19306,8 +26957,17 @@ class OutputStructNode extends Node { } +/** + * TSL function for creating an output struct node. + * + * @function + * @param {...Node} members - A parameter list of nodes. + * @returns {OutputStructNode} + */ const outputStruct = /*@__PURE__*/ nodeProxy( OutputStructNode ); +/** @module MRTNode **/ + /** * Returns the MRT texture index for the given name. * @@ -19444,6 +27104,13 @@ class MRTNode extends OutputStructNode { } +/** + * TSL function for creating a MRT node. + * + * @function + * @param {Object} outputNodes - The MRT outputs. + * @returns {MRTNode} + */ const mrt = /*@__PURE__*/ nodeProxy( MRTNode ); /** @module Hash **/ @@ -19476,7 +27143,7 @@ const hash = /*@__PURE__*/ Fn( ( [ seed ] ) => { * * @method * @param {Node} x - The value to remap. - * @param {Node} k - Allows to control the remapping functions shape by rising the parabolar to a power `k`. + * @param {Node} k - Allows to control the remapping functions shape by rising the parabola to a power `k`. * @return {Node} The remapped value. */ const parabola = ( x, k ) => pow( mul( 4.0, x.mul( sub( 1.0, x ) ) ), k ); @@ -19488,7 +27155,7 @@ const parabola = ( x, k ) => pow( mul( 4.0, x.mul( sub( 1.0, x ) ) ), k ); * * @method * @param {Node} x - The value to remap. - * @param {Node} k - `k=1` is the identity curve,`k<1` produces the classic `gain()` shape, and `k>1` produces "s" shaped curces. + * @param {Node} k - `k=1` is the identity curve,`k<1` produces the classic `gain()` shape, and `k>1` produces "s" shaped curves. * @return {Node} The remapped value. */ 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 ) ); @@ -19500,8 +27167,8 @@ const gain = ( x, k ) => x.lessThan( 0.5 ) ? parabola( x.mul( 2.0 ), k ).div( 2. * * @method * @param {Node} x - The value to remap. - * @param {Node} a - First control paramter. - * @param {Node} b - Second control paramter. + * @param {Node} a - First control parameter. + * @param {Node} b - Second control parameter. * @return {Node} The remapped value. */ const pcurve = ( x, a, b ) => pow( div( pow( x, a ), add( pow( x, a ), pow( sub( 1.0, x ), b ) ) ), 1.0 / a ); @@ -19546,8 +27213,6 @@ const tri3 = /*@__PURE__*/ Fn( ( [ p ] ) => { ] } ); -/** @module Hash **/ - /** * Generates a noise value from the given position, speed and time parameters. * @@ -19590,6 +27255,8 @@ const triNoise3D = /*@__PURE__*/ Fn( ( [ position, speed, time ] ) => { ] } ); +/** @module FunctionOverloadingNode **/ + /** * This class allows to define multiple overloaded versions * of the same function. Depending on the parameters of the function @@ -19609,7 +27276,7 @@ class FunctionOverloadingNode extends Node { * Constructs a new function overloading node. * * @param {Array} functionNodes - Array of `Fn` function definitions. - * @param {...Node} parametersNodes - A list of paramater nodes. + * @param {...Node} parametersNodes - A list of parameter nodes. */ constructor( functionNodes = [], ...parametersNodes ) { @@ -19623,9 +27290,9 @@ class FunctionOverloadingNode extends Node { this.functionNodes = functionNodes; /** - * A list of paramater nodes. + * A list of parameter nodes. * - * @type {Array} + * @type {Array} */ this.parametersNodes = parametersNodes; @@ -19728,6 +27395,13 @@ class FunctionOverloadingNode extends Node { const overloadingBaseFn = /*@__PURE__*/ nodeProxy( FunctionOverloadingNode ); +/** + * TSL function for creating a function overloading node. + * + * @function + * @param {Array} functionNodes - Array of `Fn` function definitions. + * @returns {FunctionOverloadingNode} + */ const overloadingFn = ( functionNodes ) => ( ...params ) => overloadingBaseFn( functionNodes, ...params ); /** @module Timer **/ @@ -19755,6 +27429,13 @@ const frameId = /*@__PURE__*/ uniform( 0, 'uint' ).setGroup( renderGroup ).onRen // Deprecated +/** + * @function + * @deprecated since r170. Use {@link time} instead. + * + * @param {Number} [timeScale=1] - The time scale. + * @returns {UniformNode} + */ const timerLocal = ( timeScale = 1 ) => { // @deprecated, r170 console.warn( 'TSL: timerLocal() is deprecated. Use "time" instead.' ); @@ -19762,6 +27443,13 @@ const timerLocal = ( timeScale = 1 ) => { // @deprecated, r170 }; +/** + * @function + * @deprecated since r170. Use {@link time} instead. + * + * @param {Number} [timeScale=1] - The time scale. + * @returns {UniformNode} + */ const timerGlobal = ( timeScale = 1 ) => { // @deprecated, r170 console.warn( 'TSL: timerGlobal() is deprecated. Use "time" instead.' ); @@ -19769,6 +27457,13 @@ const timerGlobal = ( timeScale = 1 ) => { // @deprecated, r170 }; +/** + * @function + * @deprecated since r170. Use {@link deltaTime} instead. + * + * @param {Number} [timeScale=1] - The time scale. + * @returns {UniformNode} + */ const timerDelta = ( timeScale = 1 ) => { // @deprecated, r170 console.warn( 'TSL: timerDelta() is deprecated. Use "deltaTime" instead.' ); @@ -19915,7 +27610,7 @@ const billboarding = /*@__PURE__*/ Fn( ( { position = null, horizontal = true, v /** * A special version of a screen uv function that involves a depth comparison - * when computing the final uvs. The function mitigates visual erros when + * when computing the final uvs. The function mitigates visual errors when * using viewport texture nodes for refraction purposes. Without this function * objects in front of a refractive surface might appear on the refractive surface * which is incorrect. @@ -19934,6 +27629,8 @@ const viewportSafeUV = /*@__PURE__*/ Fn( ( [ uv = null ] ) => { } ); +/** @module SpriteSheetUVNode **/ + /** * Can be used to compute texture coordinates for animated sprite sheets. * @@ -20007,8 +27704,19 @@ class SpriteSheetUVNode extends Node { } +/** + * TSL function for creating a sprite sheet uv node. + * + * @function + * @param {Node} countNode - The node that defines the number of sprites in the x and y direction (e.g 6x6). + * @param {Node} [uvNode=uv()] - The uv node. + * @param {Node} [frameNode=float()] - The node that defines the current frame/sprite. + * @returns {SpriteSheetUVNode} + */ const spritesheetUV = /*@__PURE__*/ nodeProxy( SpriteSheetUVNode ); +/** @module TriplanarTexturesNode **/ + /** * Can be used for triplanar texture mapping. * @@ -20119,9 +27827,36 @@ class TriplanarTexturesNode extends Node { } +/** + * TSL function for creating a triplanar textures node. + * + * @function + * @param {Node} textureXNode - First texture node. + * @param {Node?} [textureYNode=null] - Second texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [textureZNode=null] - Third texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [scaleNode=float(1)] - The scale node. + * @param {Node?} [positionNode=positionLocal] - Vertex positions in local space. + * @param {Node?} [normalNode=normalLocal] - Normals in local space. + * @returns {TriplanarTexturesNode} + */ const triplanarTextures = /*@__PURE__*/ nodeProxy( TriplanarTexturesNode ); + +/** + * TSL function for creating a triplanar textures node. + * + * @function + * @param {Node} textureXNode - First texture node. + * @param {Node?} [textureYNode=null] - Second texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [textureZNode=null] - Third texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [scaleNode=float(1)] - The scale node. + * @param {Node?} [positionNode=positionLocal] - Vertex positions in local space. + * @param {Node?} [normalNode=normalLocal] - Normals in local space. + * @returns {TriplanarTexturesNode} + */ const triplanarTexture = ( ...params ) => triplanarTextures( ...params ); +/** @module ReflectorNode **/ + const _reflectorPlane = new Plane(); const _normal = new Vector3(); const _reflectorWorldPosition = new Vector3(); @@ -20154,7 +27889,7 @@ let _inReflector = false; * plane.add( groundReflector.target ); * ``` * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class ReflectorNode extends TextureNode { @@ -20173,6 +27908,8 @@ class ReflectorNode extends TextureNode { * @param {Boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not. * @param {Boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not. * @param {Boolean} [parameters.depth=false] - Whether depth data should be generated or not. + * @param {TextureNode} [parameters.defaultTexture] - The default texture node. + * @param {ReflectorBaseNode} [parameters.reflector] - The reflector base node. */ constructor( parameters = {} ) { @@ -20182,7 +27919,7 @@ class ReflectorNode extends TextureNode { * A reference to the internal reflector base node which holds the actual implementation. * * @private - * @type {Node?} + * @type {ReflectorBaseNode?} * @default null */ this._reflectorBaseNode = parameters.reflector || new ReflectorBaseNode( this, parameters ); @@ -20203,7 +27940,7 @@ class ReflectorNode extends TextureNode { /** * A reference to the internal reflector node. * - * @type {Node} + * @type {ReflectorBaseNode} */ get reflector() { @@ -20272,7 +28009,7 @@ class ReflectorNode extends TextureNode { /** * Holds the actual implementation of the reflector. * - * TOOD: Explain why `ReflectorBaseNode`. Originally the entire logic was implemented + * TODO: Explain why `ReflectorBaseNode`. Originally the entire logic was implemented * in `ReflectorNode`, see #29619. * * @private @@ -20368,7 +28105,7 @@ class ReflectorBaseNode extends Node { /** * Weak map for managing virtual cameras. * - * @type {WeakMap} + * @type {WeakMap} */ this.virtualCameras = new WeakMap(); @@ -20467,7 +28204,7 @@ class ReflectorBaseNode extends Node { updateBefore( frame ) { - if ( this.bounces === false && _inReflector ) return; + if ( this.bounces === false && _inReflector ) return false; _inReflector = true; @@ -20564,14 +28301,17 @@ class ReflectorBaseNode extends Node { const currentRenderTarget = renderer.getRenderTarget(); const currentMRT = renderer.getMRT(); + const currentAutoClear = renderer.autoClear; renderer.setMRT( null ); renderer.setRenderTarget( renderTarget ); + renderer.autoClear = true; renderer.render( scene, virtualCamera ); renderer.setMRT( currentMRT ); renderer.setRenderTarget( currentRenderTarget ); + renderer.autoClear = currentAutoClear; material.visible = true; @@ -20581,16 +28321,39 @@ class ReflectorBaseNode extends Node { } +/** + * TSL function for creating a reflector node. + * + * @function + * @param {Object} [parameters={}] - An object holding configuration parameters. + * @param {Object3D} [parameters.target=new Object3D()] - The 3D object the reflector is linked to. + * @param {Number} [parameters.resolution=1] - The resolution scale. + * @param {Boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not. + * @param {Boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not. + * @param {Boolean} [parameters.depth=false] - Whether depth data should be generated or not. + * @param {TextureNode} [parameters.defaultTexture] - The default texture node. + * @param {ReflectorBaseNode} [parameters.reflector] - The reflector base node. + * @returns {ReflectorNode} + */ 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 - +/** + * The purpose of this special geometry is to fill the entire viewport with a single triangle. + * + * Reference: {@link https://github.com/mrdoob/three.js/pull/21358} + * + * @private + * @augments BufferGeometry + */ class QuadGeometry extends BufferGeometry { + /** + * Constructs a new quad geometry. + * + * @param {Boolean} [flipY=false] - Whether the uv coordinates should be flipped along the vertical axis or not. + */ constructor( flipY = false ) { super(); @@ -20606,24 +28369,64 @@ class QuadGeometry extends BufferGeometry { const _geometry = /*@__PURE__*/ new QuadGeometry(); + +/** + * This module is a helper for passes which need to render a full + * screen effect which is quite common in context of post processing. + * + * The intended usage is to reuse a single quad mesh for rendering + * subsequent passes by just reassigning the `material` reference. + * + * @augments BufferGeometry + */ class QuadMesh extends Mesh { + /** + * Constructs a new quad mesh. + * + * @param {Material?} [material=null] - The material to render the quad mesh with. + */ constructor( material = null ) { super( _geometry, material ); + /** + * The camera to render the quad mesh with. + * + * @type {OrthographicCamera} + * @readonly + */ this.camera = _camera; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isQuadMesh = true; } - renderAsync( renderer ) { + /** + * Async version of `render()`. + * + * @async + * @param {Renderer} renderer - The renderer. + * @return {Promise} A Promise that resolves when the render has been finished. + */ + async renderAsync( renderer ) { return renderer.renderAsync( this, _camera ); } + /** + * Renders the quad mesh + * + * @param {Renderer} renderer - The renderer. + */ render( renderer ) { renderer.render( this, _camera ); @@ -20632,6 +28435,8 @@ class QuadMesh extends Mesh { } +/** @module RTTNode **/ + const _size$1 = /*@__PURE__*/ new Vector2(); /** @@ -20640,7 +28445,7 @@ const _size$1 = /*@__PURE__*/ new Vector2(); * texture input for their effects. With the helper function `convertToTexture()` which is based * on this module, the node system can automatically ensure texture input if required. * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class RTTNode extends TextureNode { @@ -20849,8 +28654,28 @@ class RTTNode extends TextureNode { } +/** + * TSL function for creating a RTT node. + * + * @function + * @param {Node} node - The node to render a texture with. + * @param {Number?} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. + * @param {Number?} [height=null] - The height of the internal render target. + * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @returns {RTTNode} + */ const rtt = ( node, ...params ) => nodeObject( new RTTNode( nodeObject( node ), ...params ) ); +/** + * TSL function for converting nodes to textures nodes. + * + * @function + * @param {Node} node - The node to render a texture with. + * @param {Number?} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. + * @param {Number?} [height=null] - The height of the internal render target. + * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @returns {RTTNode} + */ const convertToTexture = ( node, ...params ) => { if ( node.isTextureNode ) return node; @@ -20950,34 +28775,94 @@ const getNormalFromDepth = /*@__PURE__*/ Fn( ( [ uv, depthTexture, projectionMat } ); +/** + * This special type of instanced buffer attribute is intended for compute shaders. + * In earlier three.js versions it was only possible to update attribute data + * on the CPU via JavaScript and then upload the data to the GPU. With the + * new material system and renderer it is now possible to use compute shaders + * to compute the data for an attribute more efficiently on the GPU. + * + * The idea is to create an instance of this class and provide it as an input + * to {@link module:StorageBufferNode}. + * + * Note: This type of buffer attribute can only be used with `WebGPURenderer`. + * + * @augments InstancedBufferAttribute + */ class StorageInstancedBufferAttribute extends InstancedBufferAttribute { - constructor( array, itemSize, typeClass = Float32Array ) { + /** + * Constructs a new storage instanced buffer attribute. + * + * @param {Number|TypedArray} count - The item count. It is also valid to pass a typed array as an argument. + * The subsequent parameters are then obsolete. + * @param {Number} itemSize - The item size. + * @param {TypedArray.constructor} [typeClass=Float32Array] - A typed array constructor. + */ + constructor( count, itemSize, typeClass = Float32Array ) { - if ( ArrayBuffer.isView( array ) === false ) array = new typeClass( array * itemSize ); + const array = ArrayBuffer.isView( count ) ? count : new typeClass( count * itemSize ); super( array, itemSize ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageInstancedBufferAttribute = true; } } +/** + * This special type of buffer attribute is intended for compute shaders. + * In earlier three.js versions it was only possible to update attribute data + * on the CPU via JavaScript and then upload the data to the GPU. With the + * new material system and renderer it is now possible to use compute shaders + * to compute the data for an attribute more efficiently on the GPU. + * + * The idea is to create an instance of this class and provide it as an input + * to {@link module:StorageBufferNode}. + * + * Note: This type of buffer attribute can only be used with `WebGPURenderer`. + * + * @augments BufferAttribute + */ class StorageBufferAttribute extends BufferAttribute { - constructor( array, itemSize, typeClass = Float32Array ) { + /** + * Constructs a new storage buffer attribute. + * + * @param {Number|TypedArray} count - The item count. It is also valid to pass a typed array as an argument. + * The subsequent parameters are then obsolete. + * @param {Number} itemSize - The item size. + * @param {TypedArray.constructor} [typeClass=Float32Array] - A typed array constructor. + */ + constructor( count, itemSize, typeClass = Float32Array ) { - if ( ArrayBuffer.isView( array ) === false ) array = new typeClass( array * itemSize ); + const array = ArrayBuffer.isView( count ) ? count : new typeClass( count * itemSize ); super( array, itemSize ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageBufferAttribute = true; } } +/** @module StorageArrayElementNode **/ + /** * This class enables element access on instances of {@link StorageBufferNode}. * In most cases, it is indirectly used when accessing elements with the @@ -21092,8 +28977,49 @@ class StorageArrayElementNode extends ArrayElementNode { } +/** + * TSL function for creating a storage element node. + * + * @function + * @param {StorageBufferNode} storageBufferNode - The storage buffer node. + * @param {Node} indexNode - The index node that defines the element access. + * @returns {StorageArrayElementNode} + */ const storageElement = /*@__PURE__*/ nodeProxy( StorageArrayElementNode ); +/** @module StorageBufferNode **/ + +/** + * This node is used in context of compute shaders and allows to define a + * storage buffer for data. A typical workflow is to create instances of + * this node with the convenience functions `attributeArray()` or `instancedArray()`, + * setup up a compute shader that writes into the buffers and then convert + * the storage buffers to attribute nodes for rendering. + * + * ```js + * const positionBuffer = instancedArray( particleCount, 'vec3' ); // the storage buffer node + * + * const computeInit = Fn( () => { // the compute shader + * + * const position = positionBuffer.element( instanceIndex ); + * + * // compute position data + * + * position.x = 1; + * position.y = 1; + * position.z = 1; + * + * } )().compute( particleCount ); + * + * const particleMaterial = new THREE.SpriteNodeMaterial(); + * particleMaterial.positionNode = positionBuffer.toAttribute(); + * + * renderer.computeAsync( computeInit ); + * + * ``` + * + * @augments BufferNode + */ class StorageBufferNode extends BufferNode { static get type() { @@ -21102,6 +29028,13 @@ class StorageBufferNode extends BufferNode { } + /** + * Constructs a new storage buffer node. + * + * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. + * @param {String?} [bufferType=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [bufferCount=0] - The buffer count. + */ constructor( value, bufferType = null, bufferCount = 0 ) { if ( bufferType === null && ( value.isStorageBufferAttribute || value.isStorageInstancedBufferAttribute ) ) { @@ -21113,22 +29046,67 @@ class StorageBufferNode extends BufferNode { super( value, bufferType, bufferCount ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageBufferNode = true; + /** + * The access type of the texture node. + * + * @type {String} + * @default 'readWrite' + */ this.access = NodeAccess.READ_WRITE; + + /** + * Whether the node is atomic or not. + * + * @type {Boolean} + * @default false + */ this.isAtomic = false; - this.isPBO = false; - this.bufferCount = bufferCount; + /** + * Whether the node represents a PBO or not. + * Only relevant for WebGL. + * + * @type {Boolean} + * @default false + */ + this.isPBO = false; + /** + * A reference to the internal buffer attribute node. + * + * @type {BufferAttributeNode?} + * @default null + */ this._attribute = null; + + /** + * A reference to the internal varying node. + * + * @type {VaryingNode?} + * @default null + */ this._varying = null; + /** + * `StorageBufferNode` sets this property to `true` by default. + * + * @type {Boolean} + * @default true + */ 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 + // TODO: 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; @@ -21137,6 +29115,13 @@ class StorageBufferNode extends BufferNode { } + /** + * This method is overwritten since the buffer data might be shared + * and thus the hash should be shared as well. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The hash. + */ getHash( builder ) { if ( this.bufferCount === 0 ) { @@ -21161,18 +29146,36 @@ class StorageBufferNode extends BufferNode { } + /** + * Overwrites the default implementation to return a fixed value `'indirectStorageBuffer'` or `'storageBuffer'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return this.value.isIndirectStorageBufferAttribute ? 'indirectStorageBuffer' : 'storageBuffer'; } + /** + * Enables element access with the given index node. + * + * @param {IndexNode} indexNode - The index node. + * @return {StorageArrayElementNode} A node representing the element access. + */ element( indexNode ) { return storageElement( this, indexNode ); } + /** + * Defines whether this node is a PBO or not. Only relevant for WebGL. + * + * @param {Boolean} value - The value so set. + * @return {StorageBufferNode} A reference to this node. + */ setPBO( value ) { this.isPBO = value; @@ -21181,12 +29184,23 @@ class StorageBufferNode extends BufferNode { } + /** + * Returns the `isPBO` value. + * + * @return {Boolean} Whether the node represents a PBO or not. + */ getPBO() { return this.isPBO; } + /** + * Defines the node access. + * + * @param {String} value - The node access. + * @return {StorageBufferNode} A reference to this node. + */ setAccess( value ) { this.access = value; @@ -21195,12 +29209,23 @@ class StorageBufferNode extends BufferNode { } + /** + * Convenience method for configuring a read-only node access. + * + * @return {StorageBufferNode} A reference to this node. + */ toReadOnly() { return this.setAccess( NodeAccess.READ_ONLY ); } + /** + * Defines whether the node is atomic or not. + * + * @param {Boolean} value - The atomic flag. + * @return {StorageBufferNode} A reference to this node. + */ setAtomic( value ) { this.isAtomic = value; @@ -21209,12 +29234,22 @@ class StorageBufferNode extends BufferNode { } + /** + * Convenience method for making this node atomic. + * + * @return {StorageBufferNode} A reference to this node. + */ toAtomic() { return this.setAtomic( true ); } + /** + * Returns attribute data for this storage buffer node. + * + * @return {{attribute: BufferAttributeNode, varying: VaryingNode}} The attribute data. + */ getAttributeData() { if ( this._attribute === null ) { @@ -21231,6 +29266,13 @@ class StorageBufferNode extends BufferNode { } + /** + * This method is overwritten since the node type from the availability of storage buffers + * and the attribute data. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( builder.isAvailable( 'storageBuffer' ) || builder.isAvailable( 'indirectStorageBuffer' ) ) { @@ -21245,6 +29287,12 @@ class StorageBufferNode extends BufferNode { } + /** + * Generates the code snippet of the storage buffer node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( builder ) { if ( builder.isAvailable( 'storageBuffer' ) || builder.isAvailable( 'indirectStorageBuffer' ) ) { @@ -21265,8 +29313,26 @@ class StorageBufferNode extends BufferNode { } -const storage = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ) ); +/** + * TSL function for creating a storage buffer node. + * + * @function + * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [count=0] - The buffer count. + * @returns {StorageBufferNode} + */ +const storage = ( value, type = null, count = 0 ) => nodeObject( new StorageBufferNode( value, type, count ) ); +/** + * @function + * @deprecated since r171. Use `storage().setPBO( true )` instead. + * + * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. + * @param {String?} type - The buffer type (e.g. `'vec3'`). + * @param {Number} count - The buffer count. + * @returns {StorageBufferNode} + */ const storageObject = ( value, type, count ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.' ); @@ -21275,29 +29341,55 @@ const storageObject = ( value, type, count ) => { // @deprecated, r171 }; +/** @module Arrays **/ + +/** + * TSL function for creating a storage buffer node with a configured `StorageBufferAttribute`. + * + * @function + * @param {Number} count - The data count. + * @param {String} [type='float'] - The data type. + * @returns {StorageBufferNode} + */ const attributeArray = ( count, type = 'float' ) => { const itemSize = getLengthFromType( type ); + const typedArray = getTypedArrayFromType( type ); - const buffer = new StorageBufferAttribute( count, itemSize ); + const buffer = new StorageBufferAttribute( count, itemSize, typedArray ); const node = storage( buffer, type, count ); return node; }; - +/** + * TSL function for creating a storage buffer node with a configured `StorageInstancedBufferAttribute`. + * + * @function + * @param {Number} count - The data count. + * @param {String} [type='float'] - The data type. + * @returns {StorageBufferNode} + */ const instancedArray = ( count, type = 'float' ) => { const itemSize = getLengthFromType( type ); + const typedArray = getTypedArrayFromType( type ); - const buffer = new StorageInstancedBufferAttribute( count, itemSize ); + const buffer = new StorageInstancedBufferAttribute( count, itemSize, typedArray ); const node = storage( buffer, type, count ); return node; }; +/** @module VertexColorNode **/ + +/** + * An attribute node for representing vertex colors. + * + * @augments module:AttributeNode~AttributeNode + */ class VertexColorNode extends AttributeNode { static get type() { @@ -21306,16 +29398,40 @@ class VertexColorNode extends AttributeNode { } + /** + * Constructs a new vertex color node. + * + * @param {Number} [index=0] - The attribute index. + */ constructor( index = 0 ) { super( null, 'vec4' ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVertexColorNode = true; + /** + * The attribute index to enable more than one sets of vertex colors. + * + * @type {Number} + * @default 0 + */ this.index = index; } + /** + * Overwrites the default implementation by honoring the attribute index. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The attribute name. + */ getAttributeName( /*builder*/ ) { const index = this.index; @@ -21364,8 +29480,26 @@ class VertexColorNode extends AttributeNode { } -const vertexColor = ( ...params ) => nodeObject( new VertexColorNode( ...params ) ); +/** + * TSL function for creating a reference node. + * + * @function + * @param {Number} index - The attribute index. + * @returns {VertexColorNode} + */ +const vertexColor = ( index ) => nodeObject( new VertexColorNode( index ) ); +/** @module PointUVNode **/ + +/** + * A node for representing the uv coordinates of points. + * + * Can only be used with a WebGL backend. In WebGPU, point + * primitives always have the size of one pixel and can thus + * can't be used as sprite-like objects that display textures. + * + * @augments Node + */ class PointUVNode extends Node { static get type() { @@ -21374,10 +29508,20 @@ class PointUVNode extends Node { } + /** + * Constructs a new point uv node. + */ constructor() { super( 'vec2' ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isPointUVNode = true; } @@ -21390,11 +29534,28 @@ class PointUVNode extends Node { } +/** + * TSL object that represents the uv coordinates of points. + * + * @type {PointUVNode} + */ const pointUV = /*@__PURE__*/ nodeImmutable( PointUVNode ); const _e1 = /*@__PURE__*/ new Euler(); const _m1 = /*@__PURE__*/ new Matrix4(); +/** @module SceneNode **/ + +/** + * This module allows access to a collection of scene properties. The following predefined TSL objects + * are available for easier use: + * + * - `backgroundBlurriness`: A node that represents the scene's background blurriness. + * - `backgroundIntensity`: A node that represents the scene's background intensity. + * - `backgroundRotation`: A node that represents the scene's background rotation. + * + * @augments Node + */ class SceneNode extends Node { static get type() { @@ -21403,15 +29564,40 @@ class SceneNode extends Node { } + /** + * Constructs a new scene node. + * + * @param {('backgroundBlurriness'|'backgroundIntensity'|'backgroundRotation')} scope - The scope defines the type of scene property that is accessed. + * @param {Scene?} [scene=null] - A reference to the scene. + */ constructor( scope = SceneNode.BACKGROUND_BLURRINESS, scene = null ) { super(); + /** + * The scope defines the type of scene property that is accessed. + * + * @type {('backgroundBlurriness'|'backgroundIntensity'|'backgroundRotation')} + */ this.scope = scope; + + /** + * A reference to the scene that is going to be accessed. + * + * @type {Scene?} + * @default null + */ this.scene = scene; } + /** + * Depending on the scope, the method returns a different type of node that represents + * the respective scene property. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The output node. + */ setup( builder ) { const scope = this.scope; @@ -21468,10 +29654,60 @@ SceneNode.BACKGROUND_BLURRINESS = 'backgroundBlurriness'; SceneNode.BACKGROUND_INTENSITY = 'backgroundIntensity'; SceneNode.BACKGROUND_ROTATION = 'backgroundRotation'; +/** + * TSL object that represents the scene's background blurriness. + * + * @type {SceneNode} + */ const backgroundBlurriness = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_BLURRINESS ); + +/** + * TSL object that represents the scene's background intensity. + * + * @type {SceneNode} + */ const backgroundIntensity = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_INTENSITY ); + +/** + * TSL object that represents the scene's background rotation. + * + * @type {SceneNode} + */ const backgroundRotation = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_ROTATION ); +/** @module StorageTextureNode **/ + +/** + * This special version of a texture node can be used to + * write data into a storage texture with a compute shader. + * + * ```js + * const storageTexture = new THREE.StorageTexture( width, height ); + * + * const computeTexture = Fn( ( { storageTexture } ) => { + * + * const posX = instanceIndex.modInt( width ); + * const posY = instanceIndex.div( width ); + * const indexUV = uvec2( posX, posY ); + * + * // generate RGB values + * + * const r = 1; + * const g = 1; + * const b = 1; + * + * textureStore( storageTexture, indexUV, vec4( r, g, b, 1 ) ).toWriteOnly(); + * + * } ); + * + * const computeNode = computeTexture( { storageTexture } ).compute( width * height ); + * renderer.computeAsync( computeNode ); + * ``` + * + * This node can only be used with a WebGPU backend. + * + * @augments module:TextureNode~TextureNode + */ class StorageTextureNode extends TextureNode { static get type() { @@ -21480,18 +29716,50 @@ class StorageTextureNode extends TextureNode { } + /** + * Constructs a new storage texture node. + * + * @param {StorageTexture} value - The storage texture. + * @param {Node} uvNode - The uv node. + * @param {Node?} [storeNode=null] - The value node that should be stored in the texture. + */ constructor( value, uvNode, storeNode = null ) { super( value, uvNode ); + /** + * The value node that should be stored in the texture. + * + * @type {Node?} + * @default null + */ this.storeNode = storeNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageTextureNode = true; + /** + * The access type of the texture node. + * + * @type {String} + * @default 'writeOnly' + */ this.access = NodeAccess.WRITE_ONLY; } + /** + * Overwrites the default implementation to return a fixed value `'storageTexture'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'storageTexture'; @@ -21507,6 +29775,12 @@ class StorageTextureNode extends TextureNode { } + /** + * Defines the node access. + * + * @param {String} value - The node access. + * @return {StorageTextureNode} A reference to this node. + */ setAccess( value ) { this.access = value; @@ -21514,6 +29788,14 @@ class StorageTextureNode extends TextureNode { } + /** + * Generates the code snippet of the stroge node. If no `storeNode` + * is defined, the texture node is generated as normal texture. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output. + * @return {String} The generated code snippet. + */ generate( builder, output ) { let snippet; @@ -21532,24 +29814,44 @@ class StorageTextureNode extends TextureNode { } + /** + * Convenience method for configuring a read/write node access. + * + * @return {StorageTextureNode} A reference to this node. + */ toReadWrite() { return this.setAccess( NodeAccess.READ_WRITE ); } + /** + * Convenience method for configuring a read-only node access. + * + * @return {StorageTextureNode} A reference to this node. + */ toReadOnly() { return this.setAccess( NodeAccess.READ_ONLY ); } + /** + * Convenience method for configuring a write-only node access. + * + * @return {StorageTextureNode} A reference to this node. + */ toWriteOnly() { return this.setAccess( NodeAccess.WRITE_ONLY ); } + /** + * Generates the code snippet of the storage texture node. + * + * @param {NodeBuilder} builder - The current node builder. + */ generateStore( builder ) { const properties = builder.getNodeProperties( this ); @@ -21568,8 +29870,27 @@ class StorageTextureNode extends TextureNode { } +/** + * TSL function for creating a storage texture node. + * + * @function + * @param {StorageTexture} value - The storage texture. + * @param {Node} uvNode - The uv node. + * @param {Node?} [storeNode=null] - The value node that should be stored in the texture. + * @returns {StorageTextureNode} + */ const storageTexture = /*@__PURE__*/ nodeProxy( StorageTextureNode ); + +/** + * TODO: Explain difference to `storageTexture()`. + * + * @function + * @param {StorageTexture} value - The storage texture. + * @param {Node} uvNode - The uv node. + * @param {Node?} [storeNode=null] - The value node that should be stored in the texture. + * @returns {StorageTextureNode} + */ const textureStore = ( value, uvNode, storeNode ) => { const node = storageTexture( value, uvNode, storeNode ); @@ -21580,6 +29901,22 @@ const textureStore = ( value, uvNode, storeNode ) => { }; +/** @module UserDataNode **/ + +/** + * A special type of reference node that allows to link values in + * `userData` fields to node objects. + * ```js + * sprite.userData.rotation = 1; // stores individual rotation per sprite + * + * const material = new THREE.SpriteNodeMaterial(); + * material.rotationNode = userData( 'rotation', 'float' ); + * ``` + * Since `UserDataNode` is extended from {@link module:ReferenceNode~ReferenceNode}, the node value + * will automatically be updated when the `rotation` user data field changes. + * + * @augments module:ReferenceNode~ReferenceNode + */ class UserDataNode extends ReferenceNode { static get type() { @@ -21588,14 +29925,35 @@ class UserDataNode extends ReferenceNode { } + /** + * Constructs a new user data node. + * + * @param {String} property - The property name that should be referenced by the node. + * @param {String} inputType - The node data type of the reference. + * @param {Object?} [userData=null] - A reference to the `userData` object. If not provided, the `userData` property of the 3D object that uses the node material is evaluated. + */ constructor( property, inputType, userData = null ) { super( property, inputType, userData ); + /** + * A reference to the `userData` object. If not provided, the `userData` + * property of the 3D object that uses the node material is evaluated. + * + * @type {Object?} + * @default null + */ this.userData = userData; } + /** + * Overwritten to make sure {@link module:ReferenceNode~ReferenceNode#reference} points to the correct + * `userData` field. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state to evaluate. + * @return {Object} A reference to the `userData` field. + */ updateReference( state ) { this.reference = this.userData !== null ? this.userData : state.object.userData; @@ -21606,10 +29964,31 @@ class UserDataNode extends ReferenceNode { } +/** + * TSL function for creating a user data node. + * + * @function + * @param {String} name - The property name that should be referenced by the node. + * @param {String} inputType - The node data type of the reference. + * @param {Object?} userData - A reference to the `userData` object. If not provided, the `userData` property of the 3D object that uses the node material is evaluated. + * @returns {UserDataNode} + */ const userData = ( name, inputType, userData ) => nodeObject( new UserDataNode( name, inputType, userData ) ); const _objectData = new WeakMap(); +/** @module VelocityNode **/ + +/** + * A node for representing motion or velocity vectors. Foundation + * for advanced post processing effects like motion blur or TRAA. + * + * The node keeps track of the model, view and projection matrices + * of the previous frame and uses them to compute offsets in NDC space. + * These offsets represent the final velocity. + * + * @augments TempNode + */ class VelocityNode extends TempNode { static get type() { @@ -21618,27 +29997,81 @@ class VelocityNode extends TempNode { } + /** + * Constructs a new vertex color node. + * + * @param {Number} [index=0] - The attribute index. + */ constructor() { super( 'vec2' ); + /** + * The current projection matrix. + * + * @type {Matrix4?} + * @default null + */ this.projectionMatrix = null; + /** + * Overwritten since velocity nodes are updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; + + /** + * Overwritten since velocity nodes save data after the update. + * + * @type {String} + * @default 'object' + */ this.updateAfterType = NodeUpdateType.OBJECT; + /** + * Uniform node representing the previous model matrix in world space. + * + * @type {UniformNode} + * @default null + */ this.previousModelWorldMatrix = uniform( new Matrix4() ); + + /** + * Uniform node representing the previous projection matrix. + * + * @type {UniformNode} + * @default null + */ this.previousProjectionMatrix = uniform( new Matrix4() ).setGroup( renderGroup ); + + /** + * Uniform node representing the previous view matrix. + * + * @type {UniformNode} + * @default null + */ this.previousCameraViewMatrix = uniform( new Matrix4() ); } + /** + * Sets the given projection matrix. + * + * @param {Matrix4} projectionMatrix - The projection matrix to set. + */ setProjectionMatrix( projectionMatrix ) { this.projectionMatrix = projectionMatrix; } + /** + * Updates velocity specific uniforms. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( { frameId, camera, object } ) { const previousModelMatrix = getPreviousMatrix( object ); @@ -21681,12 +30114,23 @@ class VelocityNode extends TempNode { } + /** + * Overwritten to updated velocity specific uniforms. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ updateAfter( { object } ) { getPreviousMatrix( object ).copy( object.matrixWorld ); } + /** + * Implements the velocity computation based on the previous and current vertex data. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {Node} The motion vector. + */ setup( /*builder*/ ) { const projectionMatrix = ( this.projectionMatrix === null ) ? cameraProjectionMatrix : uniform( this.projectionMatrix ); @@ -21738,6 +30182,11 @@ function getPreviousMatrix( object, index = 0 ) { } +/** + * TSL object that represents the velocity of a render pass. + * + * @type {VelocityNode} + */ const velocity = /*@__PURE__*/ nodeImmutable( VelocityNode ); const blendBurn = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { @@ -21809,6 +30258,13 @@ const blendColor = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { // deprecated +/** + * @function + * @deprecated since r171. Use {@link blendBurn} instead. + * + * @param {...any} params + * @returns {Function} + */ const burn = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "burn" has been renamed. Use "blendBurn" instead.' ); @@ -21816,6 +30272,13 @@ const burn = ( ...params ) => { // @deprecated, r171 }; +/** + * @function + * @deprecated since r171. Use {@link blendDodge} instead. + * + * @param {...any} params + * @returns {Function} + */ const dodge = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "dodge" has been renamed. Use "blendDodge" instead.' ); @@ -21823,6 +30286,13 @@ const dodge = ( ...params ) => { // @deprecated, r171 }; +/** + * @function + * @deprecated since r171. Use {@link blendScreen} instead. + * + * @param {...any} params + * @returns {Function} + */ const screen = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "screen" has been renamed. Use "blendScreen" instead.' ); @@ -21830,6 +30300,13 @@ const screen = ( ...params ) => { // @deprecated, r171 }; +/** + * @function + * @deprecated since r171. Use {@link blendOverlay} instead. + * + * @param {...any} params + * @returns {Function} + */ const overlay = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "overlay" has been renamed. Use "blendOverlay" instead.' ); @@ -21968,6 +30445,8 @@ const cdl = /*@__PURE__*/ Fn( ( [ } ); +/** @module PosterizeNode **/ + /** * Represents a posterize effect which reduces the number of colors * in an image, resulting in a more blocky and stylized appearance. @@ -22018,15 +30497,24 @@ class PosterizeNode extends TempNode { } +/** + * TSL function for creating a posterize node. + * + * @function + * @param {Node} sourceNode - The input color. + * @param {Node} stepsNode - Controls the intensity of the posterization effect. A lower number results in a more blocky appearance. + * @returns {PosterizeNode} + */ const posterize = /*@__PURE__*/ nodeProxy( PosterizeNode ); +/** @module PassNode **/ + const _size = /*@__PURE__*/ new Vector2(); /** * Represents the texture of a pass node. * - * @augments TextureNode - * @private + * @augments module:TextureNode~TextureNode */ class PassTextureNode extends TextureNode { @@ -22077,8 +30565,7 @@ class PassTextureNode extends TextureNode { * An extension of `PassTextureNode` which allows to manage more than one * internal texture. Relevant for the `getPreviousTexture()` related API. * - * @augments PassTextureNode - * @private + * @augments module:PassTextureNode~PassTextureNode */ class PassMultipleTextureNode extends PassTextureNode { @@ -22196,7 +30683,7 @@ class PassNode extends TempNode { /** * A reference to the camera. * - * @type {camera} + * @type {Camera} */ this.camera = camera; @@ -22252,7 +30739,7 @@ class PassNode extends TempNode { * A dictionary holding the internal result textures. * * @private - * @type {Object} + * @type {Object} */ this._textures = { output: renderTarget.texture, @@ -22263,7 +30750,7 @@ class PassNode extends TempNode { * A dictionary holding the internal texture nodes. * * @private - * @type {Object} + * @type {Object} */ this._textureNodes = {}; @@ -22288,7 +30775,7 @@ class PassNode extends TempNode { * Used for computing velocity/motion vectors. * * @private - * @type {Object} + * @type {Object} */ this._previousTextures = {}; @@ -22297,7 +30784,7 @@ class PassNode extends TempNode { * Used for computing velocity/motion vectors. * * @private - * @type {Object} + * @type {Object} */ this._previousTextureNodes = {}; @@ -22646,9 +31133,39 @@ class PassNode extends TempNode { PassNode.COLOR = 'color'; PassNode.DEPTH = 'depth'; +/** + * TSL function for creating a pass node. + * + * @function + * @param {Scene} scene - A reference to the scene. + * @param {Camera} camera - A reference to the camera. + * @param {Object} options - Options for the internal render target. + * @returns {PassNode} + */ const pass = ( scene, camera, options ) => nodeObject( new PassNode( PassNode.COLOR, scene, camera, options ) ); + +/** + * TSL function for creating a pass texture node. + * + * @function + * @param {PassNode} pass - The pass node. + * @param {Texture} texture - The output texture. + * @returns {PassTextureNode} + */ const passTexture = ( pass, texture ) => nodeObject( new PassTextureNode( pass, texture ) ); -const depthPass = ( scene, camera ) => nodeObject( new PassNode( PassNode.DEPTH, scene, camera ) ); + +/** + * TSL function for creating a depth pass node. + * + * @function + * @param {Scene} scene - A reference to the scene. + * @param {Camera} camera - A reference to the camera. + * @param {Object} options - Options for the internal render target. + * @returns {PassNode} + */ +const depthPass = ( scene, camera, options ) => nodeObject( new PassNode( PassNode.DEPTH, scene, camera, options ) ); + +/** @module ToonOutlinePassNode **/ /** * Represents a render pass for producing a toon outline effect on compatible objects. @@ -22783,7 +31300,7 @@ class ToonOutlinePassNode extends PassNode { } /** - * For the given toon material, this method returns a correspoding + * For the given toon material, this method returns a corresponding * outline material. * * @private @@ -22808,6 +31325,17 @@ class ToonOutlinePassNode extends PassNode { } +/** + * TSL function for creating a toon outline pass node. + * + * @function + * @param {Scene} scene - A reference to the scene. + * @param {Camera} camera - A reference to the camera. + * @param {Color} color - Defines the outline's color. + * @param {Number} [thickness=0.003] - Defines the outline's thickness. + * @param {Number} [alpha=1] - Defines the outline's alpha. + * @returns {ToonOutlinePassNode} + */ 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 ) ) ); /** @module ToneMappingFunctions **/ @@ -23044,6 +31572,8 @@ const neutralToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { ] } ); +/** @module CodeNode **/ + /** * This class represents native code sections. It is the base * class for modules like {@link FunctionNode} which allows to implement @@ -23179,10 +31709,45 @@ class CodeNode extends Node { } +/** + * TSL function for creating a code node. + * + * @function + * @param {String} [code=''] - The native code. + * @param {Array} [includes=[]] - An array of includes. + * @param {('js'|'wgsl'|'glsl')} [language=''] - The used language. + * @returns {CodeNode} + */ const code = /*@__PURE__*/ nodeProxy( CodeNode ); +/** + * TSL function for creating a JS code node. + * + * @function + * @param {String} src - The native code. + * @param {Array} includes - An array of includes. + * @returns {CodeNode} + */ const js = ( src, includes ) => code( src, includes, 'js' ); + +/** + * TSL function for creating a WGSL code node. + * + * @function + * @param {String} src - The native code. + * @param {Array} includes - An array of includes. + * @returns {CodeNode} + */ const wgsl = ( src, includes ) => code( src, includes, 'wgsl' ); + +/** + * TSL function for creating a GLSL code node. + * + * @function + * @param {String} src - The native code. + * @param {Array} includes - An array of includes. + * @returns {CodeNode} + */ const glsl = ( src, includes ) => code( src, includes, 'glsl' ); /** @@ -23341,6 +31906,13 @@ const nativeFn = ( code, includes = [], language = '' ) => { const glslFn = ( code, includes ) => nativeFn( code, includes, 'glsl' ); const wgslFn = ( code, includes ) => nativeFn( code, includes, 'wgsl' ); +/** @module ScriptableValueNode **/ + +/** + * `ScriptableNode` uses this class to manage script inputs and outputs. + * + * @augments Node + */ class ScriptableValueNode extends Node { static get type() { @@ -23349,22 +31921,72 @@ class ScriptableValueNode extends Node { } + /** + * Constructs a new scriptable node. + * + * @param {Any} [value=null] - The value. + */ constructor( value = null ) { super(); + /** + * A reference to the value. + * + * @private + * @default null + */ this._value = value; + + /** + * Depending on the type of `_value`, this property might cache parsed data. + * + * @private + * @default null + */ this._cache = null; + /** + * If this node represents an input, this property represents the input type. + * + * @type {String?} + * @default null + */ this.inputType = null; + + /** + * If this node represents an output, this property represents the output type. + * + * @type {String?} + * @default null + */ this.outputType = null; + /** + * An event dispatcher for managing events. + * + * @type {EventDispatcher} + */ this.events = new EventDispatcher(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isScriptableValueNode = true; } + /** + * Whether this node represents an output or not. + * + * @type {Boolean} + * @readonly + * @default true + */ get isScriptableOutputNode() { return this.outputType !== null; @@ -23391,18 +32013,32 @@ class ScriptableValueNode extends Node { } + /** + * The node's value. + * + * @type {Any} + */ get value() { return this._value; } + /** + * Dispatches the `refresh` event. + */ refresh() { this.events.dispatchEvent( { type: 'refresh' } ); } + /** + * The `value` property usually represents a node or even binary data in form of array buffers. + * In this case, this method tries to return the actual value behind the complex type. + * + * @return {Any} The value. + */ getValue() { const value = this.value; @@ -23430,6 +32066,12 @@ class ScriptableValueNode extends Node { } + /** + * Overwritten since the node type is inferred from the value. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { return this.value && this.value.isNode ? this.value.getNodeType( builder ) : 'float'; @@ -23502,8 +32144,22 @@ class ScriptableValueNode extends Node { } +/** + * TSL function for creating a scriptable value node. + * + * @function + * @param {Any} [value=null] - The value. + * @returns {ScriptableValueNode} + */ const scriptableValue = /*@__PURE__*/ nodeProxy( ScriptableValueNode ); +/** @module ScriptableNode **/ + +/** + * A Map-like data structure for managing resources of scriptable nodes. + * + * @augments Map + */ class Resources extends Map { get( key, callback = null, ...params ) { @@ -23559,8 +32215,49 @@ class Parameters { } +/** + * Defines the resources (e.g. namespaces) of scriptable nodes. + * + * @type {Resources} + */ const ScriptableNodeResources = new Resources(); +/** + * This type of node allows to implement nodes with custom scripts. The script + * section is represented as an instance of `CodeNode` written with JavaScript. + * The script itself must adhere to a specific structure. + * + * - main(): Executed once by default and every time `node.needsUpdate` is set. + * - layout: The layout object defines the script's interface (inputs and outputs). + * + * ```js + * ScriptableNodeResources.set( 'TSL', TSL ); + * + * const scriptableNode = scriptable( js( ` + * layout = { + * outputType: 'node', + * elements: [ + * { name: 'source', inputType: 'node' }, + * ] + * }; + * + * const { mul, oscSine } = TSL; + * + * function main() { + * const source = parameters.get( 'source' ) || float(); + * return mul( source, oscSine() ) ); + * } + * + * ` ) ); + * + * scriptableNode.setParameter( 'source', color( 1, 0, 0 ) ); + * + * const material = new THREE.MeshBasicNodeMaterial(); + * material.colorNode = scriptableNode; + * ``` + * + * @augments Node + */ class ScriptableNode extends Node { static get type() { @@ -23569,11 +32266,30 @@ class ScriptableNode extends Node { } + /** + * Constructs a new scriptable node. + * + * @param {CodeNode?} [codeNode=null] - The code node. + * @param {Object} [parameters={}] - The parameters definition. + */ constructor( codeNode = null, parameters = {} ) { super(); + /** + * The code node. + * + * @type {CodeNode?} + * @default null + */ this.codeNode = codeNode; + + /** + * The parameters definition. + * + * @type {Object} + * @default {} + */ this.parameters = parameters; this._local = new Resources(); @@ -23587,34 +32303,68 @@ class ScriptableNode extends Node { this.onRefresh = this.onRefresh.bind( this ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isScriptableNode = true; } + /** + * The source code of the scriptable node. + * + * @type {String} + */ get source() { return this.codeNode ? this.codeNode.code : ''; } + /** + * Sets the reference of a local script variable. + * + * @param {String} name - The variable name. + * @param {Object} value - The reference to set. + * @return {Resources} The resource map + */ setLocal( name, value ) { return this._local.set( name, value ); } + /** + * Gets the value of a local script variable. + * + * @param {String} name - The variable name. + * @return {Object} The value. + */ getLocal( name ) { return this._local.get( name ); } + /** + * Event listener for the `refresh` event. + */ onRefresh() { this._refresh(); } + /** + * Returns an input from the layout with the given id/name. + * + * @param {String} id - The id/name of the input. + * @return {Object} The element entry. + */ getInputLayout( id ) { for ( const element of this.getLayout() ) { @@ -23629,6 +32379,12 @@ class ScriptableNode extends Node { } + /** + * Returns an output from the layout with the given id/name. + * + * @param {String} id - The id/name of the output. + * @return {Object} The element entry. + */ getOutputLayout( id ) { for ( const element of this.getLayout() ) { @@ -23643,6 +32399,13 @@ class ScriptableNode extends Node { } + /** + * Defines a script output for the given name and value. + * + * @param {String} name - The name of the output. + * @param {Node} value - The node value. + * @return {ScriptableNode} A reference to this node. + */ setOutput( name, value ) { const outputs = this._outputs; @@ -23661,18 +32424,37 @@ class ScriptableNode extends Node { } + /** + * Returns a script output for the given name. + * + * @param {String} name - The name of the output. + * @return {ScriptableValueNode} The node value. + */ getOutput( name ) { return this._outputs[ name ]; } + /** + * Returns a parameter for the given name + * + * @param {String} name - The name of the parameter. + * @return {ScriptableValueNode} The node value. + */ getParameter( name ) { return this.parameters[ name ]; } + /** + * Sets a value for the given parameter name. + * + * @param {String} name - The parameter name. + * @param {Any} value - The parameter value. + * @return {ScriptableNode} A reference to this node. + */ setParameter( name, value ) { const parameters = this.parameters; @@ -23706,12 +32488,24 @@ class ScriptableNode extends Node { } + /** + * Returns the value of this node which is the value of + * the default output. + * + * @return {Node} The value. + */ getValue() { return this.getDefaultOutput().getValue(); } + /** + * Deletes a parameter from the script. + * + * @param {String} name - The parameter to remove. + * @return {ScriptableNode} A reference to this node. + */ deleteParameter( name ) { let valueNode = this.parameters[ name ]; @@ -23728,6 +32522,11 @@ class ScriptableNode extends Node { } + /** + * Deletes all parameters from the script. + * + * @return {ScriptableNode} A reference to this node. + */ clearParameters() { for ( const name of Object.keys( this.parameters ) ) { @@ -23742,6 +32541,13 @@ class ScriptableNode extends Node { } + /** + * Calls a function from the script. + * + * @param {String} name - The function name. + * @param {...Any} params - A list of parameters. + * @return {Any} The result of the function call. + */ call( name, ...params ) { const object = this.getObject(); @@ -23755,6 +32561,13 @@ class ScriptableNode extends Node { } + /** + * Asynchronously calls a function from the script. + * + * @param {String} name - The function name. + * @param {...Any} params - A list of parameters. + * @return {Promise} The result of the function call. + */ async callAsync( name, ...params ) { const object = this.getObject(); @@ -23768,12 +32581,23 @@ class ScriptableNode extends Node { } + /** + * Overwritten since the node types is inferred from the script's output. + * + * @param {NodeBuilder} builder - The current node builder + * @return {String} The node type. + */ getNodeType( builder ) { return this.getDefaultOutputNode().getNodeType( builder ); } + /** + * Refreshes the script node. + * + * @param {String?} [output=null] - An optional output. + */ refresh( output = null ) { if ( output !== null ) { @@ -23788,6 +32612,11 @@ class ScriptableNode extends Node { } + /** + * Returns an object representation of the script. + * + * @return {Object} The result object. + */ getObject() { if ( this.needsUpdate ) this.dispose(); @@ -23803,7 +32632,7 @@ class ScriptableNode extends Node { const THREE = ScriptableNodeResources.get( 'THREE' ); const TSL = ScriptableNodeResources.get( 'TSL' ); - const method = this.getMethod( this.codeNode ); + const method = this.getMethod(); const params = [ parameters, this._local, ScriptableNodeResources, refresh, setOutput, THREE, TSL ]; this._object = method( ...params ); @@ -23869,12 +32698,22 @@ class ScriptableNode extends Node { } + /** + * Returns the layout of the script. + * + * @return {Object} The script's layout. + */ getLayout() { return this.getObject().layout; } + /** + * Returns default node output of the script. + * + * @return {Node} The default node output. + */ getDefaultOutputNode() { const output = this.getDefaultOutput().value; @@ -23889,12 +32728,22 @@ class ScriptableNode extends Node { } + /** + * Returns default output of the script. + * + * @return {ScriptableValueNode} The default output. + */ getDefaultOutput() { return this._exec()._output; } + /** + * Returns a function created from the node's script. + * + * @return {Function} The function representing the node's code. + */ getMethod() { if ( this.needsUpdate ) this.dispose(); @@ -23919,6 +32768,9 @@ class ScriptableNode extends Node { } + /** + * Frees all internal resources. + */ dispose() { if ( this._method === null ) return; @@ -23971,6 +32823,12 @@ class ScriptableNode extends Node { } + /** + * Executes the `main` function of the script. + * + * @private + * @return {ScriptableNode} A reference to this node. + */ _exec() { if ( this.codeNode === null ) return this; @@ -23989,6 +32847,11 @@ class ScriptableNode extends Node { } + /** + * Executes the refresh. + * + * @private + */ _refresh() { this.needsUpdate = true; @@ -24001,211 +32864,124 @@ class ScriptableNode extends Node { } -const scriptable = /*@__PURE__*/ nodeProxy( ScriptableNode ); - /** - * This class can be used to configure a fog for the scene. - * Nodes of this type are assigned to `Scene.fogNode`. + * TSL function for creating a scriptable node. * - * @augments Node + * @function + * @param {CodeNode?} [codeNode=null] - The code node. + * @param {Object} [parameters={}] - The parameters definition. + * @returns {ScriptableNode} */ -class FogNode extends Node { - - static get type() { - - return 'FogNode'; - - } - - /** - * Constructs a new fog node. - * - * @param {Node} colorNode - Defines the color of the fog. - * @param {Node} factorNode - Defines how the fog is factored in the scene. - */ - constructor( colorNode, factorNode ) { - - super( 'float' ); - - /** - * This flag can be used for type testing. - * - * @type {Boolean} - * @readonly - * @default true - */ - this.isFogNode = true; - - /** - * Defines the color of the fog. - * - * @type {Node?} - */ - this.colorNode = colorNode; - - /** - * Defines how the fog is factored in the scene. - * - * @type {Node?} - */ - this.factorNode = factorNode; - - } - - /** - * Returns a node that represents the `z` coordinate in view space - * for the current fragment. It's a different representation of the - * default depth value. - * - * This value can be part of a computation that defines how the fog - * density increases when moving away from the camera. - * - * @param {NodeBuilder} builder - The current node builder. - * @return {Node} The viewZ node. - */ - getViewZNode( builder ) { +const scriptable = /*@__PURE__*/ nodeProxy( ScriptableNode ); - let viewZ; +/** @module Fog **/ - const getViewZ = builder.context.getViewZ; +/** + * Returns a node that represents the `z` coordinate in view space + * for the current fragment. It's a different representation of the + * default depth value. + * + * This value can be part of a computation that defines how the fog + * density increases when moving away from the camera. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The viewZ node. + */ +function getViewZNode( builder ) { - if ( getViewZ !== undefined ) { + let viewZ; - viewZ = getViewZ( this ); + const getViewZ = builder.context.getViewZ; - } + if ( getViewZ !== undefined ) { - return ( viewZ || positionView.z ).negate(); + viewZ = getViewZ( this ); } - setup() { - - return this.factorNode; - - } + return ( viewZ || positionView.z ).negate(); } -const fog = /*@__PURE__*/ nodeProxy( FogNode ); - /** - * Represents a range fog. The fog is smoothly interpolated - * between a range defined via near and far values. + * Constructs a new range factor node. * - * @augments FogNode + * @function + * @param {Node} near - Defines the near value. + * @param {Node} far - Defines the far value. */ -class FogRangeNode extends FogNode { - - static get type() { - - return 'FogRangeNode'; - - } - - /** - * Constructs a new range node. - * - * @param {Node} colorNode - Defines the color of the fog. - * @param {Node} nearNode - Defines the near value. - * @param {Node} farNode - Defines the far value. - */ - constructor( colorNode, nearNode, farNode ) { +const rangeFogFactor = Fn( ( [ near, far ], builder ) => { - super( colorNode, null ); + const viewZ = getViewZNode( builder ); - /** - * This flag can be used for type testing. - * - * @type {Boolean} - * @readonly - * @default true - */ - this.isFogRangeNode = true; - - /** - * Defines the near value. - * - * @type {Node} - */ - this.nearNode = nearNode; + return smoothstep( near, far, viewZ ); - /** - * Defines the far value. - * - * @type {Node} - */ - this.farNode = farNode; - - } - - setup( builder ) { - - const viewZ = this.getViewZNode( builder ); - - return smoothstep( this.nearNode, this.farNode, viewZ ); - - } - -} - -const rangeFog = /*@__PURE__*/ nodeProxy( FogRangeNode ); +} ); /** * Represents an exponential squared fog. This type of fog gives * a clear view near the camera and a faster than exponentially * densening fog farther from the camera. * - * @augments FogNode + * @function + * @param {Node} density - Defines the fog density. */ -class FogExp2Node extends FogNode { +const densityFogFactor = Fn( ( [ density ], builder ) => { - static get type() { + const viewZ = getViewZNode( builder ); - return 'FogExp2Node'; + return density.mul( density, viewZ, viewZ ).negate().exp().oneMinus(); - } +} ); - /** - * Constructs a new exponential squared fog node. - * - * @param {Node} colorNode - Defines the color of the fog. - * @param {Node} densityNode - Defines the fog density. - */ - constructor( colorNode, densityNode ) { +/** + * This class can be used to configure a fog for the scene. + * Nodes of this type are assigned to `Scene.fogNode`. + * + * @function + * @param {Node} color - Defines the color of the fog. + * @param {Node} factor - Defines how the fog is factored in the scene. + */ +const fog = Fn( ( [ color, factor ] ) => { - super( colorNode, null ); + return vec4( factor.toFloat().mix( output.rgb, color.toVec3() ), output.a ); - /** - * This flag can be used for type testing. - * - * @type {Boolean} - * @readonly - * @default true - */ - this.isFogExp2Node = true; +} ); - /** - * Defines the fog density. - * - * @type {Node} - */ - this.densityNode = densityNode; +// Deprecated - } +/** + * @function + * @deprecated since r171. Use `fog( color, rangeFogFactor( near, far ) )` instead. + * + * @param {Node} color + * @param {Node} near + * @param {Node} far + * @returns {Function} + */ +function rangeFog( color, near, far ) { // @deprecated, r171 - setup( builder ) { + console.warn( 'THREE.TSL: "rangeFog( color, near, far )" is deprecated. Use "fog( color, rangeFogFactor( near, far ) )" instead.' ); + return fog( color, rangeFogFactor( near, far ) ); - const viewZ = this.getViewZNode( builder ); - const density = this.densityNode; +} - return density.mul( density, viewZ, viewZ ).negate().exp().oneMinus(); +/** + * @function + * @deprecated since r171. Use `fog( color, densityFogFactor( density ) )` instead. + * + * @param {Node} color + * @param {Node} density + * @returns {Function} + */ +function densityFog( color, density ) { // @deprecated, r171 - } + console.warn( 'THREE.TSL: "densityFog( color, density )" is deprecated. Use "fog( color, densityFogFactor( density ) )" instead.' ); + return fog( color, densityFogFactor( density ) ); } -const densityFog = /*@__PURE__*/ nodeProxy( FogExp2Node ); +/** @module RangeNode **/ let min = null; let max = null; @@ -24356,8 +33132,26 @@ class RangeNode extends Node { } +/** + * TSL function for creating a range node. + * + * @function + * @param {Node} [minNode=float()] - A node defining the lower bound of the range. + * @param {Node} [maxNode=float()] - A node defining the upper bound of the range. + * @returns {RangeNode} + */ const range = /*@__PURE__*/ nodeProxy( RangeNode ); +/** @module ComputeBuiltinNode **/ + +/** + * `ComputeBuiltinNode` represents a compute-scope builtin value that expose information + * about the currently running dispatch and/or the device it is running on. + * + * This node can only be used with a WebGPU backend. + * + * @augments Node + */ class ComputeBuiltinNode extends Node { static get type() { @@ -24366,26 +33160,56 @@ class ComputeBuiltinNode extends Node { } + /** + * Constructs a new compute builtin node. + * + * @param {String} builtinName - The built-in name. + * @param {String} nodeType - The node type. + */ constructor( builtinName, nodeType ) { super( nodeType ); + /** + * The built-in name. + * + * @private + * @type {String} + */ this._builtinName = builtinName; } + /** + * This method is overwritten since hash is derived from the built-in name. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The hash. + */ getHash( builder ) { return this.getBuiltinName( builder ); } + /** + * This method is overwritten since the node type is simply derived from `nodeType`.. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( /*builder*/ ) { return this.nodeType; } + /** + * Sets the builtin name. + * + * @param {String} builtinName - The built-in name. + * @return {ComputeBuiltinNode} A reference to this node. + */ setBuiltinName( builtinName ) { this._builtinName = builtinName; @@ -24394,12 +33218,23 @@ class ComputeBuiltinNode extends Node { } + /** + * Returns the builtin name. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The builtin name. + */ getBuiltinName( /*builder*/ ) { return this._builtinName; } + /** + * Whether the current node builder has the builtin or not. + * + * @param {NodeBuilder} builder - The current node builder. + */ hasBuiltin( builder ) { builder.hasBuiltin( this._builtinName ); @@ -24444,15 +33279,112 @@ class ComputeBuiltinNode extends Node { } +/** + * TSL function for creating a compute builtin node. + * + * @function + * @param {String} name - The built-in name. + * @param {String} nodeType - The node type. + * @returns {ComputeBuiltinNode} + */ const computeBuiltin = ( name, nodeType ) => nodeObject( new ComputeBuiltinNode( name, nodeType ) ); +/** + * TSL function for creating a `numWorkgroups` builtin node. + * Represents the number of workgroups dispatched by the compute shader. + * ```js + * // Run 512 invocations/threads with a workgroup size of 128. + * const computeFn = Fn(() => { + * + * // numWorkgroups.x = 4 + * storageBuffer.element(0).assign(numWorkgroups.x) + * + * })().compute(512, [128]); + * + * // Run 512 invocations/threads with the default workgroup size of 64. + * const computeFn = Fn(() => { + * + * // numWorkgroups.x = 8 + * storageBuffer.element(0).assign(numWorkgroups.x) + * + * })().compute(512); + * ``` + * + * @function + * @returns {ComputeBuiltinNode} + */ const numWorkgroups = /*@__PURE__*/ computeBuiltin( 'numWorkgroups', 'uvec3' ); + +/** + * TSL function for creating a `workgroupId` builtin node. + * Represents the 3-dimensional index of the workgroup the current compute invocation belongs to. + * ```js + * // Execute 12 compute threads with a workgroup size of 3. + * const computeFn = Fn( () => { + * + * If( workgroupId.x.modInt( 2 ).equal( 0 ), () => { + * + * storageBuffer.element( instanceIndex ).assign( instanceIndex ); + * + * } ).Else( () => { + * + * storageBuffer.element( instanceIndex ).assign( 0 ); + * + * } ); + * + * } )().compute( 12, [ 3 ] ); + * + * // workgroupId.x = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]; + * // Buffer Output = [0, 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0]; + * ``` + * + * @function + * @returns {ComputeBuiltinNode} + */ const workgroupId = /*@__PURE__*/ computeBuiltin( 'workgroupId', 'uvec3' ); + +/** + * TSL function for creating a `globalId` builtin node. A non-linearized 3-dimensional + * representation of the current invocation's position within a 3D global grid. + * + * @function + * @returns {ComputeBuiltinNode} + */ +const globalId = /*@__PURE__*/ computeBuiltin( 'globalId', 'uvec3' ); +/** + * TSL function for creating a `localId` builtin node. A non-linearized 3-dimensional + * representation of the current invocation's position within a 3D workgroup grid. + * + * @function + * @returns {ComputeBuiltinNode} + */ const localId = /*@__PURE__*/ computeBuiltin( 'localId', 'uvec3' ); + +/** + * TSL function for creating a `subgroupSize` builtin node. A device dependent variable + * that exposes the size of the current invocation's subgroup. + * + * @function + * @returns {ComputeBuiltinNode} + */ const subgroupSize = /*@__PURE__*/ computeBuiltin( 'subgroupSize', 'uint' ); +/** @module BarrierNode **/ + +/** + * Represents a GPU control barrier that synchronizes compute operations within a given scope. + * + * This node can only be used with a WebGPU backend. + * + * @augments Node + */ class BarrierNode extends Node { + /** + * Constructs a new barrier node. + * + * @param {String} scope - The scope defines the behavior of the node. + */ constructor( scope ) { super(); @@ -24480,18 +33412,71 @@ class BarrierNode extends Node { } +/** + * TSL function for creating a barrier node. + * + * @function + * @param {String} scope - The scope defines the behavior of the node.. + * @returns {BarrierNode} + */ const barrier = nodeProxy( BarrierNode ); +/** + * TSL function for creating a workgroup barrier. All compute shader + * invocations must wait for each invocation within a workgroup to + * complete before the barrier can be surpassed. + * + * @function + * @returns {BarrierNode} + */ const workgroupBarrier = () => barrier( 'workgroup' ).append(); + +/** + * TSL function for creating a storage barrier. All invocations must + * wait for each access to variables within the 'storage' address space + * to complete before the barrier can be passed. + * + * @function + * @returns {BarrierNode} + */ const storageBarrier = () => barrier( 'storage' ).append(); + +/** + * TSL function for creating a texture barrier. All invocations must + * wait for each access to variables within the 'texture' address space + * to complete before the barrier can be passed. + * + * @function + * @returns {BarrierNode} + */ const textureBarrier = () => barrier( 'texture' ).append(); +/** @module WorkgroupInfoNode **/ + +/** + * Represents an element of a 'workgroup' scoped buffer. + * + * @augments ArrayElementNode + */ class WorkgroupInfoElementNode extends ArrayElementNode { + /** + * Constructs a new workgroup info element node. + * + * @param {Node} workgroupInfoNode - The workgroup info node. + * @param {Node} indexNode - The index node that defines the element access. + */ constructor( workgroupInfoNode, indexNode ) { super( workgroupInfoNode, indexNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWorkgroupInfoElementNode = true; } @@ -24519,22 +33504,77 @@ class WorkgroupInfoElementNode extends ArrayElementNode { } - +/** + * A node allowing the user to create a 'workgroup' scoped buffer within the + * context of a compute shader. Typically, workgroup scoped buffers are + * created to hold data that is transferred from a global storage scope into + * a local workgroup scope. For invocations within a workgroup, data + * access speeds on 'workgroup' scoped buffers can be significantly faster + * than similar access operations on globally accessible storage buffers. + * + * This node can only be used with a WebGPU backend. + * + * @augments Node + */ class WorkgroupInfoNode extends Node { + /** + * Constructs a new buffer scoped to type scope. + * + * @param {String} scope - TODO. + * @param {String} bufferType - The data type of a 'workgroup' scoped buffer element. + * @param {Number} [bufferCount=0] - The number of elements in the buffer. + */ constructor( scope, bufferType, bufferCount = 0 ) { super( bufferType ); + /** + * The buffer type. + * + * @type {String} + */ this.bufferType = bufferType; + + /** + * The buffer count. + * + * @type {Number} + * @default 0 + */ this.bufferCount = bufferCount; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWorkgroupInfoNode = true; + /** + * The data type of the array buffer. + * + * @type {String} + */ + this.elementType = bufferType; + + /** + * TODO. + * + * @type {String} + */ this.scope = scope; } + /** + * Sets the name/label of this node. + * + * @param {String} name - The name to set. + * @return {WorkgroupInfoNode} A reference to this node. + */ label( name ) { this.name = name; @@ -24543,26 +33583,51 @@ class WorkgroupInfoNode extends Node { } - getHash() { + /** + * Sets the scope of this node. + * + * @param {String} scope - The scope to set. + * @return {WorkgroupInfoNode} A reference to this node. + */ + setScope( scope ) { - return this.uuid; + this.scope = scope; + + return this; } - setScope( scope ) { - this.scope = scope; + /** + * The data type of the array buffer. + * + * @return {String} The element type. + */ + getElementType() { - return this; + return this.elementType; } + /** + * Overwrites the default implementation since the input type + * is inferred from the scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return `${this.scope}Array`; } + /** + * This method can be used to access elements via an index node. + * + * @param {IndexNode} indexNode - indexNode. + * @return {WorkgroupInfoElementNode} A reference to an element. + */ element( indexNode ) { return nodeObject( new WorkgroupInfoElementNode( this, indexNode ) ); @@ -24577,8 +33642,30 @@ class WorkgroupInfoNode extends Node { } +/** + * TSL function for creating a workgroup info node. + * Creates a new 'workgroup' scoped array buffer. + * + * @function + * @param {String} type - The data type of a 'workgroup' scoped buffer element. + * @param {Number} [count=0] - The number of elements in the buffer. + * @returns {WorkgroupInfoNode} + */ const workgroupArray = ( type, count ) => nodeObject( new WorkgroupInfoNode( 'Workgroup', type, count ) ); +/** @module AtomicFunctionNode **/ + +/** + * `AtomicFunctionNode` represents any function that can operate on atomic variable types + * within a shader. In an atomic function, any modification to an atomic variable will + * occur as an indivisible step with a defined order relative to other modifications. + * Accordingly, even if multiple atomic functions are modifying an atomic variable at once + * atomic operations will not interfere with each other. + * + * This node can only be used with a WebGPU backend. + * + * @augments TempNode + */ class AtomicFunctionNode extends TempNode { static get type() { @@ -24587,24 +33674,68 @@ class AtomicFunctionNode extends TempNode { } + /** + * Constructs a new atomic function node. + * + * @param {String} method - The signature of the atomic function to construct. + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + */ constructor( method, pointerNode, valueNode, storeNode = null ) { super( 'uint' ); + /** + * The signature of the atomic function to construct. + * + * @type {String} + */ this.method = method; + /** + * An atomic variable or element of an atomic buffer. + * + * @type {Node} + */ this.pointerNode = pointerNode; + + /** + * A value that modifies the atomic variable. + * + * @type {Node} + */ this.valueNode = valueNode; + + /** + * A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * + * @type {Node?} + * @default null + */ this.storeNode = storeNode; } + /** + * Overwrites the default implementation to return the type of + * the pointer node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( builder ) { return this.pointerNode.getNodeType( builder ); } + /** + * Overwritten since the node type is inferred from the input type. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { return this.getInputType( builder ); @@ -24654,9 +33785,29 @@ AtomicFunctionNode.ATOMIC_AND = 'atomicAnd'; AtomicFunctionNode.ATOMIC_OR = 'atomicOr'; AtomicFunctionNode.ATOMIC_XOR = 'atomicXor'; +/** + * TSL function for creating an atomic function node. + * + * @function + * @param {String} method - The signature of the atomic function to construct. + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicNode = nodeProxy( AtomicFunctionNode ); -const atomicFunc = ( method, pointerNode, valueNode, storeNode ) => { +/** + * TSL function for appending an atomic function call into the programmatic flow of a compute shader. + * + * @function + * @param {String} method - The signature of the atomic function to construct. + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ +const atomicFunc = ( method, pointerNode, valueNode, storeNode = null ) => { const node = atomicNode( method, pointerNode, valueNode, storeNode ); node.append(); @@ -24665,15 +33816,96 @@ const atomicFunc = ( method, pointerNode, valueNode, storeNode ) => { }; +/** + * Stores a value in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicStore = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_STORE, pointerNode, valueNode, storeNode ); + +/** + * Increments the value stored in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicAdd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_ADD, pointerNode, valueNode, storeNode ); + +/** + * Decrements the value stored in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicSub = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_SUB, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the maximum between its current value and a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicMax = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MAX, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the minimum between its current value and a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicMin = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MIN, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the bitwise AND of its value with a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicAnd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_AND, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the bitwise OR of its value with a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicOr = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_OR, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the bitwise XOR of its value with a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicXor = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_XOR, pointerNode, valueNode, storeNode ); +/** @module Lights **/ + let uniformsLib; function getLightData( light ) { @@ -24688,6 +33920,13 @@ function getLightData( light ) { } +/** + * TSL function for getting a shadow matrix uniform node for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The shadow matrix uniform node. + */ function lightShadowMatrix( light ) { const data = getLightData( light ); @@ -24706,6 +33945,14 @@ function lightShadowMatrix( light ) { } +/** + * TSL function for getting projected uv coordinates for the given light. + * Relevant when using maps with spot lights. + * + * @function + * @param {Light} light -The light source. + * @returns {Node} The projected uvs. + */ function lightProjectionUV( light ) { const data = getLightData( light ); @@ -24723,6 +33970,13 @@ function lightProjectionUV( light ) { } +/** + * TSL function for getting the position in world space for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The light's position in world space. + */ function lightPosition( light ) { const data = getLightData( light ); @@ -24731,6 +33985,13 @@ function lightPosition( light ) { } +/** + * TSL function for getting the light target position in world space for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The light target position in world space. + */ function lightTargetPosition( light ) { const data = getLightData( light ); @@ -24739,6 +34000,13 @@ function lightTargetPosition( light ) { } +/** + * TSL function for getting the position in view space for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The light's position in view space. + */ function lightViewPosition( light ) { const data = getLightData( light ); @@ -24754,8 +34022,17 @@ function lightViewPosition( light ) { } +/** + * TSL function for getting the light target direction for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {Node} The light's target direction. + */ const lightTargetDirection = ( light ) => cameraViewMatrix.transformDirection( lightPosition( light ).sub( lightTargetPosition( light ) ) ); +/** @module LightsNode **/ + const sortLights = ( lights ) => { return lights.sort( ( a, b ) => a.id - b.id ); @@ -24780,6 +34057,13 @@ const getLightNodeById = ( id, lightNodes ) => { const _lightsNodeRef = /*@__PURE__*/ new WeakMap(); +/** + * This node represents the scene's lighting and manages the lighting model's life cycle + * for the current build 3D object. It is responsible for computing the total outgoing + * light in a given lighting context. + * + * @augments Node + */ class LightsNode extends Node { static get type() { @@ -24788,33 +34072,81 @@ class LightsNode extends Node { } + /** + * Constructs a new lights node. + */ constructor() { super( 'vec3' ); + /** + * A node representing the total diffuse light. + * + * @type {Node} + */ this.totalDiffuseNode = vec3().toVar( 'totalDiffuse' ); + + /** + * A node representing the total specular light. + * + * @type {Node} + */ this.totalSpecularNode = vec3().toVar( 'totalSpecular' ); + /** + * A node representing the outgoing light. + * + * @type {Node} + */ this.outgoingLightNode = vec3().toVar( 'outgoingLight' ); + /** + * An array representing the lights in the scene. + * + * @private + * @type {Array} + */ this._lights = []; + /** + * For each light in the scene, this node will create a + * corresponding light node. + * + * @private + * @type {Array?} + * @default null + */ this._lightNodes = null; + + /** + * A hash for identifying the current light nodes setup. + * + * @private + * @type {String?} + * @default null + */ this._lightNodesHash = null; + /** + * `LightsNode` sets this property to `true` by default. + * + * @type {Boolean} + * @default true + */ this.global = true; } /** - * Overwrites the default `customCacheKey()` implementation by including the + * Overwrites the default {@link Node#customCacheKey} implementation by including the * light IDs into the cache key. * - * @return {Number} The hash. + * @return {Number} The custom cache key. */ customCacheKey() { const lightIDs = []; + const lights = this._lights; for ( let i = 0; i < lights.length; i ++ ) { @@ -24826,6 +34158,12 @@ class LightsNode extends Node { } + /** + * Computes a hash value for identifying the current light nodes setup. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {String} The computed hash. + */ getHash( builder ) { if ( this._lightNodesHash === null ) { @@ -24860,6 +34198,12 @@ class LightsNode extends Node { } + /** + * Creates lighting nodes for each scene light. This makes it possible to further + * process lights in the node system. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + */ setupLightsNode( builder ) { const lightNodes = []; @@ -24887,6 +34231,8 @@ class LightsNode extends Node { if ( lightNode === null ) { + // find the corresponding node type for a given light + const lightNodeClass = nodeLibrary.getLightNodeClass( light.constructor ); if ( lightNodeClass === null ) { @@ -24921,6 +34267,13 @@ class LightsNode extends Node { } + /** + * Setups the internal lights by building all respective + * light nodes. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Array} lightNodes - An array of lighting nodes. + */ setupLights( builder, lightNodes ) { for ( const lightNode of lightNodes ) { @@ -24931,6 +34284,14 @@ class LightsNode extends Node { } + /** + * The implementation makes sure that for each light in the scene + * there is a corresponding light node. By building the light nodes + * and evaluating the lighting model the outgoing light is computed. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {Node} A node representing the outgoing light. + */ setup( builder ) { if ( this._lightNodes === null ) this.setupLightsNode( builder ); @@ -25007,6 +34368,12 @@ class LightsNode extends Node { } + /** + * Configures this node with an array of lights. + * + * @param {Array} lights - An array of lights. + * @return {LightsNode} A reference to this node. + */ setLights( lights ) { this._lights = lights; @@ -25018,12 +34385,22 @@ class LightsNode extends Node { } + /** + * Returns an array of the scene's lights. + * + * @return {Array} The scene's lights. + */ getLights() { return this._lights; } + /** + * Whether the scene has lights or not. + * + * @type {Boolean} + */ get hasLights() { return this._lights.length > 0; @@ -25032,8 +34409,27 @@ class LightsNode extends Node { } +/** + * TSL function for creating an instance of `LightsNode` and configuring + * it with the given array of lights. + * + * @function + * @param {Array} lights - An array of lights. + * @return {LightsNode} The created lights node. + */ const lights = ( lights = [] ) => nodeObject( new LightsNode() ).setLights( lights ); +/** @module ShadowBaseNode **/ + +/** + * Base class for all shadow nodes. + * + * Shadow nodes encapsulate shadow related logic and are always coupled to lighting nodes. + * Lighting nodes might share the same shadow node type or use specific ones depending on + * their requirements. + * + * @augments Node + */ class ShadowBaseNode extends Node { static get type() { @@ -25042,25 +34438,59 @@ class ShadowBaseNode extends Node { } + /** + * Constructs a new shadow base node. + * + * @param {Light} light - The shadow casting light. + */ constructor( light ) { super(); + /** + * The shadow casting light. + * + * @type {Light} + */ this.light = light; + + /** + * Overwritten since shadows are updated by default per render. + * + * @type {String} + * @default 'render' + */ this.updateBeforeType = NodeUpdateType.RENDER; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isShadowBaseNode = true; } + /** + * Setups the shadow position node which is by default the predefined TSL node object `shadowPositionWorld`. + * + * @param {(NodeBuilder|{Material})} object - A configuration object that must at least hold a material reference. + */ setupShadowPosition( { material } ) { // Use assign inside an Fn() - shadowWorldPosition.assign( material.shadowPositionNode || positionWorld ); + shadowPositionWorld.assign( material.shadowPositionNode || positionWorld ); } + /** + * Can be called when the shadow isn't required anymore. That can happen when + * a lighting node stops casting shadows by setting {@link Object3D#castShadow} + * to `false`. + */ dispose() { this.updateBeforeType = NodeUpdateType.NONE; @@ -25069,7 +34499,219 @@ class ShadowBaseNode extends Node { } -const shadowWorldPosition = /*@__PURE__*/ vec3().toVar( 'shadowWorldPosition' ); +/** + * TSL object that represents the vertex position in world space during the shadow pass. + * + * @type {Node} + */ +const shadowPositionWorld = /*@__PURE__*/ vec3().toVar( 'shadowPositionWorld' ); + +/** @module RendererUtils **/ + +/** + * Saves the state of the given renderer and stores it into the given state object. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function saveRendererState( renderer, state = {} ) { + + state.toneMapping = renderer.toneMapping; + state.toneMappingExposure = renderer.toneMappingExposure; + state.outputColorSpace = renderer.outputColorSpace; + state.renderTarget = renderer.getRenderTarget(); + state.activeCubeFace = renderer.getActiveCubeFace(); + state.activeMipmapLevel = renderer.getActiveMipmapLevel(); + state.renderObjectFunction = renderer.getRenderObjectFunction(); + state.pixelRatio = renderer.getPixelRatio(); + state.mrt = renderer.getMRT(); + state.clearColor = renderer.getClearColor( state.clearColor || new Color() ); + state.clearAlpha = renderer.getClearAlpha(); + state.autoClear = renderer.autoClear; + state.scissorTest = renderer.getScissorTest(); + + return state; + +} + +/** + * Saves the state of the given renderer and stores it into the given state object. + * Besides, the function also resets the state of the renderer to its default values. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function resetRendererState( renderer, state ) { + + state = saveRendererState( renderer, state ); + + renderer.setMRT( null ); + renderer.setRenderObjectFunction( null ); + renderer.setClearColor( 0x000000, 1 ); + renderer.autoClear = true; + + return state; + +} + +/** + * Restores the state of the given renderer from the given state object. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Object} state - The state to restore. + */ +function restoreRendererState( renderer, state ) { + + renderer.toneMapping = state.toneMapping; + renderer.toneMappingExposure = state.toneMappingExposure; + renderer.outputColorSpace = state.outputColorSpace; + renderer.setRenderTarget( state.renderTarget, state.activeCubeFace, state.activeMipmapLevel ); + renderer.setRenderObjectFunction( state.renderObjectFunction ); + renderer.setPixelRatio( state.pixelRatio ); + renderer.setMRT( state.mrt ); + renderer.setClearColor( state.clearColor, state.clearAlpha ); + renderer.autoClear = state.autoClear; + renderer.setScissorTest( state.scissorTest ); + +} + +/** + * Saves the state of the given scene and stores it into the given state object. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function saveSceneState( scene, state = {} ) { + + state.background = scene.background; + state.backgroundNode = scene.backgroundNode; + state.overrideMaterial = scene.overrideMaterial; + + return state; + +} + +/** + * Saves the state of the given scene and stores it into the given state object. + * Besides, the function also resets the state of the scene to its default values. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function resetSceneState( scene, state ) { + + state = saveSceneState( scene, state ); + + scene.background = null; + scene.backgroundNode = null; + scene.overrideMaterial = null; + + return state; + +} + +/** + * Restores the state of the given scene from the given state object. + * + * @function + * @param {Scene} scene - The scene. + * @param {Object} state - The state to restore. + */ +function restoreSceneState( scene, state ) { + + scene.background = state.background; + scene.backgroundNode = state.backgroundNode; + scene.overrideMaterial = state.overrideMaterial; + +} + +/** + * Saves the state of the given renderer and scene and stores it into the given state object. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function saveRendererAndSceneState( renderer, scene, state = {} ) { + + state = saveRendererState( renderer, state ); + state = saveSceneState( scene, state ); + + return state; + +} + +/** + * Saves the state of the given renderer and scene and stores it into the given state object. + * Besides, the function also resets the state of the renderer and scene to its default values. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function resetRendererAndSceneState( renderer, scene, state ) { + + state = resetRendererState( renderer, state ); + state = resetSceneState( scene, state ); + + return state; + +} + +/** + * Restores the state of the given renderer and scene from the given state object. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Scene} scene - The scene. + * @param {Object} state - The state to restore. + */ +function restoreRendererAndSceneState( renderer, scene, state ) { + + restoreRendererState( renderer, state ); + restoreSceneState( scene, state ); + +} + +var RendererUtils = /*#__PURE__*/Object.freeze({ + __proto__: null, + resetRendererAndSceneState: resetRendererAndSceneState, + resetRendererState: resetRendererState, + resetSceneState: resetSceneState, + restoreRendererAndSceneState: restoreRendererAndSceneState, + restoreRendererState: restoreRendererState, + restoreSceneState: restoreSceneState, + saveRendererAndSceneState: saveRendererAndSceneState, + saveRendererState: saveRendererState, + saveSceneState: saveSceneState +}); + +/** @module ShadowNode **/ const shadowMaterialLib = /*@__PURE__*/ new WeakMap(); const linearDistance = /*@__PURE__*/ Fn( ( [ position, cameraNear, cameraFar ] ) => { @@ -25106,8 +34748,9 @@ const getShadowMaterial = ( light ) => { material = new NodeMaterial(); material.colorNode = vec4( 0, 0, 0, 1 ); material.depthNode = depthNode; - material.isShadowNodeMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode + material.isShadowPassMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode material.name = 'ShadowMaterial'; + material.fog = false; shadowMaterialLib.set( light, material ); @@ -25117,12 +34760,32 @@ const getShadowMaterial = ( light ) => { }; +/** + * A shadow filtering function performing basic filtering. This is in fact an unfiltered version of the shadow map + * with a binary `[0,1]` result. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - The shadow coordinates. + * @return {Node} The filtering result. + */ const BasicShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord } ) => { return texture( depthTexture, shadowCoord.xy ).compare( shadowCoord.z ); } ); +/** + * A shadow filtering function performing PCF filtering. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - The shadow coordinates. + * @param {LightShadow} inputs.shadow - The light shadow. + * @return {Node} The filtering result. + */ const PCFShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, shadow } ) => { const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); @@ -25162,6 +34825,16 @@ const PCFShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, shadow } ); +/** + * A shadow filtering function performing PCF soft filtering. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - The shadow coordinates. + * @param {LightShadow} inputs.shadow - The light shadow. + * @return {Node} The filtering result. + */ const PCFSoftShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, shadow } ) => { const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); @@ -25218,8 +34891,15 @@ const PCFSoftShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, sha } ); -// VSM - +/** + * A shadow filtering function performing VSM filtering. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - The shadow coordinates. + * @return {Node} The filtering result. + */ const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord } ) => { const occlusion = float( 1 ).toVar(); @@ -25242,6 +34922,17 @@ const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord } ) => { } ); +/** + * Represents the shader code for the first VSM render pass. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {Node} inputs.samples - The number of samples + * @param {Node} inputs.radius - The radius. + * @param {Node} inputs.size - The size. + * @param {TextureNode} inputs.shadowPass - A reference to the render target's depth data. + * @return {Node} The VSM output. + */ const VSMPassVertical = /*@__PURE__*/ Fn( ( { samples, radius, size, shadowPass } ) => { const mean = float( 0 ).toVar(); @@ -25268,6 +34959,17 @@ const VSMPassVertical = /*@__PURE__*/ Fn( ( { samples, radius, size, shadowPass } ); +/** + * Represents the shader code for the second VSM render pass. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {Node} inputs.samples - The number of samples + * @param {Node} inputs.radius - The radius. + * @param {Node} inputs.size - The size. + * @param {TextureNode} inputs.shadowPass - The result of the first VSM render pass. + * @return {Node} The VSM output. + */ const VSMPassHorizontal = /*@__PURE__*/ Fn( ( { samples, radius, size, shadowPass } ) => { const mean = float( 0 ).toVar(); @@ -25298,8 +35000,14 @@ const _shadowFilterLib = [ BasicShadowFilter, PCFShadowFilter, PCFSoftShadowFilt // -const _quadMesh$1 = /*@__PURE__*/ new QuadMesh(); +let _rendererState; +const _quadMesh = /*@__PURE__*/ new QuadMesh(); +/** + * Represents the default shadow implementation for lighting nodes. + * + * @augments module:ShadowBaseNode~ShadowBaseNode + */ class ShadowNode extends ShadowBaseNode { static get type() { @@ -25308,26 +35016,101 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Constructs a new shadow node. + * + * @param {Light} light - The shadow casting light. + * @param {LightShadow?} [shadow=null] - An optional light shadow. + */ constructor( light, shadow = null ) { super( light ); + /** + * The light shadow which defines the properties light's + * shadow. + * + * @type {LightShadow?} + * @default null + */ this.shadow = shadow || light.shadow; + /** + * A reference to the shadow map which is a render target. + * + * @type {RenderTarget?} + * @default null + */ this.shadowMap = null; + /** + * Only relevant for VSM shadows. Render target for the + * first VSM render pass. + * + * @type {RenderTarget?} + * @default null + */ this.vsmShadowMapVertical = null; + + /** + * Only relevant for VSM shadows. Render target for the + * second VSM render pass. + * + * @type {RenderTarget?} + * @default null + */ this.vsmShadowMapHorizontal = null; + /** + * Only relevant for VSM shadows. Node material which + * is used to render the first VSM pass. + * + * @type {NodeMaterial?} + * @default null + */ this.vsmMaterialVertical = null; + + /** + * Only relevant for VSM shadows. Node material which + * is used to render the second VSM pass. + * + * @type {NodeMaterial?} + * @default null + */ this.vsmMaterialHorizontal = null; + /** + * A reference to the output node which defines the + * final result of this shadow node. + * + * @type {Node?} + * @private + * @default null + */ this._node = null; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isShadowNode = true; } + /** + * Setups the shadow filtering. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Object} inputs - A configuration object that defines the shadow filtering. + * @param {Function} inputs.filterFn - This function defines the filtering type of the shadow map e.g. PCF. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - Shadow coordinates which are used to sample from the shadow map. + * @param {LightShadow} inputs.shadow - The light shadow. + * @return {Node} The result node of the shadow filtering. + */ setupShadowFilter( builder, { filterFn, depthTexture, shadowCoord, shadow } ) { const frustumTest = shadowCoord.x.greaterThanEqual( 0 ) @@ -25342,6 +35125,13 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Setups the shadow coordinates. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Node} shadowPosition - A node representing the shadow position. + * @return {Node} The shadow coordinates. + */ setupShadowCoord( builder, shadowPosition ) { const { shadow } = this; @@ -25389,12 +35179,24 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Returns the shadow filtering function for the given shadow type. + * + * @param {Number} type - The shadow type. + * @return {Function} The filtering function. + */ getShadowFilterFn( type ) { return _shadowFilterLib[ type ]; } + /** + * Setups the shadow output node. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {Node} The shadow output node. + */ setupShadow( builder ) { const { renderer } = builder; @@ -25442,7 +35244,7 @@ class ShadowNode extends ShadowBaseNode { const shadowIntensity = reference( 'intensity', 'float', shadow ).setGroup( renderGroup ); const normalBias = reference( 'normalBias', 'float', shadow ).setGroup( renderGroup ); - const shadowPosition = lightShadowMatrix( light ).mul( shadowWorldPosition.add( transformedNormalWorld.mul( normalBias ) ) ); + const shadowPosition = lightShadowMatrix( light ).mul( shadowPositionWorld.add( transformedNormalWorld.mul( normalBias ) ) ); const shadowCoord = this.setupShadowCoord( builder, shadowPosition ); // @@ -25469,6 +35271,13 @@ class ShadowNode extends ShadowBaseNode { } + /** + * The implementation performs the setup of the output node. An output is only + * produces if shadow mapping is globally enabled in the renderer. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {ShaderCallNodeInternal} The output node. + */ setup( builder ) { if ( builder.renderer.shadowMap.enabled === false ) return; @@ -25503,6 +35312,14 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Renders the shadow. The logic of this function could be included + * into {@link ShadowNode#updateShadow} however more specialized shadow + * nodes might require a custom shadow map rendering. By having a + * dedicated method, it's easier to overwrite the default behavior. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ renderShadow( frame ) { const { shadow, shadowMap, light } = this; @@ -25516,6 +35333,11 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Updates the shadow. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ updateShadow( frame ) { const { shadowMap, light, shadow } = this; @@ -25526,22 +35348,27 @@ class ShadowNode extends ShadowBaseNode { const depthVersion = shadowMap.depthTexture.version; this._depthVersionCached = depthVersion; - const currentOverrideMaterial = scene.overrideMaterial; - - scene.overrideMaterial = getShadowMaterial( light ); - shadow.camera.layers.mask = camera.layers.mask; - const currentRenderTarget = renderer.getRenderTarget(); const currentRenderObjectFunction = renderer.getRenderObjectFunction(); + const currentMRT = renderer.getMRT(); + const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; - renderer.setMRT( null ); + _rendererState = resetRendererAndSceneState( renderer, scene, _rendererState ); + + scene.overrideMaterial = getShadowMaterial( light ); renderer.setRenderObjectFunction( ( object, scene, _camera, geometry, material, group, ...params ) => { if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { + if ( useVelocity ) { + + getDataFromObject( object ).useVelocity = true; + + } + object.onBeforeShadow( renderer, object, camera, shadow.camera, geometry, scene.overrideMaterial, group ); renderer.renderObject( object, scene, _camera, geometry, material, group, ...params ); @@ -25566,14 +35393,15 @@ class ShadowNode extends ShadowBaseNode { } - renderer.setRenderTarget( currentRenderTarget ); - - renderer.setMRT( currentMRT ); - - scene.overrideMaterial = currentOverrideMaterial; + restoreRendererAndSceneState( renderer, scene, _rendererState ); } + /** + * For VSM additional render passes are required. + * + * @param {Renderer} renderer - A reference to the current renderer. + */ vsmPass( renderer ) { const { shadow } = this; @@ -25582,15 +35410,18 @@ class ShadowNode extends ShadowBaseNode { this.vsmShadowMapHorizontal.setSize( shadow.mapSize.width, shadow.mapSize.height ); renderer.setRenderTarget( this.vsmShadowMapVertical ); - _quadMesh$1.material = this.vsmMaterialVertical; - _quadMesh$1.render( renderer ); + _quadMesh.material = this.vsmMaterialVertical; + _quadMesh.render( renderer ); renderer.setRenderTarget( this.vsmShadowMapHorizontal ); - _quadMesh$1.material = this.vsmMaterialHorizontal; - _quadMesh$1.render( renderer ); + _quadMesh.material = this.vsmMaterialHorizontal; + _quadMesh.render( renderer ); } + /** + * Frees the internal resources of this shadow node. + */ dispose() { this.shadowMap.dispose(); @@ -25620,6 +35451,11 @@ class ShadowNode extends ShadowBaseNode { } + /** + * The implementation performs the update of the shadow map if necessary. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ updateBefore( frame ) { const { shadow } = this; @@ -25642,6 +35478,14 @@ class ShadowNode extends ShadowBaseNode { } +/** + * TSL function for creating an instance of `ShadowNode`. + * + * @function + * @param {Light} light - The shadow casting light. + * @param {LightShadow} shadow - The light shadow. + * @return {ShadowNode} The created shadow node. + */ const shadow = ( light, shadow ) => nodeObject( new ShadowNode( light, shadow ) ); /** @@ -25669,7 +35513,7 @@ class AnalyticLightNode extends LightingNode { /** * The light source. * - * @type {Light} + * @type {Light?} * @default null */ this.light = light; @@ -25691,23 +35535,26 @@ class AnalyticLightNode extends LightingNode { /** * This property is used to retain a reference to the original value of {@link AnalyticLightNode#colorNode}. - * The final color node is represented by a differnt node when using shadows. + * The final color node is represented by a different node when using shadows. * - * @type {Node} + * @type {Node?} + * @default null */ this.baseColorNode = null; /** * Represents the light's shadow. * - * @type {ShadowNode} + * @type {ShadowNode?} + * @default null */ this.shadowNode = null; /** * Represents the light's shadow color. * - * @type {Node} + * @type {Node?} + * @default null */ this.shadowColorNode = null; @@ -25763,7 +35610,8 @@ class AnalyticLightNode extends LightingNode { /** * Setups the shadow for this light. This method is only executed if the light - * cast shadows and the current build object receives shadows. + * cast shadows and the current build object receives shadows. It incorporates + * shadows into the lighting computation. * * @param {NodeBuilder} builder - The current node builder. */ @@ -25808,7 +35656,7 @@ class AnalyticLightNode extends LightingNode { /** * Unlike most other nodes, lighting nodes do not return a output node in {@link Node#setup}. * The main purpose of lighting nodes is to configure the current {@link LightingModel} and/or - * invocate the respecitve interface methods. + * invocate the respective interface methods. * * @param {NodeBuilder} builder - The current node builder. */ @@ -25879,6 +35727,8 @@ const getDistanceAttenuation = /*@__PURE__*/ Fn( ( inputs ) => { } ); // validated +/** @module PointShadowNode **/ + const _clearColor$2 = /*@__PURE__*/ new Color(); // cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D @@ -26025,8 +35875,12 @@ const _viewport = /*@__PURE__*/ new Vector4(); const _viewportSize = /*@__PURE__*/ new Vector2(); const _shadowMapSize = /*@__PURE__*/ new Vector2(); -// +/** + * Represents the shadow implementation for point light nodes. + * + * @augments module:ShadowNode~ShadowNode + */ class PointShadowNode extends ShadowNode { static get type() { @@ -26035,30 +35889,69 @@ class PointShadowNode extends ShadowNode { } + /** + * Constructs a new point shadow node. + * + * @param {PointLight} light - The shadow casting point light. + * @param {PointLightShadow?} [shadow=null] - An optional point light shadow. + */ constructor( light, shadow = null ) { super( light, shadow ); } + /** + * Overwrites the default implementation to return point light shadow specific + * filtering functions. + * + * @param {Number} type - The shadow type. + * @return {Function} The filtering function. + */ getShadowFilterFn( type ) { return type === BasicShadowMap ? BasicPointShadowFilter : PointShadowFilter; } + /** + * Overwrites the default implementation so the unaltered shadow position is used. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Node} shadowPosition - A node representing the shadow position. + * @return {Node} The shadow coordinates. + */ setupShadowCoord( builder, shadowPosition ) { return shadowPosition; } + /** + * Overwrites the default implementation to only use point light specific + * shadow filter functions. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Object} inputs - A configuration object that defines the shadow filtering. + * @param {Function} inputs.filterFn - This function defines the filtering type of the shadow map e.g. PCF. + * @param {Texture} inputs.shadowTexture - A reference to the shadow map's texture. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - Shadow coordinates which are used to sample from the shadow map. + * @param {LightShadow} inputs.shadow - The light shadow. + * @return {Node} The result node of the shadow filtering. + */ setupShadowFilter( builder, { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } ) { return pointShadowFilter( { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } ); } + /** + * Overwrites the default implementation with point light specific + * rendering code. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ renderShadow( frame ) { const { shadow, shadowMap, light } = this; @@ -26117,6 +36010,14 @@ class PointShadowNode extends ShadowNode { } +/** + * TSL function for creating an instance of `PointShadowNode`. + * + * @function + * @param {PointLight} light - The shadow casting point light. + * @param {PointLightShadow?} [shadow=null] - An optional point light shadow. + * @return {PointShadowNode} The created point shadow node. + */ const pointShadow = ( light, shadow ) => nodeObject( new PointShadowNode( light, shadow ) ); const directPointLight = Fn( ( { color, lightViewPosition, cutoffDistance, decayExponent }, builder ) => { @@ -26232,7 +36133,7 @@ class PointLightNode extends AnalyticLightNode { * Creates a 2x2 checkerboard pattern that can be used as procedural texture data. * * @method - * @param {Node} uv - The uv coordinates. + * @param {Node} coord - The uv coordinates. * @return {Node} The result data. */ const checker = /*@__PURE__*/ Fn( ( [ coord = uv() ] ) => { @@ -26247,6 +36148,36 @@ const checker = /*@__PURE__*/ Fn( ( [ coord = uv() ] ) => { } ); +/** @module Shapes **/ + +/** + * Generates a circle based on the uv coordinates. + * + * @method + * @param {Node} coord - The uv to generate the circle. + * @return {Node} The circle shape. + */ +const shapeCircle = Fn( ( [ coord = uv() ], { renderer, material } ) => { + + const alpha = float( 1 ).toVar(); + const len2 = lengthSq( coord.mul( 2 ).sub( 1 ) ); + + if ( material.alphaToCoverage && 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(); + + } + + return alpha; + +} ); + // Three.js Transpiler // https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/libraries/stdlib/genglsl/lib/mx_noise.glsl @@ -27770,8 +37701,23 @@ const mx_fractal_noise_vec2 = ( position = uv(), octaves = 3, lacunarity = 2, di 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 ); -// https://devlog-martinsh.blogspot.com/2011/09/box-projected-cube-environment-mapping.html +/** @module getParallaxCorrectNormal **/ +/** + * This computes a parallax corrected normal which is used for box-projected cube mapping (BPCEM). + * + * Reference: {@link https://devlog-martinsh.blogspot.com/2011/09/box-projected-cube-environment-mapping.html} + * + * ```js + * const uvNode = getParallaxCorrectNormal( reflectVector, vec3( 200, 100, 100 ), vec3( 0, - 50, 0 ) ); + * material.envNode = pmremTexture( renderTarget.texture, uvNode ); + * ``` + * @function + * @param {Node} normal - The normal to correct. + * @param {Node} cubeSize - The cube size should reflect the size of the environment (BPCEM is usually applied in closed environments like rooms). + * @param {Node} cubePos - The cube position. + * @return {Node} The parallax corrected normal. + */ const getParallaxCorrectNormal = /*@__PURE__*/ Fn( ( [ normal, cubeSize, cubePos ] ) => { const nDir = normalize( normal ).toVar( 'nDir' ); @@ -27821,6 +37767,7 @@ var TSL = /*#__PURE__*/Object.freeze({ BRDF_Lambert: BRDF_Lambert, BasicShadowFilter: BasicShadowFilter, Break: Break, + Const: Const, Continue: Continue, DFGApprox: DFGApprox, D_GGX: D_GGX, @@ -27846,6 +37793,7 @@ var TSL = /*#__PURE__*/Object.freeze({ TBNViewMatrix: TBNViewMatrix, VSMShadowFilter: VSMShadowFilter, V_GGX_SmithCorrelated: V_GGX_SmithCorrelated, + Var: Var, abs: abs, acesFilmicToneMapping: acesFilmicToneMapping, acos: acos, @@ -27948,6 +37896,7 @@ var TSL = /*#__PURE__*/Object.freeze({ degrees: degrees, deltaTime: deltaTime, densityFog: densityFog, + densityFogFactor: densityFogFactor, depth: depth, depthPass: depthPass, difference: difference, @@ -27971,6 +37920,7 @@ var TSL = /*#__PURE__*/Object.freeze({ expression: expression, faceDirection: faceDirection, faceForward: faceForward, + faceforward: faceforward, float: float, floor: floor, fog: fog, @@ -27993,14 +37943,15 @@ var TSL = /*#__PURE__*/Object.freeze({ getShIrradianceAt: getShIrradianceAt, getTextureIndex: getTextureIndex, getViewPosition: getViewPosition, + globalId: globalId, glsl: glsl, glslFn: glslFn, grayscale: grayscale, greaterThan: greaterThan, greaterThanEqual: greaterThanEqual, hash: hash, - highPrecisionModelNormalViewMatrix: highPrecisionModelNormalViewMatrix, - highPrecisionModelViewMatrix: highPrecisionModelViewMatrix, + highpModelNormalViewMatrix: highpModelNormalViewMatrix, + highpModelViewMatrix: highpModelViewMatrix, hue: hue, instance: instance, instanceIndex: instanceIndex, @@ -28010,6 +37961,7 @@ var TSL = /*#__PURE__*/Object.freeze({ instancedMesh: instancedMesh, int: int, inverseSqrt: inverseSqrt, + inversesqrt: inversesqrt, invocationLocalIndex: invocationLocalIndex, invocationSubgroupIndex: invocationSubgroupIndex, ior: ior, @@ -28045,7 +37997,7 @@ var TSL = /*#__PURE__*/Object.freeze({ mat3: mat3, mat4: mat4, matcapUV: matcapUV, - materialAOMap: materialAOMap, + materialAO: materialAO, materialAlphaTest: materialAlphaTest, materialAnisotropy: materialAnisotropy, materialAnisotropyVector: materialAnisotropyVector, @@ -28070,7 +38022,7 @@ var TSL = /*#__PURE__*/Object.freeze({ materialMetalness: materialMetalness, materialNormal: materialNormal, materialOpacity: materialOpacity, - materialPointWidth: materialPointWidth, + materialPointSize: materialPointSize, materialReference: materialReference, materialReflectivity: materialReflectivity, materialRefractionRatio: materialRefractionRatio, @@ -28087,6 +38039,7 @@ var TSL = /*#__PURE__*/Object.freeze({ materialTransmission: materialTransmission, max: max$1, maxMipLevel: maxMipLevel, + mediumpModelViewMatrix: mediumpModelViewMatrix, metalness: metalness, min: min$1, mix: mix, @@ -28189,6 +38142,7 @@ var TSL = /*#__PURE__*/Object.freeze({ rand: rand, range: range, rangeFog: rangeFog, + rangeFogFactor: rangeFogFactor, reciprocal: reciprocal, reference: reference, referenceBuffer: referenceBuffer, @@ -28226,6 +38180,8 @@ var TSL = /*#__PURE__*/Object.freeze({ setCurrentStack: setCurrentStack, shaderStages: shaderStages, shadow: shadow, + shadowPositionWorld: shadowPositionWorld, + shapeCircle: shapeCircle, sharedUniformGroup: sharedUniformGroup, sheen: sheen, sheenRoughness: sheenRoughness, @@ -28316,6 +38272,7 @@ var TSL = /*#__PURE__*/Object.freeze({ velocity: velocity, vertexColor: vertexColor, vertexIndex: vertexIndex, + vertexStage: vertexStage, vibrance: vibrance, viewZToLogarithmicDepth: viewZToLogarithmicDepth, viewZToOrthographicDepth: viewZToOrthographicDepth, @@ -28344,17 +38301,50 @@ var TSL = /*#__PURE__*/Object.freeze({ const _clearColor$1 = /*@__PURE__*/ new Color4(); +/** + * This renderer module manages the background. + * + * @private + * @augments DataMap + */ class Background extends DataMap { + /** + * Constructs a new background management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + */ constructor( renderer, nodes ) { super(); + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; } + /** + * Updates the background for the given scene. Depending on how `Scene.background` + * or `Scene.backgroundNode` are configured, this method might configure a simple clear + * or add a mesh to the render list for rendering the background as a textured plane + * or skybox. + * + * @param {Scene} scene - The scene. + * @param {RenderList} renderList - The current render list. + * @param {RenderContext} renderContext - The current render context. + */ update( scene, renderList, renderContext ) { const renderer = this.renderer; @@ -28395,7 +38385,7 @@ class Background extends DataMap { getTextureLevel: () => backgroundBlurriness } ); - let viewProj = modelViewProjection(); + let viewProj = modelViewProjection; viewProj = viewProj.setZ( viewProj.w ); const nodeMaterial = new NodeMaterial(); @@ -28486,50 +38476,187 @@ class Background extends DataMap { let _id$6 = 0; +/** + * A bind group represents a collection of bindings and thus a collection + * or resources. Bind groups are assigned to pipelines to provide them + * with the required resources (like uniform buffers or textures). + * + * @private + */ class BindGroup { + /** + * Constructs a new bind group. + * + * @param {String} name - The bind group's name. + * @param {Array} bindings - An array of bindings. + * @param {Number} index - The group index. + * @param {Array} bindingsReference - An array of reference bindings. + */ constructor( name = '', bindings = [], index = 0, bindingsReference = [] ) { + /** + * The bind group's name. + * + * @type {String} + */ this.name = name; + + /** + * An array of bindings. + * + * @type {Array} + */ this.bindings = bindings; + + /** + * The group index. + * + * @type {Number} + */ this.index = index; + + /** + * An array of reference bindings. + * + * @type {Array} + */ this.bindingsReference = bindingsReference; + /** + * The group's ID. + * + * @type {Number} + */ this.id = _id$6 ++; } } +/** + * This module represents the state of a node builder after it was + * used to build the nodes for a render object. The state holds the + * results of the build for further processing in the renderer. + * + * Render objects with identical cache keys share the same node builder state. + * + * @private + */ class NodeBuilderState { + /** + * Constructs a new node builder state. + * + * @param {String?} vertexShader - The native vertex shader code. + * @param {String?} fragmentShader - The native fragment shader code. + * @param {String?} computeShader - The native compute shader code. + * @param {Array} nodeAttributes - An array of node attributes. + * @param {Array} bindings - An array of bind groups. + * @param {Array} updateNodes - An array of nodes that implement their `update()` method. + * @param {Array} updateBeforeNodes - An array of nodes that implement their `updateBefore()` method. + * @param {Array} updateAfterNodes - An array of nodes that implement their `updateAfter()` method. + * @param {NodeMaterialObserver} monitor - A node material observer. + * @param {Array} transforms - An array with transform attribute objects. Only relevant when using compute shaders with WebGL 2. + */ constructor( vertexShader, fragmentShader, computeShader, nodeAttributes, bindings, updateNodes, updateBeforeNodes, updateAfterNodes, monitor, transforms = [] ) { + /** + * The native vertex shader code. + * + * @type {String} + */ this.vertexShader = vertexShader; + + /** + * The native fragment shader code. + * + * @type {String} + */ this.fragmentShader = fragmentShader; + + /** + * The native compute shader code. + * + * @type {String} + */ this.computeShader = computeShader; + + /** + * An array with transform attribute objects. + * Only relevant when using compute shaders with WebGL 2. + * + * @type {Array} + */ this.transforms = transforms; + /** + * An array of node attributes representing + * the attributes of the shaders. + * + * @type {Array} + */ this.nodeAttributes = nodeAttributes; + + /** + * An array of bind groups representing the uniform or storage + * buffers, texture or samplers of the shader. + * + * @type {Array} + */ this.bindings = bindings; + /** + * An array of nodes that implement their `update()` method. + * + * @type {Array} + */ this.updateNodes = updateNodes; + + /** + * An array of nodes that implement their `updateBefore()` method. + * + * @type {Array} + */ this.updateBeforeNodes = updateBeforeNodes; + + /** + * An array of nodes that implement their `updateAfter()` method. + * + * @type {Array} + */ this.updateAfterNodes = updateAfterNodes; + /** + * A node material observer. + * + * @type {NodeMaterialObserver} + */ this.monitor = monitor; + /** + * How often this state is used by render objects. + * + * @type {Number} + */ this.usedTimes = 0; } + /** + * This method is used to create a array of bind groups based + * on the existing bind groups of this state. Shared groups are + * not cloned. + * + * @return {Array} A array of bind groups. + */ createBindings() { const bindings = []; for ( const instanceGroup of this.bindings ) { - const shared = instanceGroup.bindings[ 0 ].groupNode.shared; + const shared = instanceGroup.bindings[ 0 ].groupNode.shared; // TODO: Is it safe to always check the first binding in the group? if ( shared !== true ) { @@ -28711,8 +38838,9 @@ class NodeVar { * * @param {String} name - The name of the variable. * @param {String} type - The type of the variable. + * @param {Boolean} [readOnly=false] - The read-only flag. */ - constructor( name, type ) { + constructor( name, type, readOnly = false ) { /** * This flag can be used for type testing. @@ -28737,6 +38865,13 @@ class NodeVar { */ this.type = type; + /** + * The read-only flag. + * + * @type {boolean} + */ + this.readOnly = readOnly; + } } @@ -28965,26 +39100,79 @@ class StructTypeNode extends Node { } +/** + * Abstract base class for uniforms. + * + * @abstract + * @private + */ class Uniform { + /** + * Constructs a new uniform. + * + * @param {String} name - The uniform's name. + * @param {Any} value - The uniform's value. + */ constructor( name, value ) { + /** + * The uniform's name. + * + * @type {String} + */ this.name = name; + + /** + * The uniform's value. + * + * @type {Any} + */ this.value = value; - this.boundary = 0; // used to build the uniform buffer according to the STD140 layout + /** + * Used to build the uniform buffer according to the STD140 layout. + * Derived uniforms will set this property to a data type specific + * value. + * + * @type {Number} + */ + this.boundary = 0; + + /** + * The item size. Derived uniforms will set this property to a data + * type specific value. + * + * @type {Number} + */ this.itemSize = 0; - this.offset = 0; // this property is set by WebGPUUniformsGroup and marks the start position in the uniform buffer + /** + * This property is set by {@link UniformsGroup} and marks + * the start position in the uniform buffer. + * + * @type {Number} + */ + this.offset = 0; } + /** + * Sets the uniform's value. + * + * @param {Any} value - The value to set. + */ setValue( value ) { this.value = value; } + /** + * Returns the uniform's value. + * + * @return {Any} The value. + */ getValue() { return this.value; @@ -28993,12 +39181,31 @@ class Uniform { } +/** + * Represents a Number uniform. + * + * @private + * @augments Uniform + */ class NumberUniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Number} value - The uniform's value. + */ constructor( name, value = 0 ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isNumberUniform = true; this.boundary = 4; @@ -29008,12 +39215,31 @@ class NumberUniform extends Uniform { } +/** + * Represents a Vector2 uniform. + * + * @private + * @augments Uniform + */ class Vector2Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Vector2} value - The uniform's value. + */ constructor( name, value = new Vector2() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVector2Uniform = true; this.boundary = 8; @@ -29023,12 +39249,31 @@ class Vector2Uniform extends Uniform { } +/** + * Represents a Vector3 uniform. + * + * @private + * @augments Uniform + */ class Vector3Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Vector3} value - The uniform's value. + */ constructor( name, value = new Vector3() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVector3Uniform = true; this.boundary = 16; @@ -29038,12 +39283,31 @@ class Vector3Uniform extends Uniform { } +/** + * Represents a Vector4 uniform. + * + * @private + * @augments Uniform + */ class Vector4Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Vector4} value - The uniform's value. + */ constructor( name, value = new Vector4() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVector4Uniform = true; this.boundary = 16; @@ -29053,12 +39317,31 @@ class Vector4Uniform extends Uniform { } +/** + * Represents a Color uniform. + * + * @private + * @augments Uniform + */ class ColorUniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Color} value - The uniform's value. + */ constructor( name, value = new Color() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isColorUniform = true; this.boundary = 16; @@ -29068,12 +39351,31 @@ class ColorUniform extends Uniform { } +/** + * Represents a Matrix3 uniform. + * + * @private + * @augments Uniform + */ class Matrix3Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Matrix3} value - The uniform's value. + */ constructor( name, value = new Matrix3() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMatrix3Uniform = true; this.boundary = 48; @@ -29083,12 +39385,31 @@ class Matrix3Uniform extends Uniform { } +/** + * Represents a Matrix4 uniform. + * + * @private + * @augments Uniform + */ class Matrix4Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Matrix4} value - The uniform's value. + */ constructor( name, value = new Matrix4() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMatrix4Uniform = true; this.boundary = 64; @@ -29098,22 +39419,49 @@ class Matrix4Uniform extends Uniform { } +/** + * A special form of Number uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments NumberUniform + */ class NumberNodeUniform extends NumberUniform { + /** + * Constructs a new node-based Number uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Number} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29122,22 +39470,49 @@ class NumberNodeUniform extends NumberUniform { } +/** + * A special form of Vector2 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Vector2Uniform + */ class Vector2NodeUniform extends Vector2Uniform { + /** + * Constructs a new node-based Vector2 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Vector2} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29146,22 +39521,49 @@ class Vector2NodeUniform extends Vector2Uniform { } +/** + * A special form of Vector3 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Vector3Uniform + */ class Vector3NodeUniform extends Vector3Uniform { + /** + * Constructs a new node-based Vector3 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Vector3} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29170,22 +39572,49 @@ class Vector3NodeUniform extends Vector3Uniform { } +/** + * A special form of Vector4 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Vector4Uniform + */ class Vector4NodeUniform extends Vector4Uniform { + /** + * Constructs a new node-based Vector4 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Vector4} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29194,22 +39623,49 @@ class Vector4NodeUniform extends Vector4Uniform { } +/** + * A special form of Color uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments ColorUniform + */ class ColorNodeUniform extends ColorUniform { + /** + * Constructs a new node-based Color uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Color} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29218,22 +39674,49 @@ class ColorNodeUniform extends ColorUniform { } +/** + * A special form of Matrix3 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Matrix3Uniform + */ class Matrix3NodeUniform extends Matrix3Uniform { + /** + * Constructs a new node-based Matrix3 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Matrix3} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29242,22 +39725,49 @@ class Matrix3NodeUniform extends Matrix3Uniform { } +/** + * A special form of Matrix4 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Matrix4Uniform + */ class Matrix4NodeUniform extends Matrix4Uniform { + /** + * Constructs a new node-based Matrix4 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Matrix4} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29370,6 +39880,7 @@ class PMREMGenerator { * @param {Number} [far=100] - The far plane distance. * @param {RenderTarget?} [renderTarget=null] - The render target to use. * @return {RenderTarget} The resulting PMREM. + * @see fromSceneAsync */ fromScene( scene, sigma = 0, near = 0.1, far = 100, renderTarget = null ) { @@ -29410,6 +39921,21 @@ class PMREMGenerator { } + /** + * 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). + * + * @param {Scene} scene - The scene to be captured. + * @param {Number} [sigma=0] - The blur radius in radians. + * @param {Number} [near=0.1] - The near plane distance. + * @param {Number} [far=100] - The far plane distance. + * @param {RenderTarget?} [renderTarget=null] - The render target to use. + * @return {Promise} The resulting PMREM. + * @see fromScene + */ async fromSceneAsync( scene, sigma = 0, near = 0.1, far = 100, renderTarget = null ) { if ( this._hasInitialized === false ) await this._renderer.init(); @@ -29426,6 +39952,7 @@ class PMREMGenerator { * @param {Texture} equirectangular - The equirectangular texture to be converted. * @param {RenderTarget?} [renderTarget=null] - The render target to use. * @return {RenderTarget} The resulting PMREM. + * @see fromEquirectangularAsync */ fromEquirectangular( equirectangular, renderTarget = null ) { @@ -29447,6 +39974,16 @@ class PMREMGenerator { } + /** + * 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. + * + * @param {Texture} equirectangular - The equirectangular texture to be converted. + * @param {RenderTarget?} [renderTarget=null] - The render target to use. + * @return {Promise} The resulting PMREM. + * @see fromEquirectangular + */ async fromEquirectangularAsync( equirectangular, renderTarget = null ) { if ( this._hasInitialized === false ) await this._renderer.init(); @@ -29463,6 +40000,7 @@ class PMREMGenerator { * @param {Texture} cubemap - The cubemap texture to be converted. * @param {RenderTarget?} [renderTarget=null] - The render target to use. * @return {RenderTarget} The resulting PMREM. + * @see fromCubemapAsync */ fromCubemap( cubemap, renderTarget = null ) { @@ -29484,6 +40022,16 @@ class PMREMGenerator { } + /** + * Generates a PMREM from an cubemap texture, which can be either LDR + * or HDR. The ideal input cube size is 256 x 256, + * with the 256 x 256 cubemap output. + * + * @param {Texture} cubemap - The cubemap texture to be converted. + * @param {RenderTarget?} [renderTarget=null] - The render target to use. + * @return {Promise} The resulting PMREM. + * @see fromCubemap + */ async fromCubemapAsync( cubemap, renderTarget = null ) { if ( this._hasInitialized === false ) await this._renderer.init(); @@ -29495,6 +40043,8 @@ class PMREMGenerator { /** * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during * your texture's network fetch for increased concurrency. + * + * @returns {Promise} */ async compileCubemapShader() { @@ -29510,6 +40060,8 @@ class PMREMGenerator { /** * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during * your texture's network fetch for increased concurrency. + * + * @returns {Promise} */ async compileEquirectangularShader() { @@ -30563,6 +41115,15 @@ class NodeBuilder { } + /** + * Returns the output struct name which is required by + * {@link module:OutputStructNode}. + * + * @abstract + * @return {String} The name of the output struct. + */ + getOutputStructName() {} + /** * Returns a bind group for the given group name and binding. * @@ -30744,6 +41305,7 @@ class NodeBuilder { /** * It is used to add Nodes that will be used as FRAME and RENDER events, * and need to follow a certain sequence in the calls to work correctly. + * This function should be called after 'setup()' in the 'build()' process to ensure that the child nodes are processed first. * * @param {Node} node - The node to add. */ @@ -31097,10 +41659,11 @@ class NodeBuilder { * @param {Texture} texture - The texture. * @param {String} textureProperty - The texture property name. * @param {String} uvSnippet - Snippet defining the texture coordinates. + * @param {String?} depthSnippet - Snippet defining the 0-based texture array index to sample. * @param {String} levelSnippet - Snippet defining the mip level. * @return {String} The generated shader string. */ - generateTextureLod( /* texture, textureProperty, uvSnippet, levelSnippet */ ) { + generateTextureLod( /* texture, textureProperty, uvSnippet, depthSnippet, levelSnippet */ ) { console.warn( 'Abstract function.' ); @@ -31274,11 +41837,11 @@ class NodeBuilder { } /** - * Whether the given texture needs a conversion to working color space. + * Checks if the given texture requires a manual conversion to the working color space. * * @abstract * @param {Texture} texture - The texture to check. - * @return {Boolean} Whether a color space conversion is required or not. + * @return {Boolean} Whether the given texture requires a conversion to working color space or not. */ needsToWorkingColorSpace( /*texture*/ ) { @@ -31657,9 +42220,11 @@ class NodeBuilder { * @param {String?} name - The variable's name. * @param {String} [type=node.getNodeType( this )] - The variable's type. * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage. + * @param {Boolean} [readOnly=false] - Whether the variable is read-only or not. + * * @return {NodeVar} The node variable. */ - getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage ) { + getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage, readOnly = false ) { const nodeData = this.getDataFromNode( node, shaderStage ); @@ -31667,13 +42232,26 @@ class NodeBuilder { if ( nodeVar === undefined ) { + const idNS = readOnly ? '_const' : '_var'; + const vars = this.vars[ shaderStage ] || ( this.vars[ shaderStage ] = [] ); + const id = this.vars[ idNS ] || ( this.vars[ idNS ] = 0 ); - if ( name === null ) name = 'nodeVar' + vars.length; + if ( name === null ) { - nodeVar = new NodeVar( name, type ); + name = ( readOnly ? 'nodeConst' : 'nodeVar' ) + id; - vars.push( nodeVar ); + this.vars[ idNS ] ++; + + } + + nodeVar = new NodeVar( name, type, readOnly ); + + if ( ! readOnly ) { + + vars.push( nodeVar ); + + } nodeData.variable = nodeVar; @@ -31683,6 +42261,35 @@ class NodeBuilder { } + /** + * Returns whether a Node or its flow is deterministic, useful for use in `const`. + * + * @param {Node} node - The varying node. + * @return {Boolean} Returns true if deterministic. + */ + isDeterministic( node ) { + + if ( node.isMathNode ) { + + return this.isDeterministic( node.aNode ) && + ( node.bNode ? this.isDeterministic( node.bNode ) : true ) && + ( node.cNode ? this.isDeterministic( node.cNode ) : true ); + + } else if ( node.isOperatorNode ) { + + return this.isDeterministic( node.aNode ) && + ( node.bNode ? this.isDeterministic( node.bNode ) : true ); + + } else if ( node.isConstNode ) { + + return true; + + } + + return false; + + } + /** * Returns an instance of {@link NodeVarying} for the given varying node. * @@ -32478,6 +43085,13 @@ class NodeBuilder { // deprecated + /** + * @function + * @deprecated since r168. Use `new NodeMaterial()` instead, with targeted node material name. + * + * @param {String} [type='NodeMaterial'] - The node material type. + * @throws {Error} + */ createNodeMaterial( type = 'NodeMaterial' ) { // @deprecated, r168 throw new Error( `THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${ type }() instead.` ); @@ -33043,14 +43657,14 @@ class SpotLightNode extends AnalyticLightNode { super( light ); /** - * Uniform node representing the cone cosinus. + * Uniform node representing the cone cosine. * * @type {UniformNode} */ this.coneCosNode = uniform( 0 ).setGroup( renderGroup ); /** - * Uniform node representing the penumbra cosinus. + * Uniform node representing the penumbra cosine. * * @type {UniformNode} */ @@ -33643,29 +44257,93 @@ class GLSLNodeParser extends NodeParser { } -const outputNodeMap = new WeakMap(); +const _outputNodeMap = new WeakMap(); +const _chainKeys$2 = []; +const _cacheKeyValues = []; +/** + * This renderer module manages node-related objects and is the + * primary interface between the renderer and the node system. + * + * @private + * @augments DataMap + */ class Nodes extends DataMap { + /** + * Constructs a new nodes management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Backend} backend - The renderer's backend. + */ constructor( renderer, backend ) { super(); + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * The node frame. + * + * @type {Renderer} + */ this.nodeFrame = new NodeFrame(); + + /** + * A cache for managing node builder states. + * + * @type {Map} + */ this.nodeBuilderCache = new Map(); + + /** + * A cache for managing data cache key data. + * + * @type {ChainMap} + */ this.callHashCache = new ChainMap(); + + /** + * A cache for managing node uniforms group data. + * + * @type {ChainMap} + */ this.groupsData = new ChainMap(); + /** + * A cache for managing node objects of + * scene properties like fog or environments. + * + * @type {Object} + */ + this.cacheLib = {}; + } + /** + * Returns `true` if the given node uniforms group must be updated or not. + * + * @param {NodeUniformsGroup} nodeUniformsGroup - The node uniforms group. + * @return {Boolean} Whether the node uniforms group requires an update or not. + */ updateGroup( nodeUniformsGroup ) { const groupNode = nodeUniformsGroup.groupNode; const name = groupNode.name; - // objectGroup is every updated + // objectGroup is always updated if ( name === objectGroup.name ) return true; @@ -33709,10 +44387,13 @@ class Nodes extends DataMap { // other groups are updated just when groupNode.needsUpdate is true - const groupChain = [ groupNode, nodeUniformsGroup ]; + _chainKeys$2[ 0 ] = groupNode; + _chainKeys$2[ 1 ] = nodeUniformsGroup; - let groupData = this.groupsData.get( groupChain ); - if ( groupData === undefined ) this.groupsData.set( groupChain, groupData = {} ); + let groupData = this.groupsData.get( _chainKeys$2 ); + if ( groupData === undefined ) this.groupsData.set( _chainKeys$2, groupData = {} ); + + _chainKeys$2.length = 0; if ( groupData.version !== groupNode.version ) { @@ -33726,12 +44407,24 @@ class Nodes extends DataMap { } + /** + * Returns the cache key for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Number} The cache key. + */ getForRenderCacheKey( renderObject ) { return renderObject.initialCacheKey; } + /** + * Returns a node builder state for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {NodeBuilderState} The node builder state. + */ getForRender( renderObject ) { const renderObjectData = this.get( renderObject ); @@ -33775,6 +44468,12 @@ class Nodes extends DataMap { } + /** + * Deletes the given object from the internal data map + * + * @param {Any} object - The object to delete. + * @return {Object?} The deleted dictionary. + */ delete( object ) { if ( object.isRenderObject ) { @@ -33794,6 +44493,12 @@ class Nodes extends DataMap { } + /** + * Returns a node builder state for the given compute node. + * + * @param {Node} computeNode - The compute node. + * @return {NodeBuilderState} The node builder state. + */ getForCompute( computeNode ) { const computeData = this.get( computeNode ); @@ -33815,6 +44520,13 @@ class Nodes extends DataMap { } + /** + * Creates a node builder state for the given node builder. + * + * @private + * @param {NodeBuilder} nodeBuilder - The node builder. + * @return {NodeBuilderState} The node builder state. + */ _createNodeBuilderState( nodeBuilder ) { return new NodeBuilderState( @@ -33832,71 +44544,149 @@ class Nodes extends DataMap { } + /** + * Returns an environment node for the current configured + * scene environment. + * + * @param {Scene} scene - The scene. + * @return {Node} A node representing the current scene environment. + */ getEnvironmentNode( scene ) { - return scene.environmentNode || this.get( scene ).environmentNode || null; + this.updateEnvironment( scene ); + + let environmentNode = null; + + if ( scene.environmentNode && scene.environmentNode.isNode ) { + + environmentNode = scene.environmentNode; + + } else { + + const sceneData = this.get( scene ); + + if ( sceneData.environmentNode ) { + + environmentNode = sceneData.environmentNode; + + } + + } + + return environmentNode; } + /** + * Returns a background node for the current configured + * scene background. + * + * @param {Scene} scene - The scene. + * @return {Node} A node representing the current scene background. + */ getBackgroundNode( scene ) { - return scene.backgroundNode || this.get( scene ).backgroundNode || null; + this.updateBackground( scene ); + + let backgroundNode = null; + + if ( scene.backgroundNode && scene.backgroundNode.isNode ) { + + backgroundNode = scene.backgroundNode; + + } else { + + const sceneData = this.get( scene ); + + if ( sceneData.backgroundNode ) { + + backgroundNode = sceneData.backgroundNode; + + } + + } + + return backgroundNode; } + /** + * Returns a fog node for the current configured scene fog. + * + * @param {Scene} scene - The scene. + * @return {Node} A node representing the current scene fog. + */ getFogNode( scene ) { + this.updateFog( scene ); + return scene.fogNode || this.get( scene ).fogNode || null; } + /** + * Returns a cache key for the given scene and lights node. + * This key is used by `RenderObject` as a part of the dynamic + * cache key (a key that must be checked every time the render + * objects is drawn). + * + * @param {Scene} scene - The scene. + * @param {LightsNode} lightsNode - The lights node. + * @return {Number} The cache key. + */ getCacheKey( scene, lightsNode ) { - const chain = [ scene, lightsNode ]; + _chainKeys$2[ 0 ] = scene; + _chainKeys$2[ 1 ] = lightsNode; + const callId = this.renderer.info.calls; - let cacheKeyData = this.callHashCache.get( chain ); + const cacheKeyData = this.callHashCache.get( _chainKeys$2 ) || {}; - if ( cacheKeyData === undefined || cacheKeyData.callId !== callId ) { + if ( cacheKeyData.callId !== callId ) { const environmentNode = this.getEnvironmentNode( scene ); const fogNode = this.getFogNode( scene ); - const values = []; + if ( lightsNode ) _cacheKeyValues.push( lightsNode.getCacheKey( true ) ); + if ( environmentNode ) _cacheKeyValues.push( environmentNode.getCacheKey() ); + if ( fogNode ) _cacheKeyValues.push( fogNode.getCacheKey() ); - if ( lightsNode ) values.push( lightsNode.getCacheKey( true ) ); - if ( environmentNode ) values.push( environmentNode.getCacheKey() ); - if ( fogNode ) values.push( fogNode.getCacheKey() ); + _cacheKeyValues.push( this.renderer.shadowMap.enabled ? 1 : 0 ); - values.push( this.renderer.shadowMap.enabled ? 1 : 0 ); + cacheKeyData.callId = callId; + cacheKeyData.cacheKey = hashArray( _cacheKeyValues ); - cacheKeyData = { - callId, - cacheKey: hashArray( values ) - }; + this.callHashCache.set( _chainKeys$2, cacheKeyData ); - this.callHashCache.set( chain, cacheKeyData ); + _cacheKeyValues.length = 0; } - return cacheKeyData.cacheKey; - - } - - updateScene( scene ) { + _chainKeys$2.length = 0; - this.updateEnvironment( scene ); - this.updateFog( scene ); - this.updateBackground( scene ); + return cacheKeyData.cacheKey; } + /** + * A boolean that indicates whether tone mapping should be enabled + * or not. + * + * @type {Boolean} + */ get isToneMappingState() { return this.renderer.getRenderTarget() ? false : true; } + /** + * If a scene background is configured, this method makes sure to + * represent the background with a corresponding node-based implementation. + * + * @param {Scene} scene - The scene. + */ updateBackground( scene ) { const sceneData = this.get( scene ); @@ -33908,41 +44698,43 @@ class Nodes extends DataMap { if ( sceneData.background !== background || forceUpdate ) { - let backgroundNode = null; + const backgroundNode = this.getCacheNode( 'background', background, () => { - if ( background.isCubeTexture === true || ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping || background.mapping === CubeUVReflectionMapping ) ) { + if ( background.isCubeTexture === true || ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping || background.mapping === CubeUVReflectionMapping ) ) { - if ( scene.backgroundBlurriness > 0 || background.mapping === CubeUVReflectionMapping ) { + if ( scene.backgroundBlurriness > 0 || background.mapping === CubeUVReflectionMapping ) { - backgroundNode = pmremTexture( background ); + return pmremTexture( background ); - } else { + } else { - let envMap; + let envMap; - if ( background.isCubeTexture === true ) { + if ( background.isCubeTexture === true ) { - envMap = cubeTexture( background ); + envMap = cubeTexture( background ); - } else { + } else { - envMap = texture( background ); + envMap = texture( background ); - } + } - backgroundNode = cubeMapNode( envMap ); + return cubeMapNode( envMap ); - } + } - } else if ( background.isTexture === true ) { + } else if ( background.isTexture === true ) { - backgroundNode = texture( background, screenUV.flipY() ).setUpdateMatrix( true ); + return texture( background, screenUV.flipY() ).setUpdateMatrix( true ); - } else if ( background.isColor !== true ) { + } else if ( background.isColor !== true ) { - console.error( 'WebGPUNodes: Unsupported background configuration.', background ); + console.error( 'WebGPUNodes: Unsupported background configuration.', background ); - } + } + + }, forceUpdate ); sceneData.backgroundNode = backgroundNode; sceneData.background = background; @@ -33959,40 +44751,75 @@ class Nodes extends DataMap { } + /** + * This method is part of the caching of nodes which are used to represents the + * scene's background, fog or environment. + * + * @param {String} type - The type of object to cache. + * @param {Object} object - The object. + * @param {Function} callback - A callback that produces a node representation for the given object. + * @param {Boolean} [forceUpdate=false] - Whether an update should be enforced or not. + * @return {Node} The node representation. + */ + getCacheNode( type, object, callback, forceUpdate = false ) { + + const nodeCache = this.cacheLib[ type ] || ( this.cacheLib[ type ] = new WeakMap() ); + + let node = nodeCache.get( object ); + + if ( node === undefined || forceUpdate ) { + + node = callback(); + nodeCache.set( object, node ); + + } + + return node; + + } + + /** + * If a scene fog is configured, this method makes sure to + * represent the fog with a corresponding node-based implementation. + * + * @param {Scene} scene - The scene. + */ updateFog( scene ) { const sceneData = this.get( scene ); - const fog = scene.fog; + const sceneFog = scene.fog; - if ( fog ) { + if ( sceneFog ) { - if ( sceneData.fog !== fog ) { + if ( sceneData.fog !== sceneFog ) { - let fogNode = null; + const fogNode = this.getCacheNode( 'fog', sceneFog, () => { - if ( fog.isFogExp2 ) { + if ( sceneFog.isFogExp2 ) { - const color = reference( 'color', 'color', fog ).setGroup( renderGroup ); - const density = reference( 'density', 'float', fog ).setGroup( renderGroup ); + const color = reference( 'color', 'color', sceneFog ).setGroup( renderGroup ); + const density = reference( 'density', 'float', sceneFog ).setGroup( renderGroup ); - fogNode = densityFog( color, density ); + return fog( color, densityFogFactor( density ) ); - } else if ( fog.isFog ) { + } else if ( sceneFog.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 ); + const color = reference( 'color', 'color', sceneFog ).setGroup( renderGroup ); + const near = reference( 'near', 'float', sceneFog ).setGroup( renderGroup ); + const far = reference( 'far', 'float', sceneFog ).setGroup( renderGroup ); - fogNode = rangeFog( color, near, far ); + return fog( color, rangeFogFactor( near, far ) ); - } else { + } else { - console.error( 'WebGPUNodes: Unsupported fog configuration.', fog ); + console.error( 'THREE.Renderer: Unsupported fog configuration.', sceneFog ); - } + } + + } ); sceneData.fogNode = fogNode; - sceneData.fog = fog; + sceneData.fog = sceneFog; } @@ -34005,6 +44832,12 @@ class Nodes extends DataMap { } + /** + * If a scene environment is configured, this method makes sure to + * represent the environment with a corresponding node-based implementation. + * + * @param {Scene} scene - The scene. + */ updateEnvironment( scene ) { const sceneData = this.get( scene ); @@ -34014,21 +44847,23 @@ class Nodes extends DataMap { if ( sceneData.environment !== environment ) { - let environmentNode = null; + const environmentNode = this.getCacheNode( 'environment', environment, () => { - if ( environment.isCubeTexture === true ) { + if ( environment.isCubeTexture === true ) { - environmentNode = cubeTexture( environment ); + return cubeTexture( environment ); - } else if ( environment.isTexture === true ) { + } else if ( environment.isTexture === true ) { - environmentNode = texture( environment ); + return texture( environment ); - } else { + } else { - console.error( 'Nodes: Unsupported environment configuration.', environment ); + console.error( 'Nodes: Unsupported environment configuration.', environment ); - } + } + + } ); sceneData.environmentNode = environmentNode; sceneData.environment = environment; @@ -34063,6 +44898,11 @@ class Nodes extends DataMap { } + /** + * Returns the current output cache key. + * + * @return {String} The output cache key. + */ getOutputCacheKey() { const renderer = this.renderer; @@ -34071,27 +44911,47 @@ class Nodes extends DataMap { } + /** + * Checks if the output configuration (tone mapping and color space) for + * the given target has changed. + * + * @param {Texture} outputTarget - The output target. + * @return {Boolean} Whether the output configuration has changed or not. + */ hasOutputChange( outputTarget ) { - const cacheKey = outputNodeMap.get( outputTarget ); + const cacheKey = _outputNodeMap.get( outputTarget ); return cacheKey !== this.getOutputCacheKey(); } - getOutputNode( outputTexture ) { + /** + * Returns a node that represents the output configuration (tone mapping and + * color space) for the current target. + * + * @param {Texture} outputTarget - The output target. + * @return {Node} The output node. + */ + getOutputNode( outputTarget ) { const renderer = this.renderer; const cacheKey = this.getOutputCacheKey(); - const output = texture( outputTexture, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); + const output = texture( outputTarget, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); - outputNodeMap.set( outputTexture, cacheKey ); + _outputNodeMap.set( outputTarget, cacheKey ); return output; } + /** + * Triggers the call of `updateBefore()` methods + * for all nodes of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateBefore( renderObject ) { const nodeBuilder = renderObject.getNodeBuilderState(); @@ -34106,6 +44966,12 @@ class Nodes extends DataMap { } + /** + * Triggers the call of `updateAfter()` methods + * for all nodes of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateAfter( renderObject ) { const nodeBuilder = renderObject.getNodeBuilderState(); @@ -34120,6 +44986,12 @@ class Nodes extends DataMap { } + /** + * Triggers the call of `update()` methods + * for all nodes of the given compute node. + * + * @param {Node} computeNode - The compute node. + */ updateForCompute( computeNode ) { const nodeFrame = this.getNodeFrame(); @@ -34133,6 +45005,12 @@ class Nodes extends DataMap { } + /** + * Triggers the call of `update()` methods + * for all nodes of the given compute node. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { const nodeFrame = this.getNodeFrameForRender( renderObject ); @@ -34146,6 +45024,12 @@ class Nodes extends DataMap { } + /** + * Returns `true` if the given render object requires a refresh. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object requires a refresh or not. + */ needsRefresh( renderObject ) { const nodeFrame = this.getNodeFrameForRender( renderObject ); @@ -34155,12 +45039,16 @@ class Nodes extends DataMap { } + /** + * Frees the internal resources. + */ dispose() { super.dispose(); this.nodeFrame = new NodeFrame(); this.nodeBuilderCache = new Map(); + this.cacheLib = {}; } @@ -34168,41 +45056,110 @@ class Nodes extends DataMap { const _plane = /*@__PURE__*/ new Plane(); +/** + * Represents the state that is used to perform clipping via clipping planes. + * There is a default clipping context for each render context. When the + * scene holds instances of `ClippingGroup`, there will be a context for each + * group. + * + * @private + */ class ClippingContext { + /** + * Constructs a new clipping context. + * + * @param {ClippingContext?} [parentContext=null] - A reference to the parent clipping context. + */ constructor( parentContext = null ) { + /** + * The clipping context's version. + * + * @type {Number} + * @readonly + */ this.version = 0; + /** + * Whether the intersection of the clipping planes is used to clip objects, rather than their union. + * + * @type {Boolean?} + * @default null + */ this.clipIntersection = null; + + /** + * The clipping context's cache key. + * + * @type {String} + */ this.cacheKey = ''; + /** + * Whether the shadow pass is active or not. + * + * @type {Boolean} + * @default false + */ + this.shadowPass = false; + + /** + * The view normal matrix. + * + * @type {Matrix3} + */ + this.viewNormalMatrix = new Matrix3(); - if ( parentContext === null ) { + /** + * Internal cache for maintaining clipping contexts. + * + * @type {WeakMap} + */ + this.clippingGroupContexts = new WeakMap(); - this.intersectionPlanes = []; - this.unionPlanes = []; + /** + * The intersection planes. + * + * @type {Array} + */ + this.intersectionPlanes = []; - this.viewNormalMatrix = new Matrix3(); - this.clippingGroupContexts = new WeakMap(); + /** + * The intersection planes. + * + * @type {Array} + */ + this.unionPlanes = []; - this.shadowPass = false; + /** + * The version of the clipping context's parent context. + * + * @type {Number?} + * @readonly + */ + this.parentVersion = null; - } else { + if ( parentContext !== null ) { this.viewNormalMatrix = parentContext.viewNormalMatrix; this.clippingGroupContexts = parentContext.clippingGroupContexts; this.shadowPass = parentContext.shadowPass; - this.viewMatrix = parentContext.viewMatrix; } - this.parentVersion = null; - } + /** + * Projects the given source clipping planes and writes the result into the + * destination array. + * + * @param {Array} source - The source clipping planes. + * @param {Array} destination - The destination. + * @param {Number} offset - The offset. + */ projectPlanes( source, destination, offset ) { const l = source.length; @@ -34223,15 +45180,27 @@ class ClippingContext { } + /** + * Updates the root clipping context of a scene. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera that is used to render the scene. + */ updateGlobal( scene, camera ) { - this.shadowPass = ( scene.overrideMaterial !== null && scene.overrideMaterial.isShadowNodeMaterial ); + this.shadowPass = ( scene.overrideMaterial !== null && scene.overrideMaterial.isShadowPassMaterial ); this.viewMatrix = camera.matrixWorldInverse; this.viewNormalMatrix.getNormalMatrix( this.viewMatrix ); } + /** + * Updates the clipping context. + * + * @param {ClippingContext} parentContext - The parent context. + * @param {ClippingGroup} clippingGroup - The clipping group this context belongs to. + */ update( parentContext, clippingGroup ) { let update = false; @@ -34303,6 +45272,12 @@ class ClippingContext { } + /** + * Returns a clipping context for the given clipping group. + * + * @param {ClippingGroup} clippingGroup - The clipping group. + * @return {ClippingContext} The clipping context. + */ getGroupContext( clippingGroup ) { if ( this.shadowPass && ! clippingGroup.clipShadows ) return this; @@ -34322,6 +45297,12 @@ class ClippingContext { } + /** + * The count of union clipping planes. + * + * @type {Number} + * @readonly + */ get unionClippingCount() { return this.unionPlanes.length; @@ -34330,67 +45311,141 @@ class ClippingContext { } +/** + * This module is used to represent render bundles inside the renderer + * for further processing. + * + * @private + */ class RenderBundle { - constructor( scene, camera ) { + /** + * Constructs a new bundle group. + * + * @param {BundleGroup} bundleGroup - The bundle group. + * @param {Camera} camera - The camera the bundle group is rendered with. + */ + constructor( bundleGroup, camera ) { - this.scene = scene; + this.bundleGroup = bundleGroup; this.camera = camera; } - clone() { - - return Object.assign( new this.constructor(), this ); - - } - } +const _chainKeys$1 = []; + +/** + * This renderer module manages render bundles. + * + * @private + */ class RenderBundles { + /** + * Constructs a new render bundle management component. + */ constructor() { - this.lists = new ChainMap(); + /** + * A chain map for maintaining the render bundles. + * + * @type {ChainMap} + */ + this.bundles = new ChainMap(); } - get( scene, camera ) { + /** + * Returns a render bundle for the given bundle group and camera. + * + * @param {BundleGroup} bundleGroup - The bundle group. + * @param {Camera} camera - The camera the bundle group is rendered with. + * @return {RenderBundle} The render bundle. + */ + get( bundleGroup, camera ) { - const lists = this.lists; - const keys = [ scene, camera ]; + const bundles = this.bundles; - let list = lists.get( keys ); + _chainKeys$1[ 0 ] = bundleGroup; + _chainKeys$1[ 1 ] = camera; - if ( list === undefined ) { + let bundle = bundles.get( _chainKeys$1 ); + + if ( bundle === undefined ) { - list = new RenderBundle( scene, camera ); - lists.set( keys, list ); + bundle = new RenderBundle( bundleGroup, camera ); + bundles.set( _chainKeys$1, bundle ); } - return list; + _chainKeys$1.length = 0; + + return bundle; } + /** + * Frees all internal resources. + */ dispose() { - this.lists = new ChainMap(); + this.bundles = new ChainMap(); } } +/** + * The purpose of a node library is to assign node implementations + * to existing library features. In `WebGPURenderer` lights, materials + * which are not based on `NodeMaterial` as well as tone mapping techniques + * are implemented with node-based modules. + * + * @private + */ class NodeLibrary { + /** + * Constructs a new node library. + */ constructor() { + /** + * A weak map that maps lights to light nodes. + * + * @type {WeakMap} + */ this.lightNodes = new WeakMap(); + + /** + * A map that maps materials to node materials. + * + * @type {WeakMap} + */ this.materialNodes = new Map(); + + /** + * A map that maps tone mapping techniques (constants) + * to tone mapping node functions. + * + * @type {WeakMap} + */ this.toneMappingNodes = new Map(); } + /** + * Returns a matching node material instance for the given material object. + * + * This method also assigns/copies the properties of the given material object + * to the node material. This is done to make sure the current material + * configuration carries over to the node version. + * + * @param {Material} material - A material. + * @return {NodeMaterial} The corresponding node material. + */ fromMaterial( material ) { if ( material.isNodeMaterial ) return material; @@ -34415,42 +45470,85 @@ class NodeLibrary { } + /** + * Adds a tone mapping node function for a tone mapping technique (constant). + * + * @param {Function} toneMappingNode - The tone mapping node function. + * @param {Number} toneMapping - The tone mapping. + */ addToneMapping( toneMappingNode, toneMapping ) { this.addType( toneMappingNode, toneMapping, this.toneMappingNodes ); } + /** + * Returns a tone mapping node function for a tone mapping technique (constant). + * + * @param {Number} toneMapping - The tone mapping. + * @return {Function?} The tone mapping node function. Returns `null` if no node function is found. + */ getToneMappingFunction( toneMapping ) { return this.toneMappingNodes.get( toneMapping ) || null; } + /** + * Returns a node material class definition for a material type. + * + * @param {String} materialType - The material type. + * @return {NodeMaterial.constructor?} The node material class definition. Returns `null` if no node material is found. + */ getMaterialNodeClass( materialType ) { return this.materialNodes.get( materialType ) || null; } + /** + * Adds a node material class definition for a given material type. + * + * @param {NodeMaterial.constructor} materialNodeClass - The node material class definition. + * @param {String} materialClassType - The material type. + */ addMaterial( materialNodeClass, materialClassType ) { this.addType( materialNodeClass, materialClassType, this.materialNodes ); } + /** + * Returns a light node class definition for a light class definition. + * + * @param {Light.constructor} light - The light class definition. + * @return {AnalyticLightNode.constructor?} The light node class definition. Returns `null` if no light node is found. + */ getLightNodeClass( light ) { return this.lightNodes.get( light ) || null; } + /** + * Adds a light node class definition for a given light class definition. + * + * @param {AnalyticLightNode.constructor} lightNodeClass - The light node class definition. + * @param {Light.constructor} lightClass - The light class definition. + */ addLight( lightNodeClass, lightClass ) { this.addClass( lightNodeClass, lightClass, this.lightNodes ); } + /** + * Adds a node class definition for the given type to the provided type library. + * + * @param {Any} nodeClass - The node class definition. + * @param {String} type - The object type. + * @param {Map} library - The type library. + */ addType( nodeClass, type, library ) { if ( library.has( type ) ) { @@ -34467,6 +45565,13 @@ class NodeLibrary { } + /** + * Adds a node class definition for the given class definition to the provided type library. + * + * @param {Any} nodeClass - The node class definition. + * @param {Any} baseClass - The class definition. + * @param {WeakMap} library - The type library. + */ addClass( nodeClass, baseClass, library ) { if ( library.has( baseClass ) ) { @@ -34486,46 +45591,76 @@ class NodeLibrary { } const _defaultLights = /*@__PURE__*/ new LightsNode(); +const _chainKeys = []; +/** + * This renderer module manages the lights nodes which are unique + * per scene and camera combination. + * + * The lights node itself is later configured in the render list + * with the actual lights from the scene. + * + * @private + * @augments ChainMap + */ class Lighting extends ChainMap { + /** + * Constructs a lighting management component. + */ constructor() { super(); } + /** + * Creates a new lights node for the given array of lights. + * + * @param {Array} lights - The render object. + * @return {Boolean} Whether if the given render object has an initialized geometry or not. + */ createNode( lights = [] ) { return new LightsNode().setLights( lights ); } + /** + * Returns a lights node for the given scene and camera. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera. + * @return {LightsNode} The lights node. + */ getNode( scene, camera ) { // ignore post-processing if ( scene.isQuadMesh ) return _defaultLights; - // tiled lighting - - const keys = [ scene, camera ]; + _chainKeys[ 0 ] = scene; + _chainKeys[ 1 ] = camera; - let node = this.get( keys ); + let node = this.get( _chainKeys ); if ( node === undefined ) { node = this.createNode(); - this.set( keys, node ); + this.set( _chainKeys, node ); } + _chainKeys.length = 0; + return node; } } +/** @module Renderer **/ + const _scene = /*@__PURE__*/ new Scene(); const _drawingBufferSize = /*@__PURE__*/ new Vector2(); const _screen = /*@__PURE__*/ new Vector4(); @@ -34533,10 +45668,34 @@ const _frustum = /*@__PURE__*/ new Frustum(); const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); const _vector4 = /*@__PURE__*/ new Vector4(); +/** + * Base class for renderers. + */ class Renderer { + /** + * Constructs a new renderer. + * + * @param {Backend} backend - The backend the renderer is targeting (e.g. WebGPU or WebGL 2). + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. This parameter can set to any other integer value than 0 + * to overwrite the default. + * @param {Function?} [parameters.getFallback=null] - This callback function can be used to provide a fallback backend, if the primary backend can't be targeted. + */ constructor( backend, parameters = {} ) { + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isRenderer = true; // @@ -34551,32 +45710,142 @@ class Renderer { getFallback = null } = parameters; - // public + /** + * A reference to the canvas element the renderer is drawing to. + * This value of this property will automatically be created by + * the renderer. + * + * @type {HTMLCanvasElement|OffscreenCanvas} + */ this.domElement = backend.getDomElement(); + /** + * A reference to the current backend. + * + * @type {Backend} + */ this.backend = backend; + /** + * The number of MSAA samples. + * + * @type {Number} + * @default 0 + */ this.samples = samples || ( antialias === true ) ? 4 : 0; + /** + * Whether the renderer should automatically clear the current rendering target + * before execute a `render()` call. The target can be the canvas (default framebuffer) + * or the current bound render target (custom framebuffer). + * + * @type {Boolean} + * @default true + */ this.autoClear = true; + + /** + * When `autoClear` is set to `true`, this property defines whether the renderer + * should clear the color buffer. + * + * @type {Boolean} + * @default true + */ this.autoClearColor = true; + + /** + * When `autoClear` is set to `true`, this property defines whether the renderer + * should clear the depth buffer. + * + * @type {Boolean} + * @default true + */ this.autoClearDepth = true; + + /** + * When `autoClear` is set to `true`, this property defines whether the renderer + * should clear the stencil buffer. + * + * @type {Boolean} + * @default true + */ this.autoClearStencil = true; + /** + * Whether the default framebuffer should be transparent or opaque. + * + * @type {Boolean} + * @default true + */ this.alpha = alpha; + /** + * Whether logarithmic depth buffer is enabled or not. + * + * @type {Boolean} + * @default false + */ this.logarithmicDepthBuffer = logarithmicDepthBuffer; + /** + * Defines the output color space of the renderer. + * + * @type {String} + * @default SRGBColorSpace + */ this.outputColorSpace = SRGBColorSpace; + /** + * Defines the tone mapping of the renderer. + * + * @type {Number} + * @default NoToneMapping + */ this.toneMapping = NoToneMapping; + + /** + * Defines the tone mapping exposure. + * + * @type {Number} + * @default 1 + */ this.toneMappingExposure = 1.0; + /** + * Whether the renderer should sort its render lists or not. + * + * Note: Sorting is used to attempt to properly render objects that have some degree of transparency. + * By definition, sorting objects may not work in all cases. Depending on the needs of application, + * it may be necessary to turn off sorting and use other methods to deal with transparency rendering + * e.g. manually determining each object's rendering order. + * + * @type {Boolean} + * @default true + */ this.sortObjects = true; + /** + * Whether the default framebuffer should have a depth buffer or not. + * + * @type {Boolean} + * @default true + */ this.depth = depth; + + /** + * Whether the default framebuffer should have a stencil buffer or not. + * + * @type {Boolean} + * @default false + */ this.stencil = stencil; + /** + * Holds a series of statistical information about the GPU memory + * and the rendering process. Useful for debugging and monitoring. + * + * @type {Info} + */ this.info = new Info(); this.nodes = { @@ -34584,82 +45853,449 @@ class Renderer { modelNormalViewMatrix: null }; + /** + * The node library defines how certain library objects like materials, lights + * or tone mapping functions are mapped to node types. This is required since + * although instances of classes like `MeshBasicMaterial` or `PointLight` can + * be part of the scene graph, they are internally represented as nodes for + * further processing. + * + * @type {NodeLibrary} + */ this.library = new NodeLibrary(); + + /** + * A map-like data structure for managing lights. + * + * @type {Lighting} + */ this.lighting = new Lighting(); // internals + /** + * This callback function can be used to provide a fallback backend, if the primary backend can't be targeted. + * + * @private + * @type {Function} + */ this._getFallback = getFallback; + /** + * The renderer's pixel ration. + * + * @private + * @type {Number} + * @default 1 + */ this._pixelRatio = 1; + + /** + * The width of the renderer's default framebuffer in logical pixel unit. + * + * @private + * @type {Number} + */ this._width = this.domElement.width; + + /** + * The height of the renderer's default framebuffer in logical pixel unit. + * + * @private + * @type {Number} + */ this._height = this.domElement.height; + /** + * The viewport of the renderer in logical pixel unit. + * + * @private + * @type {Vector4} + */ this._viewport = new Vector4( 0, 0, this._width, this._height ); + + /** + * The scissor rectangle of the renderer in logical pixel unit. + * + * @private + * @type {Vector4} + */ this._scissor = new Vector4( 0, 0, this._width, this._height ); + + /** + * Whether the scissor test should be enabled or not. + * + * @private + * @type {Boolean} + */ this._scissorTest = false; + /** + * A reference to a renderer module for managing shader attributes. + * + * @private + * @type {Attributes?} + * @default null + */ this._attributes = null; + + /** + * A reference to a renderer module for managing geometries. + * + * @private + * @type {Geometries?} + * @default null + */ this._geometries = null; + + /** + * A reference to a renderer module for managing node related logic. + * + * @private + * @type {Nodes?} + * @default null + */ this._nodes = null; + + /** + * A reference to a renderer module for managing the internal animation loop. + * + * @private + * @type {Animation?} + * @default null + */ this._animation = null; + + /** + * A reference to a renderer module for managing shader program bindings. + * + * @private + * @type {Bindings?} + * @default null + */ this._bindings = null; + + /** + * A reference to a renderer module for managing render objects. + * + * @private + * @type {RenderObjects?} + * @default null + */ this._objects = null; + + /** + * A reference to a renderer module for managing render and compute pipelines. + * + * @private + * @type {Pipelines?} + * @default null + */ this._pipelines = null; + + /** + * A reference to a renderer module for managing render bundles. + * + * @private + * @type {RenderBundles?} + * @default null + */ this._bundles = null; + + /** + * A reference to a renderer module for managing render lists. + * + * @private + * @type {RenderLists?} + * @default null + */ this._renderLists = null; + + /** + * A reference to a renderer module for managing render contexts. + * + * @private + * @type {RenderContexts?} + * @default null + */ this._renderContexts = null; + + /** + * A reference to a renderer module for managing textures. + * + * @private + * @type {Textures?} + * @default null + */ this._textures = null; + + /** + * A reference to a renderer module for backgrounds. + * + * @private + * @type {Background?} + * @default null + */ this._background = null; + /** + * This fullscreen quad is used for internal render passes + * like the tone mapping and color space output pass. + * + * @private + * @type {QuadMesh} + */ this._quad = new QuadMesh( new NodeMaterial() ); - this._quad.material.type = 'Renderer_output'; + this._quad.material.name = 'Renderer_output'; + /** + * A reference to the current render context. + * + * @private + * @type {RenderContext?} + * @default null + */ this._currentRenderContext = null; + /** + * A custom sort function for the opaque render list. + * + * @private + * @type {Function?} + * @default null + */ this._opaqueSort = null; + + /** + * A custom sort function for the transparent render list. + * + * @private + * @type {Function?} + * @default null + */ this._transparentSort = null; + /** + * The framebuffer target. + * + * @private + * @type {RenderTarget?} + * @default null + */ this._frameBufferTarget = null; const alphaClear = this.alpha === true ? 0 : 1; + /** + * The clear color value. + * + * @private + * @type {Color4} + */ this._clearColor = new Color4( 0, 0, 0, alphaClear ); + + /** + * The clear depth value. + * + * @private + * @type {Number} + * @default 1 + */ this._clearDepth = 1; + + /** + * The clear stencil value. + * + * @private + * @type {Number} + * @default 0 + */ this._clearStencil = 0; + /** + * The current render target. + * + * @private + * @type {RenderTarget?} + * @default null + */ this._renderTarget = null; + + /** + * The active cube face. + * + * @private + * @type {Number} + * @default 0 + */ this._activeCubeFace = 0; + + /** + * The active mipmap level. + * + * @private + * @type {Number} + * @default 0 + */ this._activeMipmapLevel = 0; + /** + * The MRT setting. + * + * @private + * @type {MRTNode?} + * @default null + */ this._mrt = null; + /** + * This function defines how a render object is going + * to be rendered. + * + * @private + * @type {Function?} + * @default null + */ this._renderObjectFunction = null; + + /** + * Used to keep track of the current render object function. + * + * @private + * @type {Function?} + * @default null + */ this._currentRenderObjectFunction = null; + + /** + * Used to keep track of the current render bundle. + * + * @private + * @type {RenderBundle?} + * @default null + */ this._currentRenderBundle = null; + /** + * Next to `_renderObjectFunction()`, this function provides another hook + * for influencing the render process of a render object. It is meant for internal + * use and only relevant for `compileAsync()` right now. Instead of using + * the default logic of `_renderObjectDirect()` which actually draws the render object, + * a different function might be used which performs no draw but just the node + * and pipeline updates. + * + * @private + * @type {Function?} + * @default null + */ this._handleObjectFunction = this._renderObjectDirect; + /** + * Indicates whether the device has been lost or not. In WebGL terms, the device + * lost is considered as a context lost. When this is set to `true`, rendering + * isn't possible anymore. + * + * @private + * @type {Boolean} + * @default false + */ this._isDeviceLost = false; + + /** + * A callback function that defines what should happen when a device/context lost occurs. + * + * @type {Function} + */ this.onDeviceLost = this._onDeviceLost; + /** + * Whether the renderer has been initialized or not. + * + * @private + * @type {Boolean} + * @default false + */ this._initialized = false; + + /** + * A reference to the promise which initializes the renderer. + * + * @private + * @type {Promise?} + * @default null + */ this._initPromise = null; + /** + * An array of compilation promises which are used in `compileAsync()`. + * + * @private + * @type {Array?} + * @default null + */ this._compilationPromises = null; + /** + * Whether the renderer should render transparent render objects or not. + * + * @type {Boolean} + * @default true + */ this.transparent = true; + + /** + * Whether the renderer should render opaque render objects or not. + * + * @type {Boolean} + * @default true + */ this.opaque = true; + /** + * Shadow map configuration + * @typedef {Object} ShadowMapConfig + * @property {Boolean} enabled - Whether to globally enable shadows or not. + * @property {Number} type - The shadow map type. + */ + + /** + * The renderer's shadow configuration. + * + * @type {module:Renderer~ShadowMapConfig} + */ this.shadowMap = { enabled: false, type: PCFShadowMap }; + /** + * XR configuration. + * @typedef {Object} XRConfig + * @property {Boolean} enabled - Whether to globally enable XR or not. + */ + + /** + * The renderer's XR configuration. + * + * @type {module:Renderer~XRConfig} + */ this.xr = { enabled: false }; + /** + * Debug configuration. + * @typedef {Object} DebugConfig + * @property {Boolean} checkShaderErrors - Whether shader errors should be checked or not. + * @property {Function} onShaderError - A callback function that is executed when a shader error happens. Only supported with WebGL 2 right now. + * @property {Function} getShaderAsync - Allows the get the raw shader code for the given scene, camera and 3D object. + */ + + /** + * The renderer's debug configuration. + * + * @type {module:Renderer~DebugConfig} + */ this.debug = { checkShaderErrors: true, onShaderError: null, @@ -34683,6 +46319,12 @@ class Renderer { } + /** + * Initializes the renderer so it is ready for usage. + * + * @async + * @return {Promise} A Promise that resolves when the renderer has been initialized. + */ async init() { if ( this._initialized ) { @@ -34758,12 +46400,35 @@ class Renderer { } + /** + * The coordinate system of the renderer. The value of this property + * depends on the selected backend. Either `THREE.WebGLCoordinateSystem` or + * `THREE.WebGPUCoordinateSystem`. + * + * @readonly + * @type {Number} + */ get coordinateSystem() { return this.backend.coordinateSystem; } + /** + * Compiles all materials in the given scene. This can be useful to avoid a + * phenomenon which is called "shader compilation stutter", which occurs when + * rendering an object with a new shader for the first time. + * + * If you want to add a 3D object to an existing scene, use the third optional + * parameter for applying the target scene. Note that the (target) scene's lighting + * and environment must be configured before calling this method. + * + * @async + * @param {Object3D} scene - The scene or 3D object to precompile. + * @param {Camera} camera - The camera that is used to render the scene. + * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. + * @return {Promise} A Promise that resolves when the compile has been finished. + */ async compileAsync( scene, camera, targetScene = null ) { if ( this._isDeviceLost === true ) return; @@ -34860,10 +46525,6 @@ class Renderer { // - this._nodes.updateScene( sceneRef ); - - // - this._background.update( sceneRef, renderList, renderContext ); // process render lists @@ -34892,6 +46553,14 @@ class Renderer { } + /** + * Renders the scene in an async fashion. + * + * @async + * @param {Object3D} scene - The scene or 3D object to render. + * @param {Camera} camera - The camera. + * @return {Promise} A Promise that resolves when the render has been finished. + */ async renderAsync( scene, camera ) { if ( this._initialized === false ) await this.init(); @@ -34902,12 +46571,25 @@ class Renderer { } + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ async waitForGPU() { await this.backend.waitForGPU(); } + /** + * Sets the given MRT configuration. + * + * @param {MRTNode} mrt - The MRT node to set. + * @return {Renderer} A reference to this renderer. + */ setMRT( mrt ) { this._mrt = mrt; @@ -34916,12 +46598,23 @@ class Renderer { } + /** + * Returns the MRT configuration. + * + * @return {MRTNode} The MRT configuration. + */ getMRT() { return this._mrt; } + /** + * Default implementation of the device lost callback. + * + * @private + * @param {Object} info - Information about the context lost. + */ _onDeviceLost( info ) { let errorMessage = `THREE.WebGPURenderer: ${info.api} Device Lost:\n\nMessage: ${info.message}`; @@ -34938,7 +46631,14 @@ class Renderer { } - + /** + * Renders the given render bundle. + * + * @private + * @param {Object} bundle - Render bundle data. + * @param {Scene} sceneRef - The scene the render bundle belongs to. + * @param {LightsNode} lightsNode - The current lights node. + */ _renderBundle( bundle, sceneRef, lightsNode ) { const { bundleGroup, camera, renderList } = bundle; @@ -35010,6 +46710,18 @@ class Renderer { } + /** + * Renders the scene or 3D object with the given camera. This method can only be called + * if the renderer has been initialized. + * + * The target of the method is the default framebuffer (meaning the canvas) + * or alternatively a render target when specified via `setRenderTarget()`. + * + * @param {Object3D} scene - The scene or 3D object to render. + * @param {Camera} camera - The camera to render the scene with. + * @return {Promise?} A Promise that resolve when the scene has been rendered. + * Only returned when the renderer has not been initialized. + */ render( scene, camera ) { if ( this._initialized === false ) { @@ -35024,6 +46736,14 @@ class Renderer { } + /** + * Returns an internal render target which is used when computing the output tone mapping + * and color space conversion. Unlike in `WebGLRenderer`, this is done in a separate render + * pass and not inline to achieve more correct results. + * + * @private + * @return {RenderTarget?} The render target. The method returns `null` if no output conversion should be applied. + */ _getFrameBufferTarget() { const { currentToneMapping, currentColorSpace } = this; @@ -35071,6 +46791,15 @@ class Renderer { } + /** + * Renders the scene or 3D object with the given camera. + * + * @private + * @param {Object3D} scene - The scene or 3D object to render. + * @param {Camera} camera - The camera to render the scene with. + * @param {Boolean} [useFrameBufferTarget=true] - Whether to use a framebuffer target or not. + * @return {RenderContext} The current render context. + */ _renderScene( scene, camera, useFrameBufferTarget = true ) { if ( this._isDeviceLost === true ) return; @@ -35236,10 +46965,6 @@ class Renderer { // - this._nodes.updateScene( sceneRef ); - - // - this._background.update( sceneRef, renderList, renderContext ); // @@ -35300,24 +47025,48 @@ class Renderer { } + /** + * Returns the maximum available anisotropy for texture filtering. + * + * @return {Number} The maximum available anisotropy. + */ getMaxAnisotropy() { return this.backend.getMaxAnisotropy(); } + /** + * Returns the active cube face. + * + * @return {Number} The active cube face. + */ getActiveCubeFace() { return this._activeCubeFace; } + /** + * Returns the active mipmap level. + * + * @return {Number} The active mipmap level. + */ getActiveMipmapLevel() { return this._activeMipmapLevel; } + /** + * Applications are advised to always define the animation loop + * with this method and not manually with `requestAnimationFrame()` + * for best compatibility. + * + * @async + * @param {Function} callback - The application's animation loop. + * @return {Promise} A Promise that resolves when the set has been executed. + */ async setAnimationLoop( callback ) { if ( this._initialized === false ) await this.init(); @@ -35326,36 +47075,71 @@ class Renderer { } + /** + * Can be used to transfer buffer data from a storage buffer attribute + * from the GPU to the CPU in context of compute shaders. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { return await this.backend.getArrayBufferAsync( attribute ); } + /** + * Returns the rendering context. + * + * @return {GPUCanvasContext|WebGL2RenderingContext} The rendering context. + */ getContext() { return this.backend.getContext(); } + /** + * Returns the pixel ratio. + * + * @return {Number} The pixel ratio. + */ getPixelRatio() { return this._pixelRatio; } + /** + * Returns the drawing buffer size in physical pixels. This method honors the pixel ratio. + * + * @param {Vector2} target - The method writes the result in this target object. + * @return {Vector2} The drawing buffer size. + */ getDrawingBufferSize( target ) { return target.set( this._width * this._pixelRatio, this._height * this._pixelRatio ).floor(); } + /** + * Returns the renderer's size in logical pixels. This method does not honor the pixel ratio. + * + * @param {Vector2} target - The method writes the result in this target object. + * @return {Vector2} The drawing buffer size. + */ getSize( target ) { return target.set( this._width, this._height ); } + /** + * Sets the given pixel ration and resizes the canvas if necessary. + * + * @param {Number} [value=1] - The pixel ratio. + */ setPixelRatio( value = 1 ) { if ( this._pixelRatio === value ) return; @@ -35366,6 +47150,19 @@ class Renderer { } + /** + * This method allows to define the drawing buffer size by specifying + * width, height and pixel ratio all at once. The size of the drawing + * buffer is computed with this formula: + * ```` + * size.x = width * pixelRatio; + * size.y = height * pixelRatio; + *``` + * + * @param {Number} width - The width in logical pixels. + * @param {Number} height - The height in logical pixels. + * @param {Number} pixelRatio - The pixel ratio. + */ setDrawingBufferSize( width, height, pixelRatio ) { this._width = width; @@ -35382,6 +47179,13 @@ class Renderer { } + /** + * Sets the size of the renderer. + * + * @param {Number} width - The width in logical pixels. + * @param {Number} height - The height in logical pixels. + * @param {Boolean} [updateStyle=true] - Whether to update the `style` attribute of the canvas or not. + */ setSize( width, height, updateStyle = true ) { this._width = width; @@ -35403,18 +47207,36 @@ class Renderer { } + /** + * Defines a manual sort function for the opaque render list. + * Pass `null` to use the default sort. + * + * @param {Function} method - The sort function. + */ setOpaqueSort( method ) { this._opaqueSort = method; } + /** + * Defines a manual sort function for the transparent render list. + * Pass `null` to use the default sort. + * + * @param {Function} method - The sort function. + */ setTransparentSort( method ) { this._transparentSort = method; } + /** + * Returns the scissor rectangle. + * + * @param {Vector4} target - The method writes the result in this target object. + * @return {Vector4} The scissor rectangle. + */ getScissor( target ) { const scissor = this._scissor; @@ -35428,6 +47250,15 @@ class Renderer { } + /** + * Defines the scissor rectangle. + * + * @param {Number | Vector4} x - The horizontal coordinate for the lower left corner of the box in logical pixel unit. + * Instead of passing four arguments, the method also works with a single four-dimensional vector. + * @param {Number} y - The vertical coordinate for the lower left corner of the box in logical pixel unit. + * @param {Number} width - The width of the scissor box in logical pixel unit. + * @param {Number} height - The height of the scissor box in logical pixel unit. + */ setScissor( x, y, width, height ) { const scissor = this._scissor; @@ -35444,12 +47275,22 @@ class Renderer { } + /** + * Returns the scissor test value. + * + * @return {Boolean} Whether the scissor test should be enabled or not. + */ getScissorTest() { return this._scissorTest; } + /** + * Defines the scissor test. + * + * @param {Boolean} boolean - Whether the scissor test should be enabled or not. + */ setScissorTest( boolean ) { this._scissorTest = boolean; @@ -35458,12 +47299,28 @@ class Renderer { } + /** + * Returns the viewport definition. + * + * @param {Vector4} target - The method writes the result in this target object. + * @return {Vector4} The viewport definition. + */ getViewport( target ) { return target.copy( this._viewport ); } + /** + * Defines the viewport. + * + * @param {Number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit. + * @param {Number} y - The vertical coordinate for the lower left corner of the viewport origin in logical pixel unit. + * @param {Number} width - The width of the viewport in logical pixel unit. + * @param {Number} height - The height of the viewport in logical pixel unit. + * @param {Number} minDepth - The minimum depth value of the viewport. WebGPU only. + * @param {Number} maxDepth - The maximum depth value of the viewport. WebGPU only. + */ setViewport( x, y, width, height, minDepth = 0, maxDepth = 1 ) { const viewport = this._viewport; @@ -35483,12 +47340,24 @@ class Renderer { } + /** + * Returns the clear color. + * + * @param {Color} target - The method writes the result in this target object. + * @return {Color} The clear color. + */ getClearColor( target ) { return target.copy( this._clearColor ); } + /** + * Defines the clear color and optionally the clear alpha. + * + * @param {Color} color - The clear color. + * @param {Number} [alpha=1] - The clear alpha. + */ setClearColor( color, alpha = 1 ) { this._clearColor.set( color ); @@ -35496,42 +47365,80 @@ class Renderer { } + /** + * Returns the clear alpha. + * + * @return {Number} The clear alpha. + */ getClearAlpha() { return this._clearColor.a; } + /** + * Defines the clear alpha. + * + * @param {Number} alpha - The clear alpha. + */ setClearAlpha( alpha ) { this._clearColor.a = alpha; } + /** + * Returns the clear depth. + * + * @return {Number} The clear depth. + */ getClearDepth() { return this._clearDepth; } + /** + * Defines the clear depth. + * + * @param {Number} depth - The clear depth. + */ setClearDepth( depth ) { this._clearDepth = depth; } + /** + * Returns the clear stencil. + * + * @return {Number} The clear stencil. + */ getClearStencil() { return this._clearStencil; } + /** + * Defines the clear stencil. + * + * @param {Number} stencil - The clear stencil. + */ setClearStencil( stencil ) { this._clearStencil = stencil; } + /** + * This method performs an occlusion query for the given 3D object. + * It returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. + * + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ isOccluded( object ) { const renderContext = this._currentRenderContext; @@ -35540,6 +47447,15 @@ class Renderer { } + /** + * Performs a manual clear operation. This method ignores `autoClear` properties. + * + * @param {Boolean} [color=true] - Whether the color buffer should be cleared or not. + * @param {Boolean} [depth=true] - Whether the depth buffer should be cleared or not. + * @param {Boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clear( color = true, depth = true, stencil = true ) { if ( this._initialized === false ) { @@ -35552,17 +47468,26 @@ class Renderer { const renderTarget = this._renderTarget || this._getFrameBufferTarget(); - let renderTargetData = null; + let renderContext = null; if ( renderTarget !== null ) { this._textures.updateRenderTarget( renderTarget ); - renderTargetData = this._textures.get( renderTarget ); + const renderTargetData = this._textures.get( renderTarget ); + + renderContext = this._renderContexts.getForClear( 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; } - this.backend.clear( color, depth, stencil, renderTargetData ); + this.backend.clear( color, depth, stencil, renderContext ); if ( renderTarget !== null && this._renderTarget === null ) { @@ -35584,24 +47509,51 @@ class Renderer { } + /** + * Performs a manual clear operation of the color buffer. This method ignores `autoClear` properties. + * + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clearColor() { return this.clear( true, false, false ); } + /** + * Performs a manual clear operation of the depth buffer. This method ignores `autoClear` properties. + * + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clearDepth() { return this.clear( false, true, false ); } + /** + * Performs a manual clear operation of the stencil buffer. This method ignores `autoClear` properties. + * + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clearStencil() { return this.clear( false, false, true ); } + /** + * Async version of {@link module:Renderer~Renderer#clear}. + * + * @async + * @param {Boolean} [color=true] - Whether the color buffer should be cleared or not. + * @param {Boolean} [depth=true] - Whether the depth buffer should be cleared or not. + * @param {Boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ async clearAsync( color = true, depth = true, stencil = true ) { if ( this._initialized === false ) await this.init(); @@ -35610,36 +47562,70 @@ class Renderer { } - clearColorAsync() { + /** + * Async version of {@link module:Renderer~Renderer#clearColor}. + * + * @async + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ + async clearColorAsync() { - return this.clearAsync( true, false, false ); + this.clearAsync( true, false, false ); } - clearDepthAsync() { + /** + * Async version of {@link module:Renderer~Renderer#clearDepth}. + * + * @async + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ + async clearDepthAsync() { - return this.clearAsync( false, true, false ); + this.clearAsync( false, true, false ); } - clearStencilAsync() { + /** + * Async version of {@link module:Renderer~Renderer#clearStencil}. + * + * @async + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ + async clearStencilAsync() { - return this.clearAsync( false, false, true ); + this.clearAsync( false, false, true ); } + /** + * The current output tone mapping of the renderer. When a render target is set, + * the output tone mapping is always `NoToneMapping`. + * + * @type {Number} + */ get currentToneMapping() { return this._renderTarget !== null ? NoToneMapping : this.toneMapping; } + /** + * The current output color space of the renderer. When a render target is set, + * the output color space is always `LinearSRGBColorSpace`. + * + * @type {String} + */ get currentColorSpace() { return this._renderTarget !== null ? LinearSRGBColorSpace : this.outputColorSpace; } + /** + * Frees all internal resources of the renderer. Call this method if the renderer + * is no longer in use by your app. + */ dispose() { this.info.dispose(); @@ -35659,6 +47645,15 @@ class Renderer { } + /** + * Sets the given render target. Calling this method means the renderer does not + * target the default framebuffer (meaning the canvas) anymore but a custom framebuffer. + * Use `null` as the first argument to reset the state. + * + * @param {RenderTarget?} renderTarget - The render target to set. + * @param {Number} [activeCubeFace=0] - The active cube face. + * @param {Number} [activeMipmapLevel=0] - The active mipmap level. + */ setRenderTarget( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { this._renderTarget = renderTarget; @@ -35667,27 +47662,70 @@ class Renderer { } + /** + * Returns the current render target. + * + * @return {RenderTarget?} The render target. Returns `null` if no render target is set. + */ getRenderTarget() { return this._renderTarget; } + /** + * Callback for {@link module:Renderer~Renderer#setRenderObjectFunction}. + * + * @callback renderObjectFunction + * @param {Object3D} object - The 3D object. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {BufferGeometry} geometry - The object's geometry. + * @param {Material} material - The object's material. + * @param {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {LightsNode} lightsNode - The current lights node. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ + + /** + * Sets the given render object function. Calling this method overwrites the default implementation + * which is {@link module:Renderer~Renderer#renderObject}. Defining a custom function can be useful + * if you want to modify the way objects are rendered. For example you can define things like "every + * object that has material of a certain type should perform a pre-pass with a special overwrite material". + * The custom function must always call `renderObject()` in its implementation. + * + * Use `null` as the first argument to reset the state. + * + * @param {module:Renderer~renderObjectFunction?} renderObjectFunction - The render object function. + */ setRenderObjectFunction( renderObjectFunction ) { this._renderObjectFunction = renderObjectFunction; } + /** + * Returns the current render object function. + * + * @return {Function?} The current render object function. Returns `null` if no function is set. + */ getRenderObjectFunction() { return this._renderObjectFunction; } + /** + * Execute a single or an array of compute nodes. This method can only be called + * if the renderer has been initialized. + * + * @param {Node|Array} computeNodes - The compute node(s). + * @return {Promise?} A Promise that resolve when the compute has finished. Only returned when the renderer has not been initialized. + */ compute( computeNodes ) { - if ( this.isDeviceLost === true ) return; + if ( this._isDeviceLost === true ) return; if ( this._initialized === false ) { @@ -35776,6 +47814,13 @@ class Renderer { } + /** + * Execute a single or an array of compute nodes. + * + * @async + * @param {Node|Array} computeNodes - The compute node(s). + * @return {Promise} A Promise that resolve when the compute has finished. + */ async computeAsync( computeNodes ) { if ( this._initialized === false ) await this.init(); @@ -35786,6 +47831,13 @@ class Renderer { } + /** + * Checks if the given feature is supported by the selected backend. + * + * @async + * @param {String} name - The feature's name. + * @return {Promise} A Promise that resolves with a bool that indicates whether the feature is supported or not. + */ async hasFeatureAsync( name ) { if ( this._initialized === false ) await this.init(); @@ -35794,6 +47846,13 @@ class Renderer { } + /** + * Checks if the given feature is supported by the selected backend. If the + * renderer has not been initialized, this method always returns `false`. + * + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ hasFeature( name ) { if ( this._initialized === false ) { @@ -35808,12 +47867,25 @@ class Renderer { } + /** + * Returns `true` when the renderer has been initialized. + * + * @return {Boolean} Whether the renderer has been initialized or not. + */ hasInitialized() { return this._initialized; } + /** + * Initializes the given textures. Useful for preloading a texture rather than waiting until first render + * (which can cause noticeable lags due to decode and GPU upload overhead). + * + * @async + * @param {Texture} texture - The texture. + * @return {Promise} A Promise that resolves when the texture has been initialized. + */ async initTextureAsync( texture ) { if ( this._initialized === false ) await this.init(); @@ -35822,20 +47894,32 @@ class Renderer { } + /** + * Initializes the given textures. Useful for preloading a texture rather than waiting until first render + * (which can cause noticeable lags due to decode and GPU upload overhead). + * + * This method can only be used if the renderer has been initialized. + * + * @param {Texture} texture - The texture. + */ initTexture( texture ) { if ( this._initialized === false ) { console.warn( 'THREE.Renderer: .initTexture() called before the backend is initialized. Try using .initTextureAsync() instead.' ); - return false; - } this._textures.updateTexture( texture ); } + /** + * Copies the current bound framebuffer into the given texture. + * + * @param {FramebufferTexture} framebufferTexture - The texture. + * @param {Vector2|Vector4} rectangle - A two or four dimensional vector that defines the rectangular portion of the framebuffer that should be copied. + */ copyFramebufferToTexture( framebufferTexture, rectangle = null ) { if ( rectangle !== null ) { @@ -35893,6 +47977,15 @@ class Renderer { } + /** + * Copies data of source texture into a destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Box2|Box3} [srcRegion=null] - A bounding box which describes the source region. Can be two or three-dimensional. + * @param {Vector2|Vector3} [dstPosition=null] - A vector that represents the origin of the destination region. Can be two or three-dimensional. + * @param {Number} level - The mipmap level to copy. + */ copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { this._textures.updateTexture( srcTexture ); @@ -35902,12 +47995,35 @@ class Renderer { } - readRenderTargetPixelsAsync( renderTarget, x, y, width, height, index = 0, faceIndex = 0 ) { + /** + * Reads pixel data from the given render target. + * + * @async + * @param {RenderTarget} renderTarget - The render target to read from. + * @param {Number} x - The `x` coordinate of the copy region's origin. + * @param {Number} y - The `y` coordinate of the copy region's origin. + * @param {Number} width - The width of the copy region. + * @param {Number} height - The height of the copy region. + * @param {Number} [textureIndex=0] - The texture index of a MRT render target. + * @param {Number} [faceIndex=0] - The active cube face index. + * @return {Promise} A Promise that resolves when the read has been finished. The resolve provides the read data as a typed array. + */ + async readRenderTargetPixelsAsync( renderTarget, x, y, width, height, textureIndex = 0, faceIndex = 0 ) { - return this.backend.copyTextureToBuffer( renderTarget.textures[ index ], x, y, width, height, faceIndex ); + return this.backend.copyTextureToBuffer( renderTarget.textures[ textureIndex ], x, y, width, height, faceIndex ); } + /** + * Analyzes the given 3D object's hierarchy and builds render lists from the + * processed hierarchy. + * + * @param {Object3D} object - The 3D object to process (usually a scene). + * @param {Camera} camera - The camera the object is rendered with. + * @param {Number} groupOrder - The group order is derived from the `renderOrder` of groups and is used to group 3D objects within groups. + * @param {RenderList} renderList - The current render list. + * @param {ClippingContext} clippingContext - The current clipping context. + */ _projectObject( object, camera, groupOrder, renderList, clippingContext ) { if ( object.visible === false ) return; @@ -36029,6 +48145,14 @@ class Renderer { } + /** + * Renders the given render bundles. + * + * @private + * @param {Array} bundles - Array with render bundle data. + * @param {Scene} sceneRef - The scene the render bundles belong to. + * @param {LightsNode} lightsNode - The current lights node. + */ _renderBundles( bundles, sceneRef, lightsNode ) { for ( const bundle of bundles ) { @@ -36039,6 +48163,16 @@ class Renderer { } + /** + * Renders the transparent objects from the given render lists. + * + * @private + * @param {Array} renderList - The transparent render list. + * @param {Array} doublePassList - The list of transparent objects which require a double pass (e.g. because of transmission). + * @param {Camera} camera - The camera the render list should be rendered with. + * @param {Scene} scene - The scene the render list belongs to. + * @param {LightsNode} lightsNode - The current lights node. + */ _renderTransparents( renderList, doublePassList, camera, scene, lightsNode ) { if ( doublePassList.length > 0 ) { @@ -36079,6 +48213,16 @@ class Renderer { } + /** + * Renders the objects from the given render list. + * + * @private + * @param {Array} renderList - The render list. + * @param {Camera} camera - The camera the render list should be rendered with. + * @param {Scene} scene - The scene the render list belongs to. + * @param {LightsNode} lightsNode - The current lights node. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ _renderObjects( renderList, camera, scene, lightsNode, passId = null ) { // process renderable objects @@ -36087,9 +48231,6 @@ class Renderer { 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, clippingContext } = renderItem; if ( camera.isArrayCamera ) { @@ -36110,6 +48251,7 @@ class Renderer { viewportValue.copy( vp ).multiplyScalar( this._pixelRatio ).floor(); viewportValue.minDepth = minDepth; viewportValue.maxDepth = maxDepth; + this._currentRenderContext.viewport = true; this.backend.updateViewport( this._currentRenderContext ); @@ -36129,6 +48271,20 @@ class Renderer { } + /** + * This method represents the default render object function that manages the render lifecycle + * of the object. + * + * @param {Object3D} object - The 3D object. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {BufferGeometry} geometry - The object's geometry. + * @param {Material} material - The object's material. + * @param {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {LightsNode} lightsNode - The current lights node. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ renderObject( object, scene, camera, geometry, material, group, lightsNode, clippingContext = null, passId = null ) { let overridePositionNode; @@ -36156,7 +48312,7 @@ class Renderer { overrideMaterial.alphaMap = material.alphaMap; overrideMaterial.transparent = material.transparent || material.transmission > 0; - if ( overrideMaterial.isShadowNodeMaterial ) { + if ( overrideMaterial.isShadowPassMaterial ) { overrideMaterial.side = material.shadowSide === null ? material.side : material.shadowSide; @@ -36224,6 +48380,20 @@ class Renderer { } + /** + * This method represents the default `_handleObjectFunction` implementation which creates + * a render object from the given data and performs the draw command with the selected backend. + * + * @private + * @param {Object3D} object - The 3D object. + * @param {Material} material - The object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The current lights node. + * @param {{start: Number, count: Number}?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ _renderObjectDirect( object, material, scene, camera, lightsNode, group, clippingContext, passId ) { const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId ); @@ -36255,7 +48425,7 @@ class Renderer { renderBundleData.renderObjects.push( renderObject ); - renderObject.bundle = this._currentRenderBundle.scene; + renderObject.bundle = this._currentRenderBundle.bundleGroup; } @@ -36265,9 +48435,25 @@ class Renderer { } - _createObjectPipeline( object, material, scene, camera, lightsNode, clippingContext, passId ) { + /** + * A different implementation for `_handleObjectFunction` which only makes sure the object is ready for rendering. + * Used in `compileAsync()`. + * + * @private + * @param {Object3D} object - The 3D object. + * @param {Material} material - The object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The current lights node. + * @param {{start: Number, count: Number}?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ + _createObjectPipeline( object, material, scene, camera, lightsNode, group, clippingContext, passId ) { const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId ); + renderObject.drawRange = object.geometry.drawRange; + renderObject.group = group; // @@ -36284,6 +48470,15 @@ class Renderer { } + /** + * Alias for `compileAsync()`. + * + * @method + * @param {Object3D} scene - The scene or 3D object to precompile. + * @param {Camera} camera - The camera that is used to render the scene. + * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. + * @return {Promise} A Promise that resolves when the compile has been finished. + */ get compile() { return this.compileAsync; @@ -36292,22 +48487,57 @@ class Renderer { } +/** + * A binding represents the connection between a resource (like a texture, sampler + * or uniform buffer) and the resource definition in a shader stage. + * + * This module is an abstract base class for all concrete bindings types. + * + * @abstract + * @private + */ class Binding { + /** + * Constructs a new binding. + * + * @param {String} [name=''] - The binding's name. + */ constructor( name = '' ) { + /** + * The binding's name. + * + * @type {String} + */ this.name = name; + /** + * A bitmask that defines in what shader stages the + * binding's resource is accessible. + * + * @type {Number} + */ this.visibility = 0; } + /** + * Makes sure binding's resource is visible for the given shader stage. + * + * @param {Number} visibility - The shader stage. + */ setVisibility( visibility ) { this.visibility |= visibility; } + /** + * Clones the binding. + * + * @return {Binding} The cloned binding. + */ clone() { return Object.assign( new this.constructor(), this ); @@ -36316,6 +48546,16 @@ class Binding { } +/** @module BufferUtils **/ + +/** + * This function is usually called with the length in bytes of an array buffer. + * It returns an padded value which ensure chunk size alignment according to STD140 layout. + * + * @function + * @param {Number} floatLength - The buffer length. + * @return {Number} The padded length. + */ function getFloatLength( floatLength ) { // ensure chunk size alignment (STD140 layout) @@ -36324,32 +48564,81 @@ function getFloatLength( floatLength ) { } +/** + * Represents a buffer binding type. + * + * @private + * @abstract + * @augments Binding + */ class Buffer extends Binding { + /** + * Constructs a new buffer. + * + * @param {String} name - The buffer's name. + * @param {TypedArray} [buffer=null] - The buffer. + */ constructor( name, buffer = null ) { super( name ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBuffer = true; + /** + * The bytes per element. + * + * @type {Number} + */ this.bytesPerElement = Float32Array.BYTES_PER_ELEMENT; + /** + * A reference to the internal buffer. + * + * @private + * @type {TypedArray} + */ this._buffer = buffer; } + /** + * The buffer's byte length. + * + * @type {Number} + * @readonly + */ get byteLength() { return getFloatLength( this._buffer.byteLength ); } + /** + * A reference to the internal buffer. + * + * @type {Float32Array} + * @readonly + */ get buffer() { return this._buffer; } + /** + * Updates the binding. + * + * @return {Boolean} Whether the buffer has been updated and must be + * uploaded to the GPU. + */ update() { return true; @@ -36358,12 +48647,31 @@ class Buffer extends Binding { } +/** + * Represents a uniform buffer binding type. + * + * @private + * @augments Buffer + */ class UniformBuffer extends Buffer { + /** + * Constructs a new uniform buffer. + * + * @param {String} name - The buffer's name. + * @param {TypedArray} [buffer=null] - The buffer. + */ constructor( name, buffer = null ) { super( name, buffer ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isUniformBuffer = true; } @@ -36372,17 +48680,46 @@ class UniformBuffer extends Buffer { let _id$4 = 0; +/** + * A special form of uniform buffer binding type. + * It's buffer value is managed by a node object. + * + * @private + * @augments UniformBuffer + */ class NodeUniformBuffer extends UniformBuffer { + /** + * Constructs a new node-based uniform buffer. + * + * @param {BufferNode} nodeUniform - The uniform buffer node. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( nodeUniform, groupNode ) { super( 'UniformBuffer_' + _id$4 ++, nodeUniform ? nodeUniform.value : null ); + /** + * The uniform buffer node. + * + * @type {BufferNode} + */ this.nodeUniform = nodeUniform; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; } + /** + * The uniform buffer. + * + * @type {Float32Array} + */ get buffer() { return this.nodeUniform.value; @@ -36391,22 +48728,59 @@ class NodeUniformBuffer extends UniformBuffer { } +/** + * This class represents a uniform buffer binding but with + * an API that allows to maintain individual uniform objects. + * + * @private + * @augments UniformBuffer + */ class UniformsGroup extends UniformBuffer { + /** + * Constructs a new uniforms group. + * + * @param {String} name - The group's name. + */ constructor( name ) { super( name ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isUniformsGroup = true; + /** + * An array with the raw uniform values. + * + * @private + * @type {Array?} + * @default null + */ this._values = null; - // the order of uniforms in this array must match the order of uniforms in the shader - + /** + * An array of uniform objects. + * + * The order of uniforms in this array must match the order of uniforms in the shader. + * + * @type {Array} + */ this.uniforms = []; } + /** + * Adds a uniform to this group. + * + * @param {Uniform} uniform - The uniform to add. + * @return {UniformsGroup} A reference to this group. + */ addUniform( uniform ) { this.uniforms.push( uniform ); @@ -36415,6 +48789,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Removes a uniform from this group. + * + * @param {Uniform} uniform - The uniform to remove. + * @return {UniformsGroup} A reference to this group. + */ removeUniform( uniform ) { const index = this.uniforms.indexOf( uniform ); @@ -36429,6 +48809,11 @@ class UniformsGroup extends UniformBuffer { } + /** + * An array with the raw uniform values. + * + * @type {Array} + */ get values() { if ( this._values === null ) { @@ -36441,6 +48826,11 @@ class UniformsGroup extends UniformBuffer { } + /** + * A Float32 array buffer with the uniform values. + * + * @type {Float32Array} + */ get buffer() { let buffer = this._buffer; @@ -36459,6 +48849,11 @@ class UniformsGroup extends UniformBuffer { } + /** + * The byte length of the buffer with correct buffer alignment. + * + * @type {Number} + */ get byteLength() { let offset = 0; // global buffer offset in bytes @@ -36500,6 +48895,15 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates this group by updating each uniform object of + * the internal uniform list. The uniform objects check if their + * values has actually changed so this method only returns + * `true` if there is a real value change. + * + * @return {Boolean} Whether the uniforms have been updated and + * must be uploaded to the GPU. + */ update() { let updated = false; @@ -36518,6 +48922,13 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given uniform by calling an update method matching + * the uniforms type. + * + * @param {Uniform} uniform - The uniform to update. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateByType( uniform ) { if ( uniform.isNumberUniform ) return this.updateNumber( uniform ); @@ -36532,6 +48943,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Number uniform. + * + * @param {NumberUniform} uniform - The Number uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateNumber( uniform ) { let updated = false; @@ -36554,6 +48971,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Vector2 uniform. + * + * @param {Vector2Uniform} uniform - The Vector2 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateVector2( uniform ) { let updated = false; @@ -36578,6 +49001,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Vector3 uniform. + * + * @param {Vector3Uniform} uniform - The Vector3 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateVector3( uniform ) { let updated = false; @@ -36603,6 +49032,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Vector4 uniform. + * + * @param {Vector4Uniform} uniform - The Vector4 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateVector4( uniform ) { let updated = false; @@ -36629,6 +49064,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Color uniform. + * + * @param {ColorUniform} uniform - The Color uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateColor( uniform ) { let updated = false; @@ -36653,6 +49094,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Matrix3 uniform. + * + * @param {Matrix3Uniform} uniform - The Matrix3 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateMatrix3( uniform ) { let updated = false; @@ -36685,6 +49132,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Matrix4 uniform. + * + * @param {Matrix4Uniform} uniform - The Matrix4 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateMatrix4( uniform ) { let updated = false; @@ -36706,6 +49159,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Returns a typed array that matches the given data type. + * + * @param {String} type - The data type. + * @return {TypedArray} The typed array. + */ _getBufferForType( type ) { if ( type === 'int' || type === 'ivec2' || type === 'ivec3' || type === 'ivec4' ) return new Int32Array( this.buffer.buffer ); @@ -36716,6 +49175,14 @@ class UniformsGroup extends UniformBuffer { } +/** + * Sets the values of the second array to the first array. + * + * @private + * @param {TypedArray} a - The first array. + * @param {TypedArray} b - The second array. + * @param {Number} offset - An index offset for the first array. + */ function setArray( a, b, offset ) { for ( let i = 0, l = b.length; i < l; i ++ ) { @@ -36726,6 +49193,15 @@ function setArray( a, b, offset ) { } +/** + * Returns `true` if the given arrays are equal. + * + * @private + * @param {TypedArray} a - The first array. + * @param {TypedArray} b - The second array. + * @param {Number} offset - An index offset for the first array. + * @return {Boolean} Whether the given arrays are equal or not. + */ function arraysEqual( a, b, offset ) { for ( let i = 0, l = b.length; i < l; i ++ ) { @@ -36740,58 +49216,128 @@ function arraysEqual( a, b, offset ) { let _id$3 = 0; +/** + * A special form of uniforms group that represents + * the individual uniforms as node-based uniforms. + * + * @private + * @augments UniformsGroup + */ class NodeUniformsGroup extends UniformsGroup { + /** + * Constructs a new node-based uniforms group. + * + * @param {String} name - The group's name. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( name, groupNode ) { super( name ); + /** + * The group's ID. + * + * @type {Number} + */ this.id = _id$3 ++; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ 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; +/** + * Represents a sampled texture binding type. + * + * @private + * @augments Binding + */ class SampledTexture extends Binding { + /** + * Constructs a new sampled texture. + * + * @param {String} name - The sampled texture's name. + * @param {Texture?} texture - The texture this binding is referring to. + */ constructor( name, texture ) { super( name ); + /** + * This identifier. + * + * @type {Number} + */ this.id = _id$2 ++; + /** + * The texture this binding is referring to. + * + * @type {Texture?} + */ this.texture = texture; + + /** + * The binding's version. + * + * @type {Number} + */ this.version = texture ? texture.version : 0; + + /** + * Whether the texture is a storage texture or not. + * + * @type {Boolean} + * @default false + */ this.store = false; + + /** + * The binding's generation which is an additional version + * qualifier. + * + * @type {Number?} + * @default null + */ this.generation = null; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledTexture = true; } + /** + * Returns `true` whether this binding requires an update for the + * given generation. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether an update is required or not. + */ needsBindingsUpdate( generation ) { const { texture } = this; @@ -36808,6 +49354,13 @@ class SampledTexture extends Binding { } + /** + * Updates the binding. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether the texture has been updated and must be + * uploaded to the GPU. + */ update() { const { texture, version } = this; @@ -36826,25 +49379,70 @@ class SampledTexture extends Binding { } +/** + * A special form of sampled texture binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments SampledTexture + */ class NodeSampledTexture extends SampledTexture { + /** + * Constructs a new node-based sampled texture. + * + * @param {String} name - The textures's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + * @param {String?} [access=null] - The access type. + */ constructor( name, textureNode, groupNode, access = null ) { super( name, textureNode ? textureNode.value : null ); + /** + * The texture node. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; + /** + * The access type. + * + * @type {String?} + * @default null + */ this.access = access; } + /** + * Overwrites the default to additionally check if the node value has changed. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether an update is required or not. + */ needsBindingsUpdate( generation ) { return this.textureNode.value !== this.texture || super.needsBindingsUpdate( generation ); } + /** + * Updates the binding. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether the texture has been updated and must be + * uploaded to the GPU. + */ update() { const { textureNode } = this; @@ -36863,24 +49461,68 @@ class NodeSampledTexture extends SampledTexture { } +/** + * A special form of sampled cube texture binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments NodeSampledTexture + */ class NodeSampledCubeTexture extends NodeSampledTexture { - constructor( name, textureNode, groupNode, access ) { + /** + * Constructs a new node-based sampled cube texture. + * + * @param {String} name - The textures's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + * @param {String?} [access=null] - The access type. + */ + constructor( name, textureNode, groupNode, access = null ) { super( name, textureNode, groupNode, access ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledCubeTexture = true; } } +/** + * A special form of sampled 3D texture binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments NodeSampledTexture + */ class NodeSampledTexture3D extends NodeSampledTexture { - constructor( name, textureNode, groupNode, access ) { + /** + * Constructs a new node-based sampled 3D texture. + * + * @param {String} name - The textures's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + * @param {String?} [access=null] - The access type. + */ + constructor( name, textureNode, groupNode, access = null ) { super( name, textureNode, groupNode, access ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledTexture3D = true; } @@ -36888,7 +49530,6 @@ class NodeSampledTexture3D extends NodeSampledTexture { } const glslMethods = { - atan2: 'atan', textureDimensions: 'textureSize', equals: 'equal' }; @@ -36925,39 +49566,109 @@ precision highp isampler2DArray; precision lowp sampler2DShadow; `; +/** + * A node builder targeting GLSL. + * + * This module generates GLSL shader code from node materials and also + * generates the respective bindings and vertex buffer definitions. These + * data are later used by the renderer to create render and compute pipelines + * for render objects. + * + * @augments NodeBuilder + */ class GLSLNodeBuilder extends NodeBuilder { + /** + * Constructs a new GLSL node builder renderer. + * + * @param {Object3D} object - The 3D object. + * @param {Renderer} renderer - The renderer. + */ constructor( object, renderer ) { super( object, renderer, new GLSLNodeParser() ); + /** + * A dictionary holds for each shader stage ('vertex', 'fragment', 'compute') + * another dictionary which manages UBOs per group ('render','frame','object'). + * + * @type {Object>} + */ this.uniformGroups = {}; + + /** + * An array that holds objects defining the varying and attribute data in + * context of Transform Feedback. + * + * @type {Object>} + */ this.transforms = []; + + /** + * A dictionary that holds for each shader stage a Map of used extensions. + * + * @type {Object>} + */ this.extensions = {}; + + /** + * A dictionary that holds for each shader stage an Array of used builtins. + * + * @type {Object>} + */ this.builtins = { vertex: [], fragment: [], compute: [] }; + /** + * Whether comparison in shader code are generated with methods or not. + * + * @type {Boolean} + * @default true + */ this.useComparisonMethod = true; } + /** + * Checks if the given texture requires a manual conversion to the working color space. + * + * @param {Texture} texture - The texture to check. + * @return {Boolean} Whether the given texture requires a conversion to working color space or not. + */ needsToWorkingColorSpace( texture ) { return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace; } + /** + * Returns the native shader method name for a given generic name. + * + * @param {String} method - The method name to resolve. + * @return {String} The resolved GLSL method name. + */ getMethod( method ) { return glslMethods[ method ] || method; } + /** + * Returns the output struct name. Not relevant for GLSL. + * + * @return {String} + */ getOutputStructName() { return ''; } + /** + * Builds the given shader node. + * + * @param {ShaderNodeInternal} shaderNode - The shader node. + * @return {String} The GLSL function code. + */ buildFunctionCode( shaderNode ) { const layout = shaderNode.layout; @@ -36988,6 +49699,12 @@ ${ flowData.code } } + /** + * Setups the Pixel Buffer Object (PBO) for the given storage + * buffer node. + * + * @param {StorageBufferNode} storageBufferNode - The storage buffer node. + */ setupPBO( storageBufferNode ) { const attribute = storageBufferNode.value; @@ -37056,6 +49773,13 @@ ${ flowData.code } } + /** + * Returns a GLSL snippet that represents the property name of the given node. + * + * @param {Node} node - The node. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The property name. + */ getPropertyName( node, shaderStage = this.shaderStage ) { if ( node.isNodeUniform && node.node.isTextureNode !== true && node.node.isBufferNode !== true ) { @@ -37068,6 +49792,13 @@ ${ flowData.code } } + /** + * Setups the Pixel Buffer Object (PBO) for the given storage + * buffer node. + * + * @param {StorageArrayElementNode} storageArrayElementNode - The storage array element node. + * @return {String} The property name. + */ generatePBO( storageArrayElementNode ) { const { node, indexNode } = storageArrayElementNode; @@ -37150,6 +49881,16 @@ ${ flowData.code } } + /** + * Generates the GLSL snippet that reads a single texel from a texture without sampling or filtering. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvIndexSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. + * @param {String} [levelSnippet='0u'] - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The GLSL snippet. + */ generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0' ) { if ( depthSnippet ) { @@ -37164,6 +49905,15 @@ ${ flowData.code } } + /** + * Generates the GLSL snippet for sampling/loading the given texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. + * @return {String} The GLSL snippet. + */ generateTexture( texture, textureProperty, uvSnippet, depthSnippet ) { if ( texture.isDepthTexture ) { @@ -37180,24 +49930,63 @@ ${ flowData.code } } + /** + * Generates the GLSL snippet when sampling textures with explicit mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The GLSL snippet. + */ generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet ) { return `textureLod( ${ textureProperty }, ${ uvSnippet }, ${ levelSnippet } )`; } + /** + * Generates the GLSL snippet when sampling textures with a bias to the mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String} biasSnippet - A GLSL snippet that represents the bias to apply to the mip level before sampling. + * @return {String} The GLSL snippet. + */ generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet ) { return `texture( ${ textureProperty }, ${ uvSnippet }, ${ biasSnippet } )`; } + /** + * Generates the GLSL snippet for sampling/loading the given texture using explicit gradients. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {Array} gradSnippet - An array holding both gradient GLSL snippets. + * @return {String} The GLSL snippet. + */ generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet ) { return `textureGrad( ${ textureProperty }, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] } )`; } + /** + * Generates the GLSL snippet for sampling a depth texture and comparing the sampled depth values + * against a reference value. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String} compareSnippet - A GLSL snippet that represents the reference value. + * @param {String?} depthSnippet - A GLSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The GLSL snippet. + */ generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -37212,6 +50001,12 @@ ${ flowData.code } } + /** + * Returns the variables of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the variables. + */ getVars( shaderStage ) { const snippets = []; @@ -37232,6 +50027,12 @@ ${ flowData.code } } + /** + * Returns the uniforms of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the uniforms. + */ getUniforms( shaderStage ) { const uniforms = this.uniforms[ shaderStage ]; @@ -37349,6 +50150,12 @@ ${ flowData.code } } + /** + * Returns the type for a given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + * @return {String} The type. + */ getTypeFromAttribute( attribute ) { let nodeType = super.getTypeFromAttribute( attribute ); @@ -37373,6 +50180,12 @@ ${ flowData.code } } + /** + * Returns the shader attributes of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the shader attributes. + */ getAttributes( shaderStage ) { let snippet = ''; @@ -37395,6 +50208,12 @@ ${ flowData.code } } + /** + * Returns the members of the given struct type node as a GLSL string. + * + * @param {StructTypeNode} struct - The struct type node. + * @return {String} The GLSL snippet that defines the struct members. + */ getStructMembers( struct ) { const snippets = []; @@ -37411,6 +50230,12 @@ ${ flowData.code } } + /** + * Returns the structs of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the structs. + */ getStructs( shaderStage ) { const snippets = []; @@ -37438,6 +50263,12 @@ ${ flowData.code } } + /** + * Returns the varyings of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the varyings. + */ getVaryings( shaderStage ) { let snippet = ''; @@ -37483,18 +50314,33 @@ ${ flowData.code } } + /** + * Returns the vertex index builtin. + * + * @return {String} The vertex index. + */ getVertexIndex() { return 'uint( gl_VertexID )'; } + /** + * Returns the instance index builtin. + * + * @return {String} The instance index. + */ getInstanceIndex() { return 'uint( gl_InstanceID )'; } + /** + * Returns the invocation local index builtin. + * + * @return {String} The invocation local index. + */ getInvocationLocalIndex() { const workgroupSize = this.object.workgroupSize; @@ -37505,6 +50351,11 @@ ${ flowData.code } } + /** + * Returns the draw index builtin. + * + * @return {String?} The drawIndex shader string. Returns `null` if `WEBGL_multi_draw` isn't supported by the device. + */ getDrawIndex() { const extensions = this.renderer.backend.extensions; @@ -37519,24 +50370,46 @@ ${ flowData.code } } + /** + * Returns the front facing builtin. + * + * @return {String} The front facing builtin. + */ getFrontFacing() { return 'gl_FrontFacing'; } + /** + * Returns the frag coord builtin. + * + * @return {String} The frag coord builtin. + */ getFragCoord() { return 'gl_FragCoord.xy'; } + /** + * Returns the frag depth builtin. + * + * @return {String} The frag depth builtin. + */ getFragDepth() { return 'gl_FragDepth'; } + /** + * Enables the given extension. + * + * @param {String} name - The extension name. + * @param {String} behavior - The extension behavior. + * @param {String} [shaderStage=this.shaderStage] - The shader stage. + */ enableExtension( name, behavior, shaderStage = this.shaderStage ) { const map = this.extensions[ shaderStage ] || ( this.extensions[ shaderStage ] = new Map() ); @@ -37552,6 +50425,12 @@ ${ flowData.code } } + /** + * Returns the enabled extensions of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the enabled extensions. + */ getExtensions( shaderStage ) { const snippets = []; @@ -37585,12 +50464,23 @@ ${ flowData.code } } + /** + * Returns the clip distances builtin. + * + * @return {String} The clip distances builtin. + */ getClipDistance() { return 'gl_ClipDistance'; } + /** + * Whether the requested feature is available or not. + * + * @param {String} name - The requested feature. + * @return {Boolean} Whether the requested feature is supported or not. + */ isAvailable( name ) { let result = supports$1[ name ]; @@ -37634,12 +50524,22 @@ ${ flowData.code } } + /** + * Whether to flip texture data along its vertical axis or not. + * + * @return {Boolean} Returns always `true` in context of GLSL. + */ isFlipY() { return true; } + /** + * Enables hardware clipping. + * + * @param {String} planeCount - The clipping plane count. + */ enableHardwareClipping( planeCount ) { this.enableExtension( 'GL_ANGLE_clip_cull_distance', 'require' ); @@ -37648,12 +50548,24 @@ ${ flowData.code } } + /** + * Registers a transform in context of Transform Feedback. + * + * @param {String} varyingName - The varying name. + * @param {AttributeNode} attributeNode - The attribute node. + */ registerTransform( varyingName, attributeNode ) { this.transforms.push( { varyingName, attributeNode } ); } + /** + * Returns the transforms of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the transforms. + */ getTransforms( /* shaderStage */ ) { const transforms = this.transforms; @@ -37674,6 +50586,14 @@ ${ flowData.code } } + /** + * Returns a GLSL struct based on the given name and variables. + * + * @private + * @param {String} name - The struct name. + * @param {String} vars - The struct variables. + * @return {String} The GLSL snippet representing a struct. + */ _getGLSLUniformStruct( name, vars ) { return ` @@ -37683,6 +50603,13 @@ ${vars} } + /** + * Returns a GLSL vertex shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getGLSLVertexCode( shaderData ) { return `#version 300 es @@ -37725,6 +50652,13 @@ void main() { } + /** + * Returns a GLSL fragment shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getGLSLFragmentCode( shaderData ) { return `#version 300 es @@ -37758,6 +50692,9 @@ void main() { } + /** + * Controls the code build of the shader stages. + */ buildCode() { const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; @@ -37838,6 +50775,19 @@ void main() { } + /** + * This method is one of the more important ones since it's responsible + * for generating a matching binding instance for the given uniform node. + * + * These bindings are later used in the renderer to create bind groups + * and layouts. + * + * @param {UniformNode} node - The uniform node. + * @param {String} type - The node data type. + * @param {String} shaderStage - The shader stage. + * @param {String?} [name=null] - An optional uniform name. + * @return {NodeUniform} The node uniform object. + */ getUniformFromNode( node, type, shaderStage, name = null ) { const uniformNode = super.getUniformFromNode( node, type, shaderStage, name ); @@ -37912,141 +50862,540 @@ void main() { } -let vector2 = null; -let vector4 = null; -let color4 = null; +let _vector2 = null; +let _color4 = null; +/** + * Most of the rendering related logic is implemented in the + * {@link module:Renderer} module and related management components. + * Sometimes it is required though to execute commands which are + * specific to the current 3D backend (which is WebGPU or WebGL 2). + * This abstract base class defines an interface that encapsulates + * all backend-related logic. Derived classes for each backend must + * implement the interface. + * + * @abstract + * @private + */ class Backend { + /** + * Constructs a new backend. + * + * @param {Object} parameters - An object holding parameters for the backend. + */ constructor( parameters = {} ) { + /** + * The parameters of the backend. + * + * @type {Object} + */ this.parameters = Object.assign( {}, parameters ); + + /** + * This weak map holds backend-specific data of objects + * like textures, attributes or render targets. + * + * @type {WeakMap} + */ this.data = new WeakMap(); + + /** + * A reference to the renderer. + * + * @type {Renderer?} + * @default null + */ this.renderer = null; + + /** + * A reference to the canvas element the renderer is drawing to. + * + * @type {(HTMLCanvasElement|OffscreenCanvas)?} + * @default null + */ this.domElement = null; } + /** + * Initializes the backend so it is ready for usage. Concrete backends + * are supposed to implement their rendering context creation and related + * operations in this method. + * + * @async + * @param {Renderer} renderer - The renderer. + * @return {Promise} A Promise that resolves when the backend has been initialized. + */ async init( renderer ) { this.renderer = renderer; } + /** + * The coordinate system of the backend. + * + * @abstract + * @type {Number} + * @readonly + */ + get coordinateSystem() {} + // render context - begin( /*renderContext*/ ) { } + /** + * This method is executed at the beginning of a render call and + * can be used by the backend to prepare the state for upcoming + * draw calls. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + */ + beginRender( /*renderContext*/ ) {} + + /** + * This method is executed at the end of a render call and + * can be used by the backend to finalize work after draw + * calls. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + */ + finishRender( /*renderContext*/ ) {} + + /** + * This method is executed at the beginning of a compute call and + * can be used by the backend to prepare the state for upcoming + * compute tasks. + * + * @abstract + * @param {Node|Array} computeGroup - The compute node(s). + */ + beginCompute( /*computeGroup*/ ) {} - finish( /*renderContext*/ ) { } + /** + * This method is executed at the end of a compute call and + * can be used by the backend to finalize work after compute + * tasks. + * + * @abstract + * @param {Node|Array} computeGroup - The compute node(s). + */ + finishCompute( /*computeGroup*/ ) {} // render object + /** + * Executes a draw command for the given render object. + * + * @abstract + * @param {RenderObject} renderObject - The render object to draw. + * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. + */ draw( /*renderObject, info*/ ) { } + // compute node + + /** + * Executes a compute command for the given compute node. + * + * @abstract + * @param {Node|Array} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @param {ComputePipeline} computePipeline - The compute pipeline. + */ + compute( /*computeGroup, computeNode, computeBindings, computePipeline*/ ) { } + // program + /** + * Creates a shader program from the given programmable stage. + * + * @abstract + * @param {ProgrammableStage} program - The programmable stage. + */ createProgram( /*program*/ ) { } + /** + * Destroys the shader program of the given programmable stage. + * + * @abstract + * @param {ProgrammableStage} program - The programmable stage. + */ destroyProgram( /*program*/ ) { } // bindings - createBindings( /*bingGroup, bindings*/ ) { } + /** + * Creates bindings from the given bind group definition. + * + * @abstract + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + createBindings( /*bindGroup, bindings, cacheIndex, version*/ ) { } + + /** + * Updates the given bind group definition. + * + * @abstract + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + updateBindings( /*bindGroup, bindings, cacheIndex, version*/ ) { } - updateBindings( /*bingGroup, bindings*/ ) { } + /** + * Updates a buffer binding. + * + * @abstract + * @param {Buffer} binding - The buffer binding to update. + */ + updateBinding( /*binding*/ ) { } // pipeline - createRenderPipeline( /*renderObject*/ ) { } - - createComputePipeline( /*computeNode, pipeline*/ ) { } + /** + * Creates a render pipeline for the given render object. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ + createRenderPipeline( /*renderObject, promises*/ ) { } - destroyPipeline( /*pipeline*/ ) { } + /** + * Creates a compute pipeline for the given compute node. + * + * @abstract + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ + createComputePipeline( /*computePipeline, bindings*/ ) { } // cache key - needsRenderUpdate( /*renderObject*/ ) { } // return Boolean ( fast test ) + /** + * Returns `true` if the render pipeline requires an update. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render pipeline requires an update or not. + */ + needsRenderUpdate( /*renderObject*/ ) { } - getRenderCacheKey( /*renderObject*/ ) { } // return String + /** + * Returns a cache key that is used to identify render pipelines. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @return {String} The cache key. + */ + getRenderCacheKey( /*renderObject*/ ) { } // node builder - createNodeBuilder( /*renderObject*/ ) { } // return NodeBuilder (ADD IT) + /** + * Returns a node builder for the given render object. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @param {Renderer} renderer - The renderer. + * @return {NodeBuilder} The node builder. + */ + createNodeBuilder( /*renderObject, renderer*/ ) { } // textures + /** + * Creates a GPU sampler for the given texture. + * + * @abstract + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( /*texture*/ ) { } + /** + * Destroys the GPU sampler for the given texture. + * + * @abstract + * @param {Texture} texture - The texture to destroy the sampler for. + */ + destroySampler( /*texture*/ ) {} + + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @abstract + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( /*texture*/ ) { } - createTexture( /*texture*/ ) { } + /** + * Defines a texture on the GPU for the given texture object. + * + * @abstract + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ + createTexture( /*texture, options={}*/ ) { } + + /** + * Uploads the updated texture data to the GPU. + * + * @abstract + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ + updateTexture( /*texture, options = {}*/ ) { } + + /** + * Generates mipmaps for the given texture. + * + * @abstract + * @param {Texture} texture - The texture. + */ + generateMipmaps( /*texture*/ ) { } + + /** + * Destroys the GPU data for the given texture object. + * + * @abstract + * @param {Texture} texture - The texture. + */ + destroyTexture( /*texture*/ ) { } + + /** + * Returns texture data as a typed array. + * + * @abstract + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ + async copyTextureToBuffer( /*texture, x, y, width, height, faceIndex*/ ) {} + + /** + * Copies data of the given source texture to the given destination texture. + * + * @abstract + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ + copyTextureToTexture( /*srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0*/ ) {} - copyTextureToBuffer( /*texture, x, y, width, height*/ ) {} + /** + * Copies the current bound framebuffer to the given texture. + * + * @abstract + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ + copyFramebufferToTexture( /*texture, renderContext, rectangle*/ ) {} // attributes + /** + * Creates the GPU buffer of a shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute. + */ createAttribute( /*attribute*/ ) { } + /** + * Creates the GPU buffer of an indexed shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The indexed buffer attribute. + */ createIndexAttribute( /*attribute*/ ) { } + /** + * Creates the GPU buffer of a storage attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute. + */ + createStorageAttribute( /*attribute*/ ) { } + + /** + * Updates the GPU buffer of a shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute to update. + */ updateAttribute( /*attribute*/ ) { } + /** + * Destroys the GPU buffer of a shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute to destroy. + */ destroyAttribute( /*attribute*/ ) { } // canvas + /** + * Returns the backend's rendering context. + * + * @abstract + * @return {Object} The rendering context. + */ getContext() { } + /** + * Backends can use this method if they have to run + * logic when the renderer gets resized. + * + * @abstract + */ updateSize() { } + /** + * Updates the viewport with the values from the given render context. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + */ + updateViewport( /*renderContext*/ ) {} + // utils - resolveTimestampAsync( /*renderContext, type*/ ) { } + /** + * Returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. Backends must implement this method by using + * a Occlusion Query API. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ + isOccluded( /*renderContext, object*/ ) {} - hasFeatureAsync( /*name*/ ) { } // return Boolean + /** + * Resolves the time stamp for the given render context and type. + * + * @async + * @abstract + * @param {RenderContext} renderContext - The render context. + * @param {String} type - The render context. + * @return {Promise} A Promise that resolves when the time stamp has been computed. + */ + async resolveTimestampAsync( /*renderContext, type*/ ) { } - hasFeature( /*name*/ ) { } // return Boolean + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @abstract + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ + async waitForGPU() {} - getInstanceCount( renderObject ) { + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ + async getArrayBufferAsync( /* attribute */ ) {} - const { object, geometry } = renderObject; + /** + * Checks if the given feature is supported by the backend. + * + * @async + * @abstract + * @param {String} name - The feature's name. + * @return {Promise} A Promise that resolves with a bool that indicates whether the feature is supported or not. + */ + async hasFeatureAsync( /*name*/ ) { } - return geometry.isInstancedBufferGeometry ? geometry.instanceCount : ( object.count > 1 ? object.count : 1 ); + /** + * Checks if the given feature is supported by the backend. + * + * @abstract + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ + hasFeature( /*name*/ ) {} - } + /** + * Returns the maximum anisotropy texture filtering value. + * + * @abstract + * @return {Number} The maximum anisotropy texture filtering value. + */ + getMaxAnisotropy() {} + /** + * Returns the drawing buffer size. + * + * @return {Vector2} The drawing buffer size. + */ getDrawingBufferSize() { - vector2 = vector2 || new Vector2(); - - return this.renderer.getDrawingBufferSize( vector2 ); - - } - - getScissor() { + _vector2 = _vector2 || new Vector2(); - vector4 = vector4 || new Vector4(); - - return this.renderer.getScissor( vector4 ); + return this.renderer.getDrawingBufferSize( _vector2 ); } + /** + * Defines the scissor test. + * + * @abstract + * @param {Boolean} boolean - Whether the scissor test should be enabled or not. + */ setScissorTest( /*boolean*/ ) { } + /** + * Returns the clear color and alpha into a single + * color object. + * + * @return {Color4} The clear color. + */ getClearColor() { const renderer = this.renderer; - color4 = color4 || new Color4(); + _color4 = _color4 || new Color4(); - renderer.getClearColor( color4 ); + renderer.getClearColor( _color4 ); - color4.getRGB( color4, this.renderer.currentColorSpace ); + _color4.getRGB( _color4, this.renderer.currentColorSpace ); - return color4; + return _color4; } + /** + * Returns the DOM element. If no DOM element exists, the backend + * creates a new one. + * + * @return {HTMLCanvasElement} The DOM element. + */ getDomElement() { let domElement = this.domElement; @@ -38066,14 +51415,25 @@ class Backend { } - // resource properties - + /** + * Sets a dictionary for the given object into the + * internal data structure. + * + * @param {Object} object - The object. + * @param {Object} value - The dictionary to set. + */ set( object, value ) { this.data.set( object, value ); } + /** + * Returns the dictionary for the given object. + * + * @param {Object} object - The object. + * @return {Object} The object's dictionary. + */ get( object ) { let map = this.data.get( object ); @@ -38089,24 +51449,49 @@ class Backend { } + /** + * Checks if the given object has a dictionary + * with data defined. + * + * @param {Object} object - The object. + * @return {Boolean} Whether a dictionary for the given object as been defined or not. + */ has( object ) { return this.data.has( object ); } + /** + * Deletes an object from the internal data structure. + * + * @param {Object} object - The object to delete. + */ delete( object ) { this.data.delete( object ); } + /** + * Frees internal resources. + * + * @abstract + */ dispose() { } } let _id$1 = 0; +/** + * This module is internally used in context of compute shaders. + * This type of shader is not natively supported in WebGL 2 and + * thus implemented via Transform Feedback. `DualAttributeData` + * manages the related data. + * + * @private + */ class DualAttributeData { constructor( attributeData, dualBuffer ) { @@ -38151,14 +51536,35 @@ class DualAttributeData { } +/** + * A WebGL 2 backend utility module for managing shader attributes. + * + * @private + */ class WebGLAttributeUtils { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; } + /** + * Creates the GPU buffer for the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + * @param {GLenum } bufferType - A flag that indicates the buffer type and thus binding point target. + */ createAttribute( attribute, bufferType ) { const backend = this.backend; @@ -38246,7 +51652,7 @@ class WebGLAttributeUtils { if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) { - // create buffer for tranform feedback use + // create buffer for transform feedback use const bufferGPUDual = this._createBuffer( gl, bufferType, array, usage ); attributeData = new DualAttributeData( attributeData, bufferGPUDual ); @@ -38256,6 +51662,11 @@ class WebGLAttributeUtils { } + /** + * Updates the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ updateAttribute( attribute ) { const backend = this.backend; @@ -38295,6 +51706,11 @@ class WebGLAttributeUtils { } + /** + * Destroys the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ destroyAttribute( attribute ) { const backend = this.backend; @@ -38314,6 +51730,14 @@ class WebGLAttributeUtils { } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { const backend = this.backend; @@ -38352,6 +51776,16 @@ class WebGLAttributeUtils { } + /** + * Creates a WebGL buffer with the given data. + * + * @private + * @param {WebGL2RenderingContext} gl - The rendering context. + * @param {GLenum } bufferType - A flag that indicates the buffer type and thus binding point target. + * @param {TypedArray} array - The array of the buffer attribute. + * @param {GLenum} usage - The usage. + * @return {WebGLBuffer} The WebGL buffer. + */ _createBuffer( gl, bufferType, array, usage ) { const bufferGPU = gl.createBuffer(); @@ -38368,14 +51802,43 @@ class WebGLAttributeUtils { let initialized$1 = false, equationToGL, factorToGL; +/** + * A WebGL 2 backend utility module for managing the WebGL state. + * + * The major goal of this module is to reduce the number of state changes + * by caching the WEbGL state with a series of variables. In this way, the + * renderer only executes state change commands when necessary which + * improves the overall performance. + * + * @private + */ class WebGLState { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = this.backend.gl; + // Below properties are intended to cache + // the WebGL state and are not explicitly + // documented for convenience reasons. + this.enabled = {}; this.currentFlipSided = null; this.currentCullFace = null; @@ -38412,7 +51875,7 @@ class WebGLState { if ( initialized$1 === false ) { - this._init( this.gl ); + this._init(); initialized$1 = true; @@ -38420,7 +51883,14 @@ class WebGLState { } - _init( gl ) { + /** + * Inits the state of the utility. + * + * @private + */ + _init() { + + const gl = this.gl; // Store only WebGL constants here. @@ -38446,6 +51916,14 @@ class WebGLState { } + /** + * Enables the given WebGL capability. + * + * This method caches the capability state so + * `gl.enable()` is only called when necessary. + * + * @param {GLenum} id - The capability to enable. + */ enable( id ) { const { enabled } = this; @@ -38459,6 +51937,14 @@ class WebGLState { } + /** + * Disables the given WebGL capability. + * + * This method caches the capability state so + * `gl.disable()` is only called when necessary. + * + * @param {GLenum} id - The capability to enable. + */ disable( id ) { const { enabled } = this; @@ -38472,6 +51958,15 @@ class WebGLState { } + /** + * Specifies whether polygons are front- or back-facing + * by setting the winding orientation. + * + * This method caches the state so `gl.frontFace()` is only + * called when necessary. + * + * @param {Boolean} flipSided - Whether triangles flipped their sides or not. + */ setFlipSided( flipSided ) { if ( this.currentFlipSided !== flipSided ) { @@ -38494,6 +51989,15 @@ class WebGLState { } + /** + * Specifies whether or not front- and/or back-facing + * polygons can be culled. + * + * This method caches the state so `gl.cullFace()` is only + * called when necessary. + * + * @param {Number} cullFace - Defines which polygons are candidates for culling. + */ setCullFace( cullFace ) { const { gl } = this; @@ -38530,6 +52034,14 @@ class WebGLState { } + /** + * Specifies the width of line primitives. + * + * This method caches the state so `gl.lineWidth()` is only + * called when necessary. + * + * @param {Number} width - The line width. + */ setLineWidth( width ) { const { currentLineWidth, gl } = this; @@ -38544,7 +52056,21 @@ class WebGLState { } - + /** + * Defines the blending. + * + * This method caches the state so `gl.blendEquation()`, `gl.blendEquationSeparate()`, + * `gl.blendFunc()` and `gl.blendFuncSeparate()` are only called when necessary. + * + * @param {Number} blending - The blending type. + * @param {Number} blendEquation - The blending equation. + * @param {Number} blendSrc - Only relevant for custom blending. The RGB source blending factor. + * @param {Number} blendDst - Only relevant for custom blending. The RGB destination blending factor. + * @param {Number} blendEquationAlpha - Only relevant for custom blending. The blending equation for alpha. + * @param {Number} blendSrcAlpha - Only relevant for custom blending. The alpha source blending factor. + * @param {Number} blendDstAlpha - Only relevant for custom blending. The alpha destination blending factor. + * @param {Boolean} premultipliedAlpha - Whether premultiplied alpha is enabled or not. + */ setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { const { gl } = this; @@ -38681,6 +52207,15 @@ class WebGLState { } + /** + * Specifies whether colors can be written when rendering + * into a framebuffer or not. + * + * This method caches the state so `gl.colorMask()` is only + * called when necessary. + * + * @param {Boolean} colorMask - The color mask. + */ setColorMask( colorMask ) { if ( this.currentColorMask !== colorMask ) { @@ -38692,6 +52227,11 @@ class WebGLState { } + /** + * Specifies whether the depth test is enabled or not. + * + * @param {Boolean} depthTest - Whether the depth test is enabled or not. + */ setDepthTest( depthTest ) { const { gl } = this; @@ -38708,6 +52248,15 @@ class WebGLState { } + /** + * Specifies whether depth values can be written when rendering + * into a framebuffer or not. + * + * This method caches the state so `gl.depthMask()` is only + * called when necessary. + * + * @param {Boolean} depthMask - The depth mask. + */ setDepthMask( depthMask ) { if ( this.currentDepthMask !== depthMask ) { @@ -38719,6 +52268,14 @@ class WebGLState { } + /** + * Specifies the depth compare function. + * + * This method caches the state so `gl.depthFunc()` is only + * called when necessary. + * + * @param {Number} depthFunc - The depth compare function. + */ setDepthFunc( depthFunc ) { if ( this.currentDepthFunc !== depthFunc ) { @@ -38779,6 +52336,11 @@ class WebGLState { } + /** + * Specifies whether the stencil test is enabled or not. + * + * @param {Boolean} stencilTest - Whether the stencil test is enabled or not. + */ setStencilTest( stencilTest ) { const { gl } = this; @@ -38795,6 +52357,15 @@ class WebGLState { } + /** + * Specifies whether stencil values can be written when rendering + * into a framebuffer or not. + * + * This method caches the state so `gl.stencilMask()` is only + * called when necessary. + * + * @param {Boolean} stencilMask - The stencil mask. + */ setStencilMask( stencilMask ) { if ( this.currentStencilMask !== stencilMask ) { @@ -38806,6 +52377,16 @@ class WebGLState { } + /** + * Specifies whether the stencil test functions. + * + * This method caches the state so `gl.stencilFunc()` is only + * called when necessary. + * + * @param {Number} stencilFunc - The stencil compare function. + * @param {Number} stencilRef - The reference value for the stencil test. + * @param {Number} stencilMask - A bit-wise mask that is used to AND the reference value and the stored stencil value when the test is done. + */ setStencilFunc( stencilFunc, stencilRef, stencilMask ) { if ( this.currentStencilFunc !== stencilFunc || @@ -38822,6 +52403,17 @@ class WebGLState { } + /** + * Specifies whether the stencil test operation. + * + * This method caches the state so `gl.stencilOp()` is only + * called when necessary. + * + * @param {Number} stencilFail - The function to use when the stencil test fails. + * @param {Number} stencilZFail - The function to use when the stencil test passes, but the depth test fail. + * @param {Number} stencilZPass - The function to use when both the stencil test and the depth test pass, + * or when the stencil test passes and there is no depth buffer or depth testing is disabled. + */ setStencilOp( stencilFail, stencilZFail, stencilZPass ) { if ( this.currentStencilFail !== stencilFail || @@ -38838,6 +52430,13 @@ class WebGLState { } + /** + * Configures the WebGL state for the given material. + * + * @param {Material} material - The material to configure the state for. + * @param {Number} frontFaceCW - Whether the front faces are counter-clockwise or not. + * @param {Number} hardwareClippingPlanes - The number of hardware clipping planes. + */ setMaterial( material, frontFaceCW, hardwareClippingPlanes ) { const { gl } = this; @@ -38902,6 +52501,16 @@ class WebGLState { } + /** + * Specifies the polygon offset. + * + * This method caches the state so `gl.polygonOffset()` is only + * called when necessary. + * + * @param {Boolean} polygonOffset - Whether polygon offset is enabled or not. + * @param {Number} factor - The scale factor for the variable depth offset for each polygon. + * @param {Number} units - The multiplier by which an implementation-specific value is multiplied with to create a constant depth offset. + */ setPolygonOffset( polygonOffset, factor, units ) { const { gl } = this; @@ -38927,6 +52536,15 @@ class WebGLState { } + /** + * Defines the usage of the given WebGL program. + * + * This method caches the state so `gl.useProgram()` is only + * called when necessary. + * + * @param {WebGLProgram} program - The WebGL program to use. + * @return {Boolean} Whether a program change has been executed or not. + */ useProgram( program ) { if ( this.currentProgram !== program ) { @@ -38946,6 +52564,16 @@ class WebGLState { // framebuffer + /** + * Binds the given framebuffer. + * + * This method caches the state so `gl.bindFramebuffer()` is only + * called when necessary. + * + * @param {Number} target - The binding point (target). + * @param {WebGLFramebuffer} framebuffer - The WebGL framebuffer to bind. + * @return {Boolean} Whether a bind has been executed or not. + */ bindFramebuffer( target, framebuffer ) { const { gl, currentBoundFramebuffers } = this; @@ -38978,6 +52606,16 @@ class WebGLState { } + /** + * Defines draw buffers to which fragment colors are written into. + * Configures the MRT setup of custom framebuffers. + * + * This method caches the state so `gl.drawBuffers()` is only + * called when necessary. + * + * @param {RenderContext} renderContext - The render context. + * @param {WebGLFramebuffer} framebuffer - The WebGL framebuffer. + */ drawBuffers( renderContext, framebuffer ) { const { gl } = this; @@ -39038,6 +52676,14 @@ class WebGLState { // texture + /** + * Makes the given texture unit active. + * + * This method caches the state so `gl.activeTexture()` is only + * called when necessary. + * + * @param {Number} webglSlot - The texture unit to make active. + */ activeTexture( webglSlot ) { const { gl, currentTextureSlot, maxTextures } = this; @@ -39053,6 +52699,16 @@ class WebGLState { } + /** + * Binds the given WebGL texture to a target. + * + * This method caches the state so `gl.bindTexture()` is only + * called when necessary. + * + * @param {Number} webglType - The binding point (target). + * @param {WebGLTexture} webglTexture - The WebGL texture to bind. + * @param {Number} webglSlot - The texture. + */ bindTexture( webglType, webglTexture, webglSlot ) { const { gl, currentTextureSlot, currentBoundTextures, maxTextures } = this; @@ -39098,6 +52754,17 @@ class WebGLState { } + /** + * Binds a given WebGL buffer to a given binding point (target) at a given index. + * + * This method caches the state so `gl.bindBufferBase()` is only + * called when necessary. + * + * @param {Number} target - The target for the bind operation. + * @param {Number} index - The index of the target. + * @param {WebGLBuffer} buffer - The WebGL buffer. + * @return {Boolean} Whether a bind has been executed or not. + */ bindBufferBase( target, index, buffer ) { const { gl } = this; @@ -39118,6 +52785,12 @@ class WebGLState { } + /** + * Unbinds the current bound texture. + * + * This method caches the state so `gl.bindTexture()` is only + * called when necessary. + */ unbindTexture() { const { gl, currentTextureSlot, currentBoundTextures } = this; @@ -39137,17 +52810,53 @@ class WebGLState { } +/** + * A WebGL 2 backend utility module with common helpers. + * + * @private + */ class WebGLUtils { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = this.backend.gl; + + /** + * A reference to a backend module holding extension-related + * utility functions. + * + * @type {WebGLExtensions} + */ this.extensions = backend.extensions; } + /** + * Converts the given three.js constant into a WebGL constant. + * The method currently supports the conversion of texture formats + * and types. + * + * @param {Number} p - The three.js constant. + * @param {String} [colorSpace=NoColorSpace] - The color space. + * @return {Number} The corresponding WebGL constant. + */ convert( p, colorSpace = NoColorSpace ) { const { gl, extensions } = this; @@ -39358,6 +53067,13 @@ class WebGLUtils { } + /** + * This method can be used to synchronize the CPU with the GPU by waiting until + * ongoing GPU commands have been completed. + * + * @private + * @return {Promise} A promise that resolves when all ongoing GPU commands have been completed. + */ _clientWaitAsync() { const { gl } = this; @@ -39404,19 +53120,53 @@ class WebGLUtils { let initialized = false, wrappingToGL, filterToGL, compareToGL; +/** + * A WebGL 2 backend utility module for managing textures. + * + * @private + */ class WebGLTextureUtils { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = backend.gl; + + /** + * A reference to a backend module holding extension-related + * utility functions. + * + * @type {WebGLExtensions} + */ this.extensions = backend.extensions; + + /** + * A dictionary for managing default textures. The key + * is the binding point (target), the value the WEbGL texture object. + * + * @type {Object} + */ this.defaultTextures = {}; if ( initialized === false ) { - this._init( this.gl ); + this._init(); initialized = true; @@ -39424,7 +53174,14 @@ class WebGLTextureUtils { } - _init( gl ) { + /** + * Inits the state of the utility. + * + * @private + */ + _init() { + + const gl = this.gl; // Store only WebGL constants here. @@ -39457,20 +53214,12 @@ class WebGLTextureUtils { } - filterFallback( f ) { - - const { gl } = this; - - if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - - return gl.NEAREST; - - } - - return gl.LINEAR; - - } - + /** + * Returns the native texture type for the given texture. + * + * @param {Texture} texture - The texture. + * @return {GLenum} The native texture type. + */ getGLTextureType( texture ) { const { gl } = this; @@ -39500,6 +53249,16 @@ class WebGLTextureUtils { } + /** + * Returns the native texture type for the given texture. + * + * @param {String?} internalFormatName - The internal format name. When `null`, the internal format is derived from the subsequent parameters. + * @param {GLenum} glFormat - The WebGL format. + * @param {GLenum} glType - The WebGL type. + * @param {String} colorSpace - The texture's color space. + * @param {Boolean} [forceLinearTransfer=false] - Whether to force a linear transfer or not. + * @return {GLenum} The internal format. + */ getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { const { gl, extensions } = this; @@ -39643,6 +53402,12 @@ class WebGLTextureUtils { } + /** + * Sets the texture parameters for the given texture. + * + * @param {GLenum} textureType - The texture type. + * @param {Texture} texture - The texture. + */ setTextureParameters( textureType, texture ) { const { gl, extensions, backend } = this; @@ -39696,6 +53461,12 @@ class WebGLTextureUtils { } + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { const { gl, backend, defaultTextures } = this; @@ -39727,6 +53498,13 @@ class WebGLTextureUtils { } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + * @return {undefined} + */ createTexture( texture, options ) { const { gl, backend } = this; @@ -39767,6 +53545,12 @@ class WebGLTextureUtils { } + /** + * Uploads texture buffer data to the GPU memory. + * + * @param {WebGLBuffer} buffer - The buffer data. + * @param {Texture} texture - The texture, + */ copyBufferToTexture( buffer, texture ) { const { gl, backend } = this; @@ -39802,6 +53586,12 @@ class WebGLTextureUtils { } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { const { gl } = this; @@ -39922,6 +53712,11 @@ class WebGLTextureUtils { } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { const { gl, backend } = this; @@ -39932,6 +53727,11 @@ class WebGLTextureUtils { } + /** + * Deallocates the render buffers of the given render target. + * + * @param {RenderTarget} renderTarget - The render target. + */ deallocateRenderBuffers( renderTarget ) { const { gl, backend } = this; @@ -39992,6 +53792,11 @@ class WebGLTextureUtils { } + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { const { gl, backend } = this; @@ -40004,6 +53809,15 @@ class WebGLTextureUtils { } + /** + * Copies data of the given source texture to the given destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { const { gl, backend } = this; @@ -40122,6 +53936,13 @@ class WebGLTextureUtils { } + /** + * Copies the current bound framebuffer to the given texture. + * + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ copyFramebufferToTexture( texture, renderContext, rectangle ) { const { gl } = this; @@ -40133,7 +53954,7 @@ class WebGLTextureUtils { const requireDrawFrameBuffer = texture.isDepthTexture === true || ( renderContext.renderTarget && renderContext.renderTarget.samples > 0 ); - const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.gerDrawingBufferSize().y; + const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.getDrawingBufferSize().y; if ( requireDrawFrameBuffer ) { @@ -40209,7 +54030,12 @@ class WebGLTextureUtils { } - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer + /** + * SetupS storage for internal depth/stencil buffers and bind to correct framebuffer. + * + * @param {WebGLRenderbuffer} renderbuffer - The render buffer. + * @param {RenderContext} renderContext - The render context. + */ setupRenderBufferStorage( renderbuffer, renderContext ) { const { gl } = this; @@ -40264,6 +54090,18 @@ class WebGLTextureUtils { } + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { const { backend, gl } = this; @@ -40305,6 +54143,13 @@ class WebGLTextureUtils { } + /** + * Returns the corresponding typed array type for the given WebGL data type. + * + * @private + * @param {GLenum} glType - The WebGL data type. + * @return {TypedArray.constructor} The typed array type. + */ _getTypedArrayType( glType ) { const { gl } = this; @@ -40324,6 +54169,14 @@ class WebGLTextureUtils { } + /** + * Returns the bytes-per-texel value for the given WebGL data type and texture format. + * + * @private + * @param {GLenum} glType - The WebGL data type. + * @param {GLenum} glFormat - The WebGL texture format. + * @return {Number} The bytes-per-texel. + */ _getBytesPerTexel( glType, glFormat ) { const { gl } = this; @@ -40349,19 +54202,58 @@ class WebGLTextureUtils { } +/** + * A WebGL 2 backend utility module for managing extensions. + * + * @private + */ class WebGLExtensions { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = this.backend.gl; + + /** + * A list with all the supported WebGL extensions. + * + * @type {Array} + */ this.availableExtensions = this.gl.getSupportedExtensions(); + /** + * A dictionary with requested WebGL extensions. + * The key is the name of the extension, the value + * the requested extension object. + * + * @type {Object} + */ this.extensions = {}; } + /** + * Returns the extension object for the given extension name. + * + * @param {String} name - The extension name. + * @return {Object} The extension object. + */ get( name ) { let extension = this.extensions[ name ]; @@ -40378,6 +54270,12 @@ class WebGLExtensions { } + /** + * Returns `true` if the requested extension is available. + * + * @param {String} name - The extension name. + * @return {Boolean} Whether the given extension is available or not. + */ has( name ) { return this.availableExtensions.includes( name ); @@ -40386,16 +54284,44 @@ class WebGLExtensions { } +/** + * A WebGL 2 backend utility module for managing the device's capabilities. + * + * @private + */ class WebGLCapabilities { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * This value holds the cached max anisotropy value. + * + * @type {Number?} + * @default null + */ this.maxAnisotropy = null; } + /** + * Returns the maximum anisotropy texture filtering value. This value + * depends on the device and is reported by the `EXT_texture_filter_anisotropic` + * WebGL extension. + * + * @return {Number} The maximum anisotropy texture filtering value. + */ getMaxAnisotropy() { if ( this.maxAnisotropy !== null ) return this.maxAnisotropy; @@ -40573,18 +54499,184 @@ class WebGLBufferRenderer { } -// - +/** + * A backend implementation targeting WebGL 2. + * + * @private + * @augments Backend + */ class WebGLBackend extends Backend { + /** + * Constructs a new WebGPU backend. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. + * @param {WebGL2RenderingContext} [parameters.context=undefined] - A WebGL 2 rendering context. + */ constructor( parameters = {} ) { super( parameters ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGLBackend = true; + /** + * A reference to a backend module holding shader attribute-related + * utility functions. + * + * @type {WebGLAttributeUtils?} + * @default null + */ + this.attributeUtils = null; + + /** + * A reference to a backend module holding extension-related + * utility functions. + * + * @type {WebGLExtensions?} + * @default null + */ + this.extensions = null; + + /** + * A reference to a backend module holding capability-related + * utility functions. + * + * @type {WebGLCapabilities?} + * @default null + */ + this.capabilities = null; + + /** + * A reference to a backend module holding texture-related + * utility functions. + * + * @type {WebGLTextureUtils?} + * @default null + */ + this.textureUtils = null; + + /** + * A reference to a backend module holding renderer-related + * utility functions. + * + * @type {WebGLBufferRenderer?} + * @default null + */ + this.bufferRenderer = null; + + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext?} + * @default null + */ + this.gl = null; + + /** + * A reference to a backend module holding state-related + * utility functions. + * + * @type {WebGLState?} + * @default null + */ + this.state = null; + + /** + * A reference to a backend module holding common + * utility functions. + * + * @type {WebGLUtils?} + * @default null + */ + this.utils = null; + + /** + * Dictionary for caching VAOs. + * + * @type {Object} + */ + this.vaoCache = {}; + + /** + * Dictionary for caching transform feedback objects. + * + * @type {Object} + */ + this.transformFeedbackCache = {}; + + /** + * Controls if `gl.RASTERIZER_DISCARD` should be enabled or not. + * Only relevant when using compute shaders. + * + * @type {Boolean} + * @default false + */ + this.discard = false; + + /** + * A reference to the `EXT_disjoint_timer_query_webgl2` extension. `null` if the + * device does not support the extension. + * + * @type {EXTDisjointTimerQueryWebGL2?} + * @default null + */ + this.disjoint = null; + + /** + * A reference to the `KHR_parallel_shader_compile` extension. `null` if the + * device does not support the extension. + * + * @type {KHRParallelShaderCompile?} + * @default null + */ + this.parallel = null; + + /** + * Whether to track timestamps with a Timestamp Query API or not. + * + * @type {Boolean} + * @default false + */ + this.trackTimestamp = ( parameters.trackTimestamp === true ); + + /** + * A reference to the current render context. + * + * @private + * @type {RenderContext} + * @default null + */ + this._currentContext = null; + + /** + * A unique collection of bindings. + * + * @private + * @type {WeakSet} + */ + this._knownBindings = new WeakSet(); + } + /** + * Initializes the backend so it is ready for usage. + * + * @param {Renderer} renderer - The renderer. + */ init( renderer ) { super.init( renderer ); @@ -40625,11 +54717,6 @@ class WebGLBackend extends Backend { 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' ); @@ -40641,30 +54728,52 @@ class WebGLBackend extends Backend { this.disjoint = this.extensions.get( 'EXT_disjoint_timer_query_webgl2' ); this.parallel = this.extensions.get( 'KHR_parallel_shader_compile' ); - this._knownBindings = new WeakSet(); - - this._currentContext = null; - } + /** + * The coordinate system of the backend. + * + * @type {Number} + * @readonly + */ get coordinateSystem() { return WebGLCoordinateSystem; } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { return await this.attributeUtils.getArrayBufferAsync( attribute ); } + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ async waitForGPU() { await this.utils._clientWaitAsync(); } + /** + * Inits a time stamp query for the given render context. + * + * @param {RenderContext} renderContext - The render context. + */ initTimestampQuery( renderContext ) { if ( ! this.disjoint || ! this.trackTimestamp ) return; @@ -40699,6 +54808,11 @@ class WebGLBackend extends Backend { // timestamp utils + /** + * Prepares the timestamp buffer. + * + * @param {RenderContext} renderContext - The render context. + */ prepareTimestampBuffer( renderContext ) { if ( ! this.disjoint || ! this.trackTimestamp ) return; @@ -40725,6 +54839,14 @@ class WebGLBackend extends Backend { } + /** + * Resolves the time stamp for the given render context and type. + * + * @async + * @param {RenderContext} renderContext - The render context. + * @param {String} type - The render context. + * @return {Promise} A Promise that resolves when the time stamp has been computed. + */ async resolveTimestampAsync( renderContext, type = 'render' ) { if ( ! this.disjoint || ! this.trackTimestamp ) return; @@ -40754,12 +54876,23 @@ class WebGLBackend extends Backend { } + /** + * Returns the backend's rendering context. + * + * @return {WebGL2RenderingContext} The rendering context. + */ getContext() { return this.gl; } + /** + * This method is executed at the beginning of a render call and prepares + * the WebGL state for upcoming render calls + * + * @param {RenderContext} renderContext - The render context. + */ beginRender( renderContext ) { const { gl } = this; @@ -40815,6 +54948,12 @@ class WebGLBackend extends Backend { } + /** + * This method is executed at the end of a render call and finalizes work + * after draw calls. + * + * @param {RenderContext} renderContext - The render context. + */ finishRender( renderContext ) { const { gl, state } = this; @@ -40921,6 +55060,13 @@ class WebGLBackend extends Backend { } + /** + * This method processes the result of occlusion queries and writes it + * into render context data. + * + * @async + * @param {RenderContext} renderContext - The render context. + */ resolveOccludedAsync( renderContext ) { const renderContextData = this.get( renderContext ); @@ -40950,7 +55096,7 @@ class WebGLBackend extends Backend { if ( gl.getQueryParameter( query, gl.QUERY_RESULT_AVAILABLE ) ) { - if ( gl.getQueryParameter( query, gl.QUERY_RESULT ) > 0 ) occluded.add( currentOcclusionQueryObjects[ i ] ); + if ( gl.getQueryParameter( query, gl.QUERY_RESULT ) === 0 ) occluded.add( currentOcclusionQueryObjects[ i ] ); currentOcclusionQueries[ i ] = null; gl.deleteQuery( query ); @@ -40979,6 +55125,14 @@ class WebGLBackend extends Backend { } + /** + * Returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ isOccluded( renderContext, object ) { const renderContextData = this.get( renderContext ); @@ -40987,6 +55141,11 @@ class WebGLBackend extends Backend { } + /** + * Updates the viewport with the values from the given render context. + * + * @param {RenderContext} renderContext - The render context. + */ updateViewport( renderContext ) { const gl = this.gl; @@ -40996,6 +55155,11 @@ class WebGLBackend extends Backend { } + /** + * Defines the scissor test. + * + * @param {Boolean} boolean - Whether the scissor test should be enabled or not. + */ setScissorTest( boolean ) { const gl = this.gl; @@ -41012,6 +55176,15 @@ class WebGLBackend extends Backend { } + /** + * Performs a clear operation. + * + * @param {Boolean} color - Whether the color buffer should be cleared or not. + * @param {Boolean} depth - Whether the depth buffer should be cleared or not. + * @param {Boolean} stencil - Whether the stencil buffer should be cleared or not. + * @param {Object?} [descriptor=null] - The render context of the current set render target. + * @param {Boolean} [setFrameBuffer=true] - TODO. + */ clear( color, depth, stencil, descriptor = null, setFrameBuffer = true ) { const { gl } = this; @@ -41102,6 +55275,12 @@ class WebGLBackend extends Backend { } + /** + * This method is executed at the beginning of a compute call and + * prepares the state for upcoming compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ beginCompute( computeGroup ) { const { state, gl } = this; @@ -41111,11 +55290,19 @@ class WebGLBackend extends Backend { } + /** + * Executes a compute command for the given compute node. + * + * @param {Node|Array} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @param {ComputePipeline} pipeline - The compute pipeline. + */ compute( computeGroup, computeNode, bindings, pipeline ) { const { state, gl } = this; - if ( ! this.discard ) { + if ( this.discard === false ) { // required here to handle async behaviour of render.compute() gl.enable( gl.RASTERIZER_DISCARD ); @@ -41180,6 +55367,12 @@ class WebGLBackend extends Backend { } + /** + * This method is executed at the end of a compute call and + * finalizes work after compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ finishCompute( computeGroup ) { const gl = this.gl; @@ -41198,6 +55391,12 @@ class WebGLBackend extends Backend { } + /** + * Executes a draw command for the given render object. + * + * @param {RenderObject} renderObject - The render object to draw. + * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. + */ draw( renderObject/*, info*/ ) { const { object, pipeline, material, context, hardwareClippingPlanes } = renderObject; @@ -41360,12 +55559,24 @@ class WebGLBackend extends Backend { } + /** + * Explain why always null is returned. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render pipeline requires an update or not. + */ needsRenderUpdate( /*renderObject*/ ) { return false; } + /** + * Explain why no cache key is computed. + * + * @param {RenderObject} renderObject - The render object. + * @return {String} The cache key. + */ getRenderCacheKey( /*renderObject*/ ) { return ''; @@ -41374,53 +55585,109 @@ class WebGLBackend extends Backend { // textures + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { this.textureUtils.createDefaultTexture( texture ); } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ createTexture( texture, options ) { this.textureUtils.createTexture( texture, options ); } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { this.textureUtils.updateTexture( texture, options ); } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { this.textureUtils.generateMipmaps( texture ); } - + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { this.textureUtils.destroyTexture( texture ); } - copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); } + /** + * This method does nothing since WebGL 2 has no concept of samplers. + * + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( /*texture*/ ) { //console.warn( 'Abstract class.' ); } - destroySampler() {} + /** + * This method does nothing since WebGL 2 has no concept of samplers. + * + * @param {Texture} texture - The texture to destroy the sampler for. + */ + destroySampler( /*texture*/ ) {} // node builder + /** + * Returns a node builder for the given render object. + * + * @param {RenderObject} object - The render object. + * @param {Renderer} renderer - The renderer. + * @return {GLSLNodeBuilder} The node builder. + */ createNodeBuilder( object, renderer ) { return new GLSLNodeBuilder( object, renderer ); @@ -41429,6 +55696,11 @@ class WebGLBackend extends Backend { // program + /** + * Creates a shader program from the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ createProgram( program ) { const gl = this.gl; @@ -41445,12 +55717,23 @@ class WebGLBackend extends Backend { } - destroyProgram( /*program*/ ) { + /** + * Destroys the shader program of the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ + destroyProgram( program ) { - console.warn( 'Abstract class.' ); + this.delete( program ); } + /** + * Creates a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ createRenderPipeline( renderObject, promises ) { const gl = this.gl; @@ -41509,6 +55792,14 @@ class WebGLBackend extends Backend { } + /** + * Formats the source code of error messages. + * + * @private + * @param {String} string - The code. + * @param {Number} errorLine - The error line. + * @return {String} The formatted code. + */ _handleSource( string, errorLine ) { const lines = string.split( '\n' ); @@ -41528,6 +55819,15 @@ class WebGLBackend extends Backend { } + /** + * Gets the shader compilation errors from the info log. + * + * @private + * @param {WebGL2RenderingContext} gl - The rendering context. + * @param {WebGLShader} shader - The WebGL shader object. + * @param {String} type - The shader type. + * @return {String} The shader errors. + */ _getShaderErrors( gl, shader, type ) { const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); @@ -41549,6 +55849,14 @@ class WebGLBackend extends Backend { } + /** + * Logs shader compilation errors. + * + * @private + * @param {WebGLProgram} programGPU - The WebGL program. + * @param {WebGLShader} glFragmentShader - The fragment shader as a native WebGL shader object. + * @param {WebGLShader} glVertexShader - The vertex shader as a native WebGL shader object. + */ _logProgramError( programGPU, glFragmentShader, glVertexShader ) { if ( this.renderer.debug.checkShaderErrors ) { @@ -41591,6 +55899,13 @@ class WebGLBackend extends Backend { } + /** + * Completes the shader program setup for the given render object. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @param {RenderPipeline} pipeline - The render pipeline. + */ _completeCompile( renderObject, pipeline ) { const { state, gl } = this; @@ -41619,6 +55934,12 @@ class WebGLBackend extends Backend { } + /** + * Creates a compute pipeline for the given compute node. + * + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ createComputePipeline( computePipeline, bindings ) { const { state, gl } = this; @@ -41713,7 +56034,15 @@ class WebGLBackend extends Backend { } - createBindings( bindGroup, bindings ) { + /** + * Creates bindings from the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + createBindings( bindGroup, bindings /*, cacheIndex, version*/ ) { if ( this._knownBindings.has( bindings ) === false ) { @@ -41744,7 +56073,15 @@ class WebGLBackend extends Backend { } - updateBindings( bindGroup /*, bindings*/ ) { + /** + * Updates the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + updateBindings( bindGroup /*, bindings, cacheIndex, version*/ ) { const { gl } = this; @@ -41784,6 +56121,11 @@ class WebGLBackend extends Backend { } + /** + * Updates a buffer binding. + * + * @param {Buffer} binding - The buffer binding to update. + */ updateBinding( binding ) { const gl = this.gl; @@ -41803,6 +56145,11 @@ class WebGLBackend extends Backend { // attributes + /** + * Creates the GPU buffer of an indexed shader attribute. + * + * @param {BufferAttribute} attribute - The indexed buffer attribute. + */ createIndexAttribute( attribute ) { const gl = this.gl; @@ -41811,6 +56158,11 @@ class WebGLBackend extends Backend { } + /** + * Creates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createAttribute( attribute ) { if ( this.has( attribute ) ) return; @@ -41821,6 +56173,11 @@ class WebGLBackend extends Backend { } + /** + * Creates the GPU buffer of a storage attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createStorageAttribute( attribute ) { if ( this.has( attribute ) ) return; @@ -41831,24 +56188,34 @@ class WebGLBackend extends Backend { } + /** + * Updates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to update. + */ updateAttribute( attribute ) { this.attributeUtils.updateAttribute( attribute ); } + /** + * Destroys the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to destroy. + */ destroyAttribute( attribute ) { this.attributeUtils.destroyAttribute( attribute ); } - updateSize() { - - //console.warn( 'Abstract class.' ); - - } - + /** + * Checks if the given feature is supported by the backend. + * + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ hasFeature( name ) { const keysMatching = Object.keys( GLFeatureName ).filter( key => GLFeatureName[ key ] === name ); @@ -41865,24 +56232,51 @@ class WebGLBackend extends Backend { } + /** + * Returns the maximum anisotropy texture filtering value. + * + * @return {Number} The maximum anisotropy texture filtering value. + */ getMaxAnisotropy() { return this.capabilities.getMaxAnisotropy(); } - copyTextureToTexture( srcTexture, dstTexture, srcRegion, dstPosition, level ) { + /** + * Copies data of the given source texture to the given destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ + copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { this.textureUtils.copyTextureToTexture( srcTexture, dstTexture, srcRegion, dstPosition, level ); } + /** + * Copies the current bound framebuffer to the given texture. + * + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ copyFramebufferToTexture( texture, renderContext, rectangle ) { this.textureUtils.copyFramebufferToTexture( texture, renderContext, rectangle ); } + /** + * Configures the active framebuffer from the given render context. + * + * @private + * @param {RenderContext} descriptor - The render context. + */ _setFramebuffer( descriptor ) { const { gl, state } = this; @@ -41896,6 +56290,8 @@ class WebGLBackend extends Backend { const { samples, depthBuffer, stencilBuffer } = renderTarget; const isCube = renderTarget.isWebGLCubeRenderTarget === true; + const isRenderTarget3D = renderTarget.isRenderTarget3D === true; + const isRenderTargetArray = renderTarget.isRenderTargetArray === true; let msaaFb = renderTargetContextData.msaaFrameBuffer; let depthRenderbuffer = renderTargetContextData.depthRenderbuffer; @@ -41949,7 +56345,19 @@ class WebGLBackend extends Backend { const attachment = gl.COLOR_ATTACHMENT0 + i; - gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0 ); + if ( isRenderTarget3D || isRenderTargetArray ) { + + const layer = this.renderer._activeCubeFace; + + gl.framebufferTextureLayer( gl.FRAMEBUFFER, attachment, textureData.textureGPU, 0, layer ); + + } else { + + gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0 ); + + } + + } @@ -42041,10 +56449,17 @@ class WebGLBackend extends Backend { } - + /** + * Computes the VAO key for the given index and attributes. + * + * @private + * @param {BufferAttribute?} index - The index. `null` for non-indexed geometries. + * @param {Array} attributes - An array of buffer attributes. + * @return {String} The VAO key. + */ _getVaoKey( index, attributes ) { - let key = []; + let key = ''; if ( index !== null ) { @@ -42066,6 +56481,14 @@ class WebGLBackend extends Backend { } + /** + * Creates a VAO from the index and attributes. + * + * @private + * @param {BufferAttribute?} index - The index. `null` for non-indexed geometries. + * @param {Array} attributes - An array of buffer attributes. + * @return {Object} The VAO data. + */ _createVao( index, attributes ) { const { gl } = this; @@ -42143,6 +56566,13 @@ class WebGLBackend extends Backend { } + /** + * Creates a transform feedback from the given transform buffers. + * + * @private + * @param {Array} transformBuffers - The transform buffers. + * @return {WebGLTransformFeedback} The transform feedback. + */ _getTransformFeedback( transformBuffers ) { let key = ''; @@ -42183,7 +56613,13 @@ class WebGLBackend extends Backend { } - + /** + * Setups the given bindings. + * + * @private + * @param {Array} bindings - The bindings. + * @param {WebGLProgram} programGPU - The WebGL program. + */ _setupBindings( bindings, programGPU ) { const gl = this.gl; @@ -42213,6 +56649,12 @@ class WebGLBackend extends Backend { } + /** + * Binds the given uniforms. + * + * @private + * @param {Array} bindings - The bindings. + */ _bindUniforms( bindings ) { const { gl, state } = this; @@ -42241,6 +56683,9 @@ class WebGLBackend extends Backend { } + /** + * Frees internal resources. + */ dispose() { this.renderer.domElement.removeEventListener( 'webglcontextlost', this._onContextLost ); @@ -42544,32 +56989,90 @@ const GPUFeatureName = { Subgroups: 'subgroups' }; +/** + * Represents a sampler binding type. + * + * @private + * @augments Binding + */ class Sampler extends Binding { + /** + * Constructs a new sampler. + * + * @param {String} name - The samplers's name. + * @param {Texture?} texture - The texture this binding is referring to. + */ constructor( name, texture ) { super( name ); + /** + * The texture the sampler is referring to. + * + * @type {Texture?} + */ this.texture = texture; + + /** + * The binding's version. + * + * @type {Number} + */ this.version = texture ? texture.version : 0; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampler = true; } } +/** + * A special form of sampler binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments Sampler + */ class NodeSampler extends Sampler { + /** + * Constructs a new node-based sampler. + * + * @param {String} name - The samplers's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( name, textureNode, groupNode ) { super( name, textureNode ? textureNode.value : null ); + /** + * The texture node. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; } + /** + * Updates the texture value of this sampler. + */ update() { this.texture = this.textureNode.value; @@ -42578,14 +57081,38 @@ class NodeSampler extends Sampler { } +/** + * Represents a storage buffer binding type. + * + * @private + * @augments Buffer + */ class StorageBuffer extends Buffer { + /** + * Constructs a new uniform buffer. + * + * @param {String} name - The buffer's name. + * @param {BufferAttribute} attribute - The buffer attribute. + */ constructor( name, attribute ) { super( name, attribute ? attribute.array : null ); + /** + * This flag can be used for type testing. + * + * @type {BufferAttribute} + */ this.attribute = attribute; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageBuffer = true; } @@ -42594,18 +57121,53 @@ class StorageBuffer extends Buffer { let _id = 0; +/** + * A special form of storage buffer binding type. + * It's buffer value is managed by a node object. + * + * @private + * @augments StorageBuffer + */ class NodeStorageBuffer extends StorageBuffer { + /** + * Constructs a new node-based storage buffer. + * + * @param {StorageBufferNode} nodeUniform - The storage buffer node. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( nodeUniform, groupNode ) { super( 'StorageBuffer_' + _id ++, nodeUniform ? nodeUniform.value : null ); + /** + * The node uniform. + * + * @type {StorageBufferNode} + */ this.nodeUniform = nodeUniform; + + /** + * The access type. + * + * @type {String} + */ this.access = nodeUniform ? nodeUniform.access : NodeAccess.READ_WRITE; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; } + /** + * The storage buffer. + * + * @type {BufferAttribute} + */ get buffer() { return this.nodeUniform.value; @@ -42614,12 +57176,27 @@ class NodeStorageBuffer extends StorageBuffer { } +/** + * A WebGPU backend utility module used by {@link WebGPUTextureUtils}. + * + * @private + */ class WebGPUTexturePassUtils extends DataMap { + /** + * Constructs a new utility object. + * + * @param {GPUDevice} device - The WebGPU device. + */ constructor( device ) { super(); + /** + * The WebGPU device. + * + * @type {GPUDevice} + */ this.device = device; const mipmapVertexSource = ` @@ -42684,23 +57261,62 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } `; + + /** + * The mipmap GPU sampler. + * + * @type {GPUSampler} + */ this.mipmapSampler = device.createSampler( { minFilter: GPUFilterMode.Linear } ); + + /** + * The flipY GPU sampler. + * + * @type {GPUSampler} + */ this.flipYSampler = device.createSampler( { minFilter: GPUFilterMode.Nearest } ); //@TODO?: Consider using textureLoad() - // We'll need a new pipeline for every texture format used. + /** + * A cache for GPU render pipelines used for copy/transfer passes. + * Every texture format requires a unique pipeline. + * + * @type {Object} + */ this.transferPipelines = {}; + + /** + * A cache for GPU render pipelines used for flipY passes. + * Every texture format requires a unique pipeline. + * + * @type {Object} + */ this.flipYPipelines = {}; + /** + * The mipmap vertex shader module. + * + * @type {GPUShaderModule} + */ this.mipmapVertexShaderModule = device.createShaderModule( { label: 'mipmapVertex', code: mipmapVertexSource } ); + /** + * The mipmap fragment shader module. + * + * @type {GPUShaderModule} + */ this.mipmapFragmentShaderModule = device.createShaderModule( { label: 'mipmapFragment', code: mipmapFragmentSource } ); + /** + * The flipY fragment shader module. + * + * @type {GPUShaderModule} + */ this.flipYFragmentShaderModule = device.createShaderModule( { label: 'flipYFragment', code: flipYFragmentSource @@ -42708,6 +57324,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Returns a render pipeline for the internal copy render pass. The pass + * requires a unique render pipeline for each texture format. + * + * @param {String} format - The GPU texture format + * @return {GPURenderPipeline} The GPU render pipeline. + */ getTransferPipeline( format ) { let pipeline = this.transferPipelines[ format ]; @@ -42740,6 +57363,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Returns a render pipeline for the flipY render pass. The pass + * requires a unique render pipeline for each texture format. + * + * @param {String} format - The GPU texture format + * @return {GPURenderPipeline} The GPU render pipeline. + */ getFlipYPipeline( format ) { let pipeline = this.flipYPipelines[ format ]; @@ -42772,6 +57402,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Flip the contents of the given GPU texture along its vertical axis. + * + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureGPUDescriptor - The texture descriptor. + * @param {Number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. + */ flipY( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) { const format = textureGPUDescriptor.format; @@ -42842,6 +57479,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Generates mipmaps for the given GPU texture. + * + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureGPUDescriptor - The texture descriptor. + * @param {Number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. + */ generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) { const textureData = this.get( textureGPU ); @@ -42867,6 +57511,15 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Since multiple copy render passes are required to generate mipmaps, the passes + * are managed as render bundles to improve performance. + * + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureGPUDescriptor - The texture descriptor. + * @param {Number} baseArrayLayer - The index of the first array layer accessible to the texture view. + * @return {Array} An array of render bundles. + */ _mipmapCreateBundles( textureGPU, textureGPUDescriptor, baseArrayLayer ) { const pipeline = this.getTransferPipeline( textureGPUDescriptor.format ); @@ -42932,6 +57585,12 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Executes the render bundles. + * + * @param {GPUCommandEncoder} commandEncoder - The GPU command encoder. + * @param {Array} passes - An array of render bundles. + */ _mipmapRunBundles( commandEncoder, passes ) { const levels = passes.length; @@ -42965,25 +57624,82 @@ const _compareToWebGPU = { const _flipMap = [ 0, 1, 3, 2, 4, 5 ]; +/** + * A WebGPU backend utility module for managing textures. + * + * @private + */ class WebGPUTextureUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; + /** + * A reference to the pass utils. + * + * @type {WebGPUTexturePassUtils?} + * @default null + */ this._passUtils = null; + /** + * A dictionary for managing default textures. The key + * is the texture format, the value the texture object. + * + * @type {Object} + */ this.defaultTexture = {}; + + /** + * A dictionary for managing default cube textures. The key + * is the texture format, the value the texture object. + * + * @type {Object} + */ this.defaultCubeTexture = {}; + + /** + * A default video frame. + * + * @type {VideoFrame?} + * @default null + */ this.defaultVideoFrame = null; + /** + * Represents the color attachment of the default framebuffer. + * + * @type {GPUTexture?} + * @default null + */ this.colorBuffer = null; + /** + * Represents the depth attachment of the default framebuffer. + * + * @type {DepthTexture} + */ this.depthTexture = new DepthTexture(); this.depthTexture.name = 'depthBuffer'; } + /** + * Creates a GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( texture ) { const backend = this.backend; @@ -43019,6 +57735,12 @@ class WebGPUTextureUtils { } + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { let textureGPU; @@ -43043,6 +57765,13 @@ class WebGPUTextureUtils { } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + * @return {undefined} + */ createTexture( texture, options = {} ) { const backend = this.backend; @@ -43154,6 +57883,11 @@ class WebGPUTextureUtils { } + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { const backend = this.backend; @@ -43167,6 +57901,11 @@ class WebGPUTextureUtils { } + /** + * Destroys the GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to destroy the sampler for. + */ destroySampler( texture ) { const backend = this.backend; @@ -43176,6 +57915,11 @@ class WebGPUTextureUtils { } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { const textureData = this.backend.get( texture ); @@ -43202,6 +57946,12 @@ class WebGPUTextureUtils { } + /** + * Returns the color buffer representing the color + * attachment of the default framebuffer. + * + * @return {GPUTexture} The color buffer. + */ getColorBuffer() { if ( this.colorBuffer ) this.colorBuffer.destroy(); @@ -43225,6 +57975,14 @@ class WebGPUTextureUtils { } + /** + * Returns the depth buffer representing the depth + * attachment of the default framebuffer. + * + * @param {Boolean} [depth=true] - Whether depth is enabled or not. + * @param {Boolean} [stencil=false] - Whether stencil is enabled or not. + * @return {GPUTexture} The depth buffer. + */ getDepthBuffer( depth = true, stencil = false ) { const backend = this.backend; @@ -43271,6 +58029,12 @@ class WebGPUTextureUtils { } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { const textureData = this.backend.get( texture ); @@ -43322,6 +58086,18 @@ class WebGPUTextureUtils { } + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { const device = this.backend.device; @@ -43371,6 +58147,13 @@ class WebGPUTextureUtils { } + /** + * Returns `true` if the given texture is an environment map. + * + * @private + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the given texture is an environment map or not. + */ _isEnvironmentTexture( texture ) { const mapping = texture.mapping; @@ -43379,6 +58162,13 @@ class WebGPUTextureUtils { } + /** + * Returns the default GPU texture for the given format. + * + * @private + * @param {String} format - The GPU format. + * @return {GPUTexture} The GPU texture. + */ _getDefaultTextureGPU( format ) { let defaultTexture = this.defaultTexture[ format ]; @@ -43399,6 +58189,13 @@ class WebGPUTextureUtils { } + /** + * Returns the default GPU cube texture for the given format. + * + * @private + * @param {String} format - The GPU format. + * @return {GPUTexture} The GPU texture. + */ _getDefaultCubeTextureGPU( format ) { let defaultCubeTexture = this.defaultTexture[ format ]; @@ -43419,6 +58216,12 @@ class WebGPUTextureUtils { } + /** + * Returns the default video frame used as default data in context of video textures. + * + * @private + * @return {VideoFrame} The video frame. + */ _getDefaultVideoFrame() { let defaultVideoFrame = this.defaultVideoFrame; @@ -43440,6 +58243,15 @@ class WebGPUTextureUtils { } + /** + * Uploads cube texture image data to the GPU memory. + * + * @private + * @param {Array} images - The cube image data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + * @param {Boolean} flipY - Whether to flip texture data along their vertical axis or not. + */ _copyCubeMapToTexture( images, textureGPU, textureDescriptorGPU, flipY ) { for ( let i = 0; i < 6; i ++ ) { @@ -43462,13 +58274,24 @@ class WebGPUTextureUtils { } + /** + * Uploads texture image data to the GPU memory. + * + * @private + * @param {HTMLImageElement|ImageBitmap|HTMLCanvasElement} image - The image data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + * @param {Number} originDepth - The origin depth. + * @param {Boolean} flipY - Whether to flip texture data along their vertical axis or not. + */ _copyImageToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY ) { const device = this.backend.device; device.queue.copyExternalImageToTexture( { - source: image + source: image, + flipY: flipY }, { texture: textureGPU, mipLevel: 0, @@ -43480,14 +58303,14 @@ class WebGPUTextureUtils { } ); - if ( flipY === true ) { - - this._flipY( textureGPU, textureDescriptorGPU, originDepth ); - - } - } + /** + * Returns the pass utils singleton. + * + * @private + * @return {WebGPUTexturePassUtils} The utils instance. + */ _getPassUtils() { let passUtils = this._passUtils; @@ -43502,18 +58325,45 @@ class WebGPUTextureUtils { } + /** + * Generates mipmaps for the given GPU texture. + * + * @private + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureDescriptorGPU - The texture descriptor. + * @param {Number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. + */ _generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0 ) { this._getPassUtils().generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer ); } + /** + * Flip the contents of the given GPU texture along its vertical axis. + * + * @private + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureDescriptorGPU - The texture descriptor. + * @param {Number} [originDepth=0] - The origin depth. + */ _flipY( textureGPU, textureDescriptorGPU, originDepth = 0 ) { this._getPassUtils().flipY( textureGPU, textureDescriptorGPU, originDepth ); } + /** + * Uploads texture buffer data to the GPU memory. + * + * @private + * @param {Object} image - An object defining the image buffer data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + * @param {Number} originDepth - The origin depth. + * @param {Boolean} flipY - Whether to flip texture data along their vertical axis or not. + * @param {Number} [depth=0] - TODO. + */ _copyBufferToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY, depth = 0 ) { // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture() @@ -43551,6 +58401,14 @@ class WebGPUTextureUtils { } + /** + * Uploads compressed texture data to the GPU memory. + * + * @private + * @param {Array} mipmaps - An array with mipmap data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + */ _copyCompressedBufferToTexture( mipmaps, textureGPU, textureDescriptorGPU ) { // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture() @@ -43598,10 +58456,16 @@ class WebGPUTextureUtils { } + /** + * This method is only relevant for compressed texture formats. It returns a block + * data descriptor for the given GPU compressed texture format. + * + * @private + * @param {String} format - The GPU compressed texture format. + * @return {Object} The block data descriptor. + */ _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 @@ -43635,6 +58499,13 @@ class WebGPUTextureUtils { } + /** + * Converts the three.js uv wrapping constants to GPU address mode constants. + * + * @private + * @param {Number} value - The three.js constant defining a uv wrapping mode. + * @return {String} The GPU address mode. + */ _convertAddressMode( value ) { let addressMode = GPUAddressMode.ClampToEdge; @@ -43653,6 +58524,13 @@ class WebGPUTextureUtils { } + /** + * Converts the three.js filter constants to GPU filter constants. + * + * @private + * @param {Number} value - The three.js constant defining a filter mode. + * @return {String} The GPU filter mode. + */ _convertFilterMode( value ) { let filterMode = GPUFilterMode.Linear; @@ -43667,6 +58545,13 @@ class WebGPUTextureUtils { } + /** + * Returns the bytes-per-texel value for the given GPU texture format. + * + * @private + * @param {String} format - The GPU texture format. + * @return {Number} The bytes-per-texel. + */ _getBytesPerTexel( format ) { // 8-bit formats @@ -43723,6 +58608,13 @@ class WebGPUTextureUtils { } + /** + * Returns the corresponding typed array type for the given GPU texture format. + * + * @private + * @param {String} format - The GPU texture format. + * @return {TypedArray.constructor} The typed array type. + */ _getTypedArrayType( format ) { if ( format === GPUTextureFormat.R8Uint ) return Uint8Array; @@ -43773,6 +58665,13 @@ class WebGPUTextureUtils { } + /** + * Returns the GPU dimensions for the given texture. + * + * @private + * @param {Texture} texture - The texture. + * @return {String} The GPU dimension. + */ _getDimension( texture ) { let dimension; @@ -43793,6 +58692,14 @@ class WebGPUTextureUtils { } +/** + * Returns the GPU format for the given texture. + * + * @param {Texture} texture - The texture. + * @param {GPUDevice?} [device=null] - The GPU device which is used for feature detection. + * It is not necessary to apply the device for most formats. + * @return {String} The GPU format. + */ function getFormat( texture, device = null ) { const format = texture.format; @@ -44212,6 +59119,7 @@ const wgslTypeLib$1 = { 'texture_multisampled_2d': 'cubeTexture', 'texture_depth_2d': 'depthTexture', + 'texture_depth_multisampled_2d': 'depthTexture', 'texture_3d': 'texture3D', @@ -44494,30 +59402,83 @@ if ( ( typeof navigator !== 'undefined' && /Firefox|Deno/g.test( navigator.userA } -// - +/** + * A node builder targeting WGSL. + * + * This module generates WGSL shader code from node materials and also + * generates the respective bindings and vertex buffer definitions. These + * data are later used by the renderer to create render and compute pipelines + * for render objects. + * + * @augments NodeBuilder + */ class WGSLNodeBuilder extends NodeBuilder { + /** + * Constructs a new WGSL node builder renderer. + * + * @param {Object3D} object - The 3D object. + * @param {Renderer} renderer - The renderer. + */ constructor( object, renderer ) { super( object, renderer, new WGSLNodeParser() ); + /** + * A dictionary that holds for each shader stage ('vertex', 'fragment', 'compute') + * another dictionary which manages UBOs per group ('render','frame','object'). + * + * @type {Object>} + */ this.uniformGroups = {}; + /** + * A dictionary that holds for each shader stage a Map of builtins. + * + * @type {Object>} + */ this.builtins = {}; + /** + * A dictionary that holds for each shader stage a Set of directives. + * + * @type {Object>} + */ this.directives = {}; + /** + * A map for managing scope arrays. Only relevant for when using + * {@link module:WorkgroupInfoNode} in context of compute shaders. + * + * @type {Map} + */ this.scopedArrays = new Map(); } + /** + * Checks if the given texture requires a manual conversion to the working color space. + * + * @param {Texture} texture - The texture to check. + * @return {Boolean} Whether the given texture requires a conversion to working color space or not. + */ needsToWorkingColorSpace( texture ) { return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace; } + /** + * Generates the WGSL snippet for sampled textures. + * + * @private + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ _generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44544,6 +59505,15 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling video textures. + * + * @private + * @param {String} textureProperty - The name of the video texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ _generateVideoSample( textureProperty, uvSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44558,6 +59528,18 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling textures with explicit mip level. + * + * @private + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ _generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( ( shaderStage === 'fragment' || shaderStage === 'compute' ) && this.isUnfilterable( texture ) === false ) { @@ -44576,9 +59558,15 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates a wrap function used in context of textures. + * + * @param {Texture} texture - The texture to generate the function for. + * @return {String} The name of the generated function. + */ generateWrapFunction( texture ) { - const functionName = `tsl_coord_${ wrapNames[ texture.wrapS ] }S_${ wrapNames[ texture.wrapT ] }T`; + const functionName = `tsl_coord_${ wrapNames[ texture.wrapS ] }S_${ wrapNames[ texture.wrapT ] }_${texture.isData3DTexture ? '3d' : '2d'}T`; let nodeCode = wgslCodeCache[ functionName ]; @@ -44586,7 +59574,9 @@ class WGSLNodeBuilder extends NodeBuilder { const includes = []; - let code = `fn ${ functionName }( coord : vec2f ) -> vec2f {\n\n\treturn vec2f(\n`; + // For 3D textures, use vec3f; for texture arrays, keep vec2f since array index is separate + const coordType = texture.isData3DTexture ? 'vec3f' : 'vec2f'; + let code = `fn ${functionName}( coord : ${coordType} ) -> ${coordType} {\n\n\treturn ${coordType}(\n`; const addWrapSnippet = ( wrap, axis ) => { @@ -44624,6 +59614,13 @@ class WGSLNodeBuilder extends NodeBuilder { addWrapSnippet( texture.wrapT, 'y' ); + if ( texture.isData3DTexture ) { + + code += ',\n'; + addWrapSnippet( texture.wrapR, 'z' ); + + } + code += '\n\t);\n\n}\n'; wgslCodeCache[ functionName ] = nodeCode = new CodeNode( code, includes ); @@ -44636,6 +59633,16 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates a WGSL variable that holds the texture dimension of the given texture. + * It also returns information about the the number of layers (elements) of an arrayed + * texture as well as the cube face count of cube textures. + * + * @param {Texture} texture - The texture to generate the function for. + * @param {String} textureProperty - The name of the video texture uniform in the shader. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The name of the dimension variable. + */ generateTextureDimension( texture, textureProperty, levelSnippet ) { const textureData = this.getDataFromNode( texture, this.shaderStage, this.globalCache ); @@ -44647,29 +59654,72 @@ class WGSLNodeBuilder extends NodeBuilder { if ( textureData.dimensionsSnippet[ levelSnippet ] === undefined ) { let textureDimensionsParams; + let dimensionType; const { primarySamples } = this.renderer.backend.utils.getTextureSampleData( texture ); + const isMultisampled = primarySamples > 1; + + if ( texture.isData3DTexture ) { + + dimensionType = 'vec3'; + + } else { + + // Regular 2D textures, depth textures, etc. + dimensionType = 'vec2'; + + } - if ( primarySamples > 1 ) { + // Build parameters string based on texture type and multisampling + if ( isMultisampled || texture.isVideoTexture || texture.isStorageTexture ) { textureDimensionsParams = textureProperty; } else { - textureDimensionsParams = `${ textureProperty }, u32( ${ levelSnippet } )`; + textureDimensionsParams = `${textureProperty}${levelSnippet ? `, u32( ${ levelSnippet } )` : ''}`; } - textureDimensionNode = new VarNode( new ExpressionNode( `textureDimensions( ${ textureDimensionsParams } )`, 'uvec2' ) ); + textureDimensionNode = new VarNode( new ExpressionNode( `textureDimensions( ${ textureDimensionsParams } )`, dimensionType ) ); textureData.dimensionsSnippet[ levelSnippet ] = textureDimensionNode; + if ( texture.isDataArrayTexture || texture.isData3DTexture ) { + + textureData.arrayLayerCount = new VarNode( + new ExpressionNode( + `textureNumLayers(${textureProperty})`, + 'u32' + ) + ); + + } + + // For cube textures, we know it's always 6 faces + if ( texture.isTextureCube ) { + + textureData.cubeFaceCount = new VarNode( + new ExpressionNode( '6u', 'u32' ) + ); + + } + } return textureDimensionNode.build( this ); } + /** + * Generates the WGSL snippet for a manual filtered texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The WGSL snippet. + */ generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet = '0u' ) { this._include( 'biquadraticTexture' ); @@ -44681,17 +59731,39 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for a texture lookup with explicit level-of-detail. + * Since it's a lookup, no sampling or filtering is applied. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The WGSL snippet. + */ generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, levelSnippet = '0u' ) { const wrapFunction = this.generateWrapFunction( texture ); const textureDimension = this.generateTextureDimension( texture, textureProperty, levelSnippet ); - const coordSnippet = `vec2u( ${ wrapFunction }( ${ uvSnippet } ) * vec2f( ${ textureDimension } ) )`; + const vecType = texture.isData3DTexture ? 'vec3' : 'vec2'; + const coordSnippet = `${vecType}(${wrapFunction}(${uvSnippet}) * ${vecType}(${textureDimension}))`; return this.generateTextureLoad( texture, textureProperty, coordSnippet, depthSnippet, levelSnippet ); } + /** + * Generates the WGSL snippet that reads a single texel from a texture without sampling or filtering. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The WGSL snippet. + */ generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0u' ) { if ( texture.isVideoTexture === true || texture.isStorageTexture === true ) { @@ -44710,18 +59782,39 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet that writes a single texel to a texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} valueSnippet - A WGSL snippet that represent the new texel value. + * @return {String} The WGSL snippet. + */ generateTextureStore( texture, textureProperty, uvIndexSnippet, valueSnippet ) { return `textureStore( ${ textureProperty }, ${ uvIndexSnippet }, ${ valueSnippet } )`; } + /** + * Returns `true` if the sampled values of the given texture should be compared against a reference value. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the sampled values of the given texture should be compared against a reference value or not. + */ isSampleCompare( texture ) { return texture.isDepthTexture === true && texture.compareFunction !== null; } + /** + * Returns `true` if the given texture is unfilterable. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the given texture is unfilterable or not. + */ isUnfilterable( texture ) { return this.getComponentTypeFromTexture( texture ) !== 'float' || @@ -44731,6 +59824,16 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for sampling/loading the given texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTexture( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { let snippet = null; @@ -44753,6 +59856,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for sampling/loading the given texture using explicit gradients. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {Array} gradSnippet - An array holding both gradient WGSL snippets. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44768,6 +59882,18 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for sampling a depth texture and comparing the sampled depth values + * against a reference value. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} compareSnippet - A WGSL snippet that represents the reference value. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44782,6 +59908,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling textures with explicit mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) { let snippet = null; @@ -44800,6 +59937,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling textures with a bias to the mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} biasSnippet - A WGSL snippet that represents the bias to apply to the mip level before sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44814,6 +59962,13 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns a WGSL snippet that represents the property name of the given node. + * + * @param {Node} node - The node. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The property name. + */ getPropertyName( node, shaderStage = this.shaderStage ) { if ( node.isNodeVarying === true && node.needsInterpolation === true ) { @@ -44849,18 +60004,36 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns the output struct name. + * + * @return {String} The name of the output struct. + */ getOutputStructName() { return 'output'; } + /** + * Returns uniforms group count for the given shader stage. + * + * @private + * @param {String} shaderStage - The shader stage. + * @return {Number} The uniforms group count for the given shader stage. + */ _getUniformGroupCount( shaderStage ) { return Object.keys( this.uniforms[ shaderStage ] ).length; } + /** + * Returns the native shader operator name for a given generic name. + * + * @param {String} op - The operator name to resolve. + * @return {String} The resolved operator name. + */ getFunctionOperator( op ) { const fnOp = wgslFnOpLib[ op ]; @@ -44877,6 +60050,13 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns the node access for the given node and shader stage. + * + * @param {StorageTextureNode|StorageBufferNode} node - The storage node. + * @param {String} shaderStage - The shader stage. + * @return {String} The node access. + */ getNodeAccess( node, shaderStage ) { if ( shaderStage !== 'compute' ) @@ -44886,12 +60066,32 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns A WGSL snippet representing the storage access. + * + * @param {StorageTextureNode|StorageBufferNode} node - The storage node. + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet representing the storage access. + */ getStorageAccess( node, shaderStage ) { return accessNames[ this.getNodeAccess( node, shaderStage ) ]; } + /** + * This method is one of the more important ones since it's responsible + * for generating a matching binding instance for the given uniform node. + * + * These bindings are later used in the renderer to create bind groups + * and layouts. + * + * @param {UniformNode} node - The uniform node. + * @param {String} type - The node data type. + * @param {String} shaderStage - The shader stage. + * @param {String?} [name=null] - An optional uniform name. + * @return {NodeUniform} The node uniform object. + */ getUniformFromNode( node, type, shaderStage, name = null ) { const uniformNode = super.getUniformFromNode( node, type, shaderStage, name ); @@ -44988,6 +60188,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * This method should be used whenever builtins are required in nodes. + * The internal builtins data structure will make sure builtins are + * defined in the WGSL source. + * + * @param {String} name - The builtin name. + * @param {String} property - The property name. + * @param {String} type - The node data type. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The property name. + */ getBuiltin( name, property, type, shaderStage = this.shaderStage ) { const map = this.builtins[ shaderStage ] || ( this.builtins[ shaderStage ] = new Map() ); @@ -45006,12 +60217,24 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns `true` if the given builtin is defined in the given shader stage. + * + * @param {String} name - The builtin name. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} Whether the given builtin is defined in the given shader stage or not. + */ hasBuiltin( name, shaderStage = this.shaderStage ) { return ( this.builtins[ shaderStage ] !== undefined && this.builtins[ shaderStage ].has( name ) ); } + /** + * Returns the vertex index builtin. + * + * @return {String} The vertex index. + */ getVertexIndex() { if ( this.shaderStage === 'vertex' ) { @@ -45024,6 +60247,12 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Builds the given shader node. + * + * @param {ShaderNodeInternal} shaderNode - The shader node. + * @return {String} The WGSL function code. + */ buildFunctionCode( shaderNode ) { const layout = shaderNode.layout; @@ -45058,6 +60287,11 @@ ${ flowData.code } } + /** + * Returns the instance index builtin. + * + * @return {String} The instance index. + */ getInstanceIndex() { if ( this.shaderStage === 'vertex' ) { @@ -45070,12 +60304,22 @@ ${ flowData.code } } + /** + * Returns the invocation local index builtin. + * + * @return {String} The invocation local index. + */ getInvocationLocalIndex() { return this.getBuiltin( 'local_invocation_index', 'invocationLocalIndex', 'u32', 'attribute' ); } + /** + * Returns the subgroup size builtin. + * + * @return {String} The subgroup size. + */ getSubgroupSize() { this.enableSubGroups(); @@ -45084,6 +60328,11 @@ ${ flowData.code } } + /** + * Returns the invocation subgroup index builtin. + * + * @return {String} The invocation subgroup index. + */ getInvocationSubgroupIndex() { this.enableSubGroups(); @@ -45092,6 +60341,11 @@ ${ flowData.code } } + /** + * Returns the subgroup index builtin. + * + * @return {String} The subgroup index. + */ getSubgroupIndex() { this.enableSubGroups(); @@ -45100,42 +60354,78 @@ ${ flowData.code } } + /** + * Overwritten as a NOP since this method is intended for the WebGL 2 backend. + * + * @return {null} Null. + */ getDrawIndex() { return null; } + /** + * Returns the front facing builtin. + * + * @return {String} The front facing builtin. + */ getFrontFacing() { return this.getBuiltin( 'front_facing', 'isFront', 'bool' ); } + /** + * Returns the frag coord builtin. + * + * @return {String} The frag coord builtin. + */ getFragCoord() { return this.getBuiltin( 'position', 'fragCoord', 'vec4' ) + '.xy'; } + /** + * Returns the frag depth builtin. + * + * @return {String} The frag depth builtin. + */ getFragDepth() { return 'output.' + this.getBuiltin( 'frag_depth', 'depth', 'f32', 'output' ); } + /** + * Returns the clip distances builtin. + * + * @return {String} The clip distances builtin. + */ getClipDistance() { return 'varyings.hw_clip_distances'; } + /** + * Whether to flip texture data along its vertical axis or not. + * + * @return {Boolean} Returns always `false` in context of WGSL. + */ isFlipY() { return false; } + /** + * Enables the given directive for the given shader stage. + * + * @param {String} name - The directive name. + * @param {String} [shaderStage=this.shaderStage] - The shader stage to enable the directive for. + */ enableDirective( name, shaderStage = this.shaderStage ) { const stage = this.directives[ shaderStage ] || ( this.directives[ shaderStage ] = new Set() ); @@ -45143,6 +60433,12 @@ ${ flowData.code } } + /** + * Returns the directives of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} A WGSL snippet that enables the directives of the given stage. + */ getDirectives( shaderStage ) { const snippets = []; @@ -45162,36 +60458,56 @@ ${ flowData.code } } + /** + * Enables the 'subgroups' directive. + */ enableSubGroups() { this.enableDirective( 'subgroups' ); } + /** + * Enables the 'subgroups-f16' directive. + */ enableSubgroupsF16() { this.enableDirective( 'subgroups-f16' ); } + /** + * Enables the 'clip_distances' directive. + */ enableClipDistances() { this.enableDirective( 'clip_distances' ); } + /** + * Enables the 'f16' directive. + */ enableShaderF16() { this.enableDirective( 'f16' ); } + /** + * Enables the 'dual_source_blending' directive. + */ enableDualSourceBlending() { this.enableDirective( 'dual_source_blending' ); } + /** + * Enables hardware clipping. + * + * @param {String} planeCount - The clipping plane count. + */ enableHardwareClipping( planeCount ) { this.enableClipDistances(); @@ -45199,6 +60515,12 @@ ${ flowData.code } } + /** + * Returns the builtins of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} A WGSL snippet that represents the builtins of the given stage. + */ getBuiltins( shaderStage ) { const snippets = []; @@ -45218,6 +60540,17 @@ ${ flowData.code } } + /** + * This method should be used when a new scoped buffer is used in context of + * compute shaders. It adds the array to the internal data structure which is + * later used to generate the respective WGSL. + * + * @param {String} name - The array name. + * @param {String} scope - The scope. + * @param {String} bufferType - The buffer type. + * @param {String} bufferCount - The buffer count. + * @return {String} The array name. + */ getScopedArray( name, scope, bufferType, bufferCount ) { if ( this.scopedArrays.has( name ) === false ) { @@ -45235,6 +60568,13 @@ ${ flowData.code } } + /** + * Returns the scoped arrays of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String|undefined} The WGSL snippet that defines the scoped arrays. + * Returns `undefined` when used in the vertex or fragment stage. + */ getScopedArrays( shaderStage ) { if ( shaderStage !== 'compute' ) { @@ -45257,13 +60597,19 @@ ${ flowData.code } } + /** + * Returns the shader attributes of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the shader attributes. + */ getAttributes( shaderStage ) { const snippets = []; if ( shaderStage === 'compute' ) { - this.getBuiltin( 'global_invocation_id', 'id', 'vec3', 'attribute' ); + this.getBuiltin( 'global_invocation_id', 'globalId', 'vec3', 'attribute' ); this.getBuiltin( 'workgroup_id', 'workgroupId', 'vec3', 'attribute' ); this.getBuiltin( 'local_invocation_id', 'localId', 'vec3', 'attribute' ); this.getBuiltin( 'num_workgroups', 'numWorkgroups', 'vec3', 'attribute' ); @@ -45301,6 +60647,12 @@ ${ flowData.code } } + /** + * Returns the members of the given struct type node as a WGSL string. + * + * @param {StructTypeNode} struct - The struct type node. + * @return {String} The WGSL snippet that defines the struct members. + */ getStructMembers( struct ) { const snippets = []; @@ -45321,6 +60673,12 @@ ${ flowData.code } } + /** + * Returns the structs of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the structs. + */ getStructs( shaderStage ) { const snippets = []; @@ -45346,12 +60704,25 @@ ${ flowData.code } } + /** + * Returns a WGSL string representing a variable. + * + * @param {String} type - The variable's type. + * @param {String} name - The variable's name. + * @return {String} The WGSL snippet that defines a variable. + */ getVar( type, name ) { return `var ${ name } : ${ this.getType( type ) }`; } + /** + * Returns the variables of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the variables. + */ getVars( shaderStage ) { const snippets = []; @@ -45371,6 +60742,12 @@ ${ flowData.code } } + /** + * Returns the varyings of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the varyings. + */ getVaryings( shaderStage ) { const snippets = []; @@ -45423,6 +60800,12 @@ ${ flowData.code } } + /** + * Returns the uniforms of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the uniforms. + */ getUniforms( shaderStage ) { const uniforms = this.uniforms[ shaderStage ]; @@ -45550,6 +60933,9 @@ ${ flowData.code } } + /** + * Controls the code build of the shader stages. + */ buildCode() { const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; @@ -45588,7 +60974,7 @@ ${ flowData.code } if ( flow.length > 0 ) flow += '\n'; - flow += `\t// flow -> ${ slotName }\n\t`; + flow += `\t// flow -> ${ slotName }\n`; } @@ -45650,6 +61036,13 @@ ${ flowData.code } } + /** + * Returns the native shader method name for a given generic name. + * + * @param {String} method - The method name to resolve. + * @param {String} [output=null] - An optional output. + * @return {String} The resolved WGSL method name. + */ getMethod( method, output = null ) { let wgslMethod; @@ -45670,12 +61063,24 @@ ${ flowData.code } } + /** + * Returns the WGSL type of the given node data type. + * + * @param {String} type - The node data type. + * @return {String} The WGSL type. + */ getType( type ) { return wgslTypeLib[ type ] || type; } + /** + * Whether the requested feature is available or not. + * + * @param {String} name - The requested feature. + * @return {Boolean} Whether the requested feature is supported or not. + */ isAvailable( name ) { let result = supports[ name ]; @@ -45700,6 +61105,13 @@ ${ flowData.code } } + /** + * Returns the native shader method name for a given generic name. + * + * @private + * @param {String} method - The method name to resolve. + * @return {String} The resolved WGSL method name. + */ _getWGSLMethod( method ) { if ( wgslPolyfill[ method ] !== undefined ) { @@ -45712,6 +61124,14 @@ ${ flowData.code } } + /** + * Includes the given method name into the current + * function node. + * + * @private + * @param {String} name - The method name to include. + * @return {CodeNode} The respective code node. + */ _include( name ) { const codeNode = wgslPolyfill[ name ]; @@ -45727,6 +61147,13 @@ ${ flowData.code } } + /** + * Returns a WGSL vertex shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getWGSLVertexCode( shaderData ) { return `${ this.getSignature() } @@ -45759,6 +61186,13 @@ fn main( ${shaderData.attributes} ) -> VaryingsStruct { } + /** + * Returns a WGSL fragment shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getWGSLFragmentCode( shaderData ) { return `${ this.getSignature() } @@ -45788,6 +61222,14 @@ fn main( ${shaderData.varyings} ) -> ${shaderData.returnType} { } + /** + * Returns a WGSL compute shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @param {String} workgroupSize - The workgroup size. + * @return {String} The vertex shader. + */ _getWGSLComputeCode( shaderData, workgroupSize ) { return `${ this.getSignature() } @@ -45810,7 +61252,7 @@ ${shaderData.codes} fn main( ${shaderData.attributes} ) { // system - instanceIndex = id.x + id.y * numWorkgroups.x * u32(${workgroupSize}) + id.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize}); + instanceIndex = globalId.x + globalId.y * numWorkgroups.x * u32(${workgroupSize}) + globalId.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize}); // vars ${shaderData.vars} @@ -45823,6 +61265,14 @@ fn main( ${shaderData.attributes} ) { } + /** + * Returns a WGSL struct based on the given name and variables. + * + * @private + * @param {String} name - The struct name. + * @param {String} vars - The struct variables. + * @return {String} The WGSL snippet representing a struct. + */ _getWGSLStruct( name, vars ) { return ` @@ -45832,6 +61282,17 @@ ${vars} } + /** + * Returns a WGSL struct binding. + * + * @private + * @param {String} name - The struct name. + * @param {String} vars - The struct variables. + * @param {String} access - The access. + * @param {Number} [binding=0] - The binding index. + * @param {Number} [group=0] - The group index. + * @return {String} The WGSL snippet representing a struct binding. + */ _getWGSLStructBinding( name, vars, access, binding = 0, group = 0 ) { const structName = name + 'Struct'; @@ -45845,14 +61306,35 @@ var<${access}> ${name} : ${structName};`; } +/** + * A WebGPU backend utility module with common helpers. + * + * @private + */ class WebGPUUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; } + /** + * Returns the depth/stencil GPU format for the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {String} The depth/stencil GPU texture format. + */ getCurrentDepthStencilFormat( renderContext ) { let format; @@ -45875,12 +61357,24 @@ class WebGPUUtils { } + /** + * Returns the GPU format for the given texture. + * + * @param {Texture} texture - The texture. + * @return {String} The GPU texture format. + */ getTextureFormatGPU( texture ) { return this.backend.get( texture ).format; } + /** + * Returns an object that defines the multi-sampling state of the given texture. + * + * @param {Texture} texture - The texture. + * @return {Object} The multi-sampling state. + */ getTextureSampleData( texture ) { let samples; @@ -45911,6 +61405,12 @@ class WebGPUUtils { } + /** + * Returns the default color attachment's GPU format of the current render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {String} The GPU texture format of the default color attachment. + */ getCurrentColorFormat( renderContext ) { let format; @@ -45929,6 +61429,12 @@ class WebGPUUtils { } + /** + * Returns the output color space of the current render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {String} The output color space. + */ getCurrentColorSpace( renderContext ) { if ( renderContext.textures !== null ) { @@ -45941,6 +61447,13 @@ class WebGPUUtils { } + /** + * Returns GPU primitive topology for the given object and material. + * + * @param {Object3D} object - The 3D object. + * @param {Material} material - The material. + * @return {String} The GPU primitive topology. + */ getPrimitiveTopology( object, material ) { if ( object.isPoints ) return GPUPrimitiveTopology.PointList; @@ -45950,6 +61463,14 @@ class WebGPUUtils { } + /** + * Returns a modified sample count from the given sample count value. + * + * That is required since WebGPU does not support arbitrary sample counts. + * + * @param {Number} sampleCount - The input sample count. + * @return {Number} The (potentially updated) output sample count. + */ getSampleCount( sampleCount ) { let count = 1; @@ -45971,6 +61492,12 @@ class WebGPUUtils { } + /** + * Returns the sample count of the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {Number} The sample count. + */ getSampleCountRenderContext( renderContext ) { if ( renderContext.textures !== null ) { @@ -45983,6 +61510,14 @@ class WebGPUUtils { } + /** + * Returns the preferred canvas format. + * + * There is a separate method for this so it's possible to + * honor edge cases for specific devices. + * + * @return {String} The GPU texture format of the canvas. + */ getPreferredCanvasFormat() { // TODO: Remove this check when Quest 34.5 is out @@ -46024,14 +61559,35 @@ const typeArraysToVertexFormatPrefixForItemSize1 = new Map( [ [ Float32Array, 'float32' ] ] ); +/** + * A WebGPU backend utility module for managing shader attributes. + * + * @private + */ class WebGPUAttributeUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; } + /** + * Creates the GPU buffer for the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + * @param {GPUBufferUsage} usage - A flag that indicates how the buffer may be used after its creation. + */ createAttribute( attribute, usage ) { const bufferAttribute = this._getBufferAttribute( attribute ); @@ -46048,16 +61604,27 @@ class WebGPUAttributeUtils { let array = bufferAttribute.array; // patch for INT16 and UINT16 - if ( attribute.normalized === false && ( array.constructor === Int16Array || array.constructor === Uint16Array ) ) { + if ( attribute.normalized === false ) { - const tempArray = new Uint32Array( array.length ); - for ( let i = 0; i < array.length; i ++ ) { + if ( array.constructor === Int16Array ) { - tempArray[ i ] = array[ i ]; + array = new Int32Array( array ); - } + } else if ( array.constructor === Uint16Array ) { + + array = new Uint32Array( array ); - array = tempArray; + if ( usage & GPUBufferUsage.INDEX ) { + + for ( let i = 0; i < array.length; i ++ ) { + + if ( array[ i ] === 0xffff ) array[ i ] = 0xffffffff; // use correct primitive restart index + + } + + } + + } } @@ -46098,6 +61665,11 @@ class WebGPUAttributeUtils { } + /** + * Updates the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ updateAttribute( attribute ) { const bufferAttribute = this._getBufferAttribute( attribute ); @@ -46149,6 +61721,13 @@ class WebGPUAttributeUtils { } + /** + * This method creates the vertex buffer layout data which are + * require when creating a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Array} An array holding objects which describe the vertex buffer layout. + */ createShaderVertexBuffers( renderObject ) { const attributes = renderObject.getAttributes(); @@ -46210,6 +61789,11 @@ class WebGPUAttributeUtils { } + /** + * Destroys the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ destroyAttribute( attribute ) { const backend = this.backend; @@ -46221,24 +61805,32 @@ class WebGPUAttributeUtils { } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ 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, + label: `${ attribute.name }_readback`, size, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ } ); - - const cmdEncoder = device.createCommandEncoder( {} ); + const cmdEncoder = device.createCommandEncoder( { + label: `readback_encoder_${ attribute.name }` + } ); cmdEncoder.copyBufferToBuffer( bufferGPU, @@ -46248,8 +61840,6 @@ class WebGPUAttributeUtils { size ); - readBufferGPU.unmap(); - const gpuCommands = cmdEncoder.finish(); device.queue.submit( [ gpuCommands ] ); @@ -46257,10 +61847,21 @@ class WebGPUAttributeUtils { const arrayBuffer = readBufferGPU.getMappedRange(); - return arrayBuffer; + const dstBuffer = new attribute.array.constructor( arrayBuffer.slice( 0 ) ); + + readBufferGPU.unmap(); + + return dstBuffer.buffer; } + /** + * Returns the vertex format of the given buffer attribute. + * + * @private + * @param {BufferAttribute} geometryAttribute - The buffer attribute. + * @return {String} The vertex format (e.g. 'float32x3'). + */ _getVertexFormat( geometryAttribute ) { const { itemSize, normalized } = geometryAttribute; @@ -46306,12 +61907,27 @@ class WebGPUAttributeUtils { } + /** + * Returns `true` if the given array is a typed array. + * + * @private + * @param {Any} array - The array. + * @return {Boolean} Whether the given array is a typed array or not. + */ _isTypedArray( array ) { return ArrayBuffer.isView( array ) && ! ( array instanceof DataView ); } + /** + * Utility method for handling interleaved buffer attributes correctly. + * To process them, their `InterleavedBuffer` is returned. + * + * @private + * @param {BufferAttribute} attribute - The attribute. + * @return {BufferAttribute|InterleavedBuffer} + */ _getBufferAttribute( attribute ) { if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; @@ -46322,15 +61938,47 @@ class WebGPUAttributeUtils { } +/** + * A WebGPU backend utility module for managing bindings. + * + * When reading the documentation it's helpful to keep in mind that + * all class definitions starting with 'GPU*' are modules from the + * WebGPU API. So for example `BindGroup` is a class from the engine + * whereas `GPUBindGroup` is a class from WebGPU. + * + * @private + */ class WebGPUBindingUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; + + /** + * A cache for managing bind group layouts. + * + * @type {WeakMap,GPUBindGroupLayout>} + */ this.bindGroupLayoutCache = new WeakMap(); } + /** + * Creates a GPU bind group layout for the given bind group. + * + * @param {BindGroup} bindGroup - The bind group. + * @return {GPUBindGroupLayout} The GPU bind group layout. + */ createBindingsLayout( bindGroup ) { const backend = this.backend; @@ -46500,6 +62148,14 @@ class WebGPUBindingUtils { } + /** + * Creates bindings from the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ createBindings( bindGroup, bindings, cacheIndex, version = 0 ) { const { backend, bindGroupLayoutCache } = this; @@ -46553,6 +62209,11 @@ class WebGPUBindingUtils { } + /** + * Updates a buffer binding. + * + * @param {Buffer} binding - The buffer binding to update. + */ updateBinding( binding ) { const backend = this.backend; @@ -46565,6 +62226,13 @@ class WebGPUBindingUtils { } + /** + * Creates a GPU bind group for the given bind group and GPU layout. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {GPUBindGroupLayout} layoutGPU - The GPU bind group layout. + * @return {GPUBindGroup} The GPU bind group. + */ createBindGroup( bindGroup, layoutGPU ) { const backend = this.backend; @@ -46685,20 +62353,48 @@ class WebGPUBindingUtils { } +/** + * A WebGPU backend utility module for managing pipelines. + * + * @private + */ class WebGPUPipelineUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; } - _getSampleCount( renderObjectContext ) { + /** + * Returns the sample count derived from the given render context. + * + * @private + * @param {RenderContext} renderContext - The render context. + * @return {Number} The sample count. + */ + _getSampleCount( renderContext ) { - return this.backend.utils.getSampleCountRenderContext( renderObjectContext ); + return this.backend.utils.getSampleCountRenderContext( renderContext ); } + /** + * Creates a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ createRenderPipeline( renderObject, promises ) { const { object, material, geometry, pipeline } = renderObject; @@ -46858,6 +62554,12 @@ class WebGPUPipelineUtils { } + /** + * Creates GPU render bundle encoder for the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {GPURenderBundleEncoder} The GPU render bundle encoder. + */ createBundleEncoder( renderContext ) { const backend = this.backend; @@ -46878,6 +62580,12 @@ class WebGPUPipelineUtils { } + /** + * Creates a compute pipeline for the given compute node. + * + * @param {ComputePipeline} pipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ createComputePipeline( pipeline, bindings ) { const backend = this.backend; @@ -46908,6 +62616,14 @@ class WebGPUPipelineUtils { } + /** + * Returns the blending state as a descriptor object required + * for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {Object} The blending state. + */ _getBlending( material ) { let color, alpha; @@ -47015,7 +62731,13 @@ class WebGPUPipelineUtils { } } - + /** + * Returns the GPU blend factor which is required for the pipeline creation. + * + * @private + * @param {Number} blend - The blend factor as a three.js constant. + * @return {String} The GPU blend factor. + */ _getBlendFactor( blend ) { let blendFactor; @@ -47083,6 +62805,13 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU stencil compare function which is required for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {String} The GPU stencil compare function. + */ _getStencilCompare( material ) { let stencilCompare; @@ -47132,6 +62861,13 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU stencil operation which is required for the pipeline creation. + * + * @private + * @param {Number} op - A three.js constant defining the stencil operation. + * @return {String} The GPU stencil operation. + */ _getStencilOperation( op ) { let stencilOperation; @@ -47179,6 +62915,13 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU blend operation which is required for the pipeline creation. + * + * @private + * @param {Number} blendEquation - A three.js constant defining the blend equation. + * @return {String} The GPU blend operation. + */ _getBlendOperation( blendEquation ) { let blendOperation; @@ -47214,6 +62957,16 @@ class WebGPUPipelineUtils { } + /** + * Returns the primitive state as a descriptor object required + * for the pipeline creation. + * + * @private + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The geometry. + * @param {Material} material - The material. + * @return {Object} The primitive state. + */ _getPrimitiveState( object, geometry, material ) { const descriptor = {}; @@ -47254,12 +63007,26 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU color write mask which is required for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {String} The GPU color write mask. + */ _getColorWriteMask( material ) { return ( material.colorWrite === true ) ? GPUColorWriteFlags.All : GPUColorWriteFlags.None; } + /** + * Returns the GPU depth compare function which is required for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {String} The GPU depth compare function. + */ _getDepthCompare( material ) { let depthCompare; @@ -47324,14 +63091,41 @@ import 'https://greggman.github.io/webgpu-avoid-redundant-state-setting/webgpu-c //*/ -// - +/** + * A backend implementation targeting WebGPU. + * + * @private + * @augments Backend + */ class WebGPUBackend extends Backend { + /** + * Constructs a new WebGPU backend. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. + * @param {Boolean} [parameters.trackTimestamp=false] - Whether to track timestamps with a Timestamp Query API or not. + * @param {String} [parameters.powerPreference=undefined] - The power preference. + * @param {Object} [parameters.requiredLimits=undefined] - Specifies the limits that are required by the device request. The request will fail if the adapter cannot provide these limits. + * @param {GPUDevice} [parameters.device=undefined] - If there is an existing GPU device on app level, it can be passed to the renderer as a parameter. + */ constructor( parameters = {} ) { super( parameters ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGPUBackend = true; // some parameters require default values other than "undefined" @@ -47339,22 +63133,101 @@ class WebGPUBackend extends Backend { this.parameters.requiredLimits = ( parameters.requiredLimits === undefined ) ? {} : parameters.requiredLimits; + /** + * Whether to track timestamps with a Timestamp Query API or not. + * + * @type {Boolean} + * @default false + */ this.trackTimestamp = ( parameters.trackTimestamp === true ); + /** + * A reference to the device. + * + * @type {GPUDevice?} + * @default null + */ this.device = null; + + /** + * A reference to the context. + * + * @type {GPUCanvasContext?} + * @default null + */ this.context = null; + + /** + * A reference to the color attachment of the default framebuffer. + * + * @type {GPUTexture?} + * @default null + */ this.colorBuffer = null; + + /** + * A reference to the default render pass descriptor. + * + * @type {Object?} + * @default null + */ this.defaultRenderPassdescriptor = null; + /** + * A reference to a backend module holding common utility functions. + * + * @type {WebGPUUtils} + */ this.utils = new WebGPUUtils( this ); + + /** + * A reference to a backend module holding shader attribute-related + * utility functions. + * + * @type {WebGPUAttributeUtils} + */ this.attributeUtils = new WebGPUAttributeUtils( this ); + + /** + * A reference to a backend module holding shader binding-related + * utility functions. + * + * @type {WebGPUBindingUtils} + */ this.bindingUtils = new WebGPUBindingUtils( this ); + + /** + * A reference to a backend module holding shader pipeline-related + * utility functions. + * + * @type {WebGPUPipelineUtils} + */ this.pipelineUtils = new WebGPUPipelineUtils( this ); + + /** + * A reference to a backend module holding shader texture-related + * utility functions. + * + * @type {WebGPUTextureUtils} + */ this.textureUtils = new WebGPUTextureUtils( this ); + + /** + * A map that manages the resolve buffers for occlusion queries. + * + * @type {Map} + */ this.occludedResolveCache = new Map(); } + /** + * Initializes the backend so it is ready for usage. + * + * @async + * @param {Renderer} renderer - The renderer. + * @return {Promise} A Promise that resolves when the backend has been initialized. + */ async init( renderer ) { await super.init( renderer ); @@ -47443,24 +63316,53 @@ class WebGPUBackend extends Backend { } + /** + * The coordinate system of the backend. + * + * @type {Number} + * @readonly + */ get coordinateSystem() { return WebGPUCoordinateSystem; } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { return await this.attributeUtils.getArrayBufferAsync( attribute ); } + /** + * Returns the backend's rendering context. + * + * @return {GPUCanvasContext} The rendering context. + */ getContext() { return this.context; } + /** + * Returns the default render pass descriptor. + * + * In WebGPU, the default framebuffer must be configured + * like custom framebuffers so the backend needs a render + * pass descriptor even when rendering directly to screen. + * + * @private + * @return {Object} The render pass descriptor. + */ _getDefaultRenderPassDescriptor() { let descriptor = this.defaultRenderPassdescriptor; @@ -47515,7 +63417,15 @@ class WebGPUBackend extends Backend { } - _getRenderPassDescriptor( renderContext ) { + /** + * Returns the render pass descriptor for the given render context. + * + * @private + * @param {RenderContext} renderContext - The render context. + * @param {Object} colorAttachmentsConfig - Configuration object for the color attachments. + * @return {Object} The render pass descriptor. + */ + _getRenderPassDescriptor( renderContext, colorAttachmentsConfig = {} ) { const renderTarget = renderContext.renderTarget; const renderTargetData = this.get( renderTarget ); @@ -47525,8 +63435,11 @@ class WebGPUBackend extends Backend { if ( descriptors === undefined || renderTargetData.width !== renderTarget.width || renderTargetData.height !== renderTarget.height || + renderTargetData.dimensions !== renderTarget.dimensions || renderTargetData.activeMipmapLevel !== renderTarget.activeMipmapLevel || - renderTargetData.samples !== renderTarget.samples + renderTargetData.activeCubeFace !== renderContext.activeCubeFace || + renderTargetData.samples !== renderTarget.samples || + renderTargetData.loadOp !== colorAttachmentsConfig.loadOp ) { descriptors = {}; @@ -47556,16 +63469,37 @@ class WebGPUBackend extends Backend { const textures = renderContext.textures; const colorAttachments = []; + let sliceIndex; + for ( let i = 0; i < textures.length; i ++ ) { const textureData = this.get( textures[ i ] ); - const textureView = textureData.texture.createView( { + const viewDescriptor = { + label: `colorAttachment_${ i }`, baseMipLevel: renderContext.activeMipmapLevel, mipLevelCount: 1, baseArrayLayer: renderContext.activeCubeFace, + arrayLayerCount: 1, dimension: GPUTextureViewDimension.TwoD - } ); + }; + + if ( renderTarget.isRenderTarget3D ) { + + sliceIndex = renderContext.activeCubeFace; + + viewDescriptor.baseArrayLayer = 0; + viewDescriptor.dimension = GPUTextureViewDimension.ThreeD; + viewDescriptor.depthOrArrayLayers = textures[ i ].image.depth; + + } else if ( renderTarget.isRenderTargetArray ) { + + viewDescriptor.dimension = GPUTextureViewDimension.TwoDArray; + viewDescriptor.depthOrArrayLayers = textures[ i ].image.depth; + + } + + const textureView = textureData.texture.createView( viewDescriptor ); let view, resolveTarget; @@ -47583,9 +63517,11 @@ class WebGPUBackend extends Backend { colorAttachments.push( { view, + depthSlice: sliceIndex, resolveTarget, loadOp: GPULoadOp.Load, - storeOp: GPUStoreOp.Store + storeOp: GPUStoreOp.Store, + ...colorAttachmentsConfig } ); } @@ -47611,7 +63547,11 @@ class WebGPUBackend extends Backend { renderTargetData.width = renderTarget.width; renderTargetData.height = renderTarget.height; renderTargetData.samples = renderTarget.samples; - renderTargetData.activeMipmapLevel = renderTarget.activeMipmapLevel; + renderTargetData.activeMipmapLevel = renderContext.activeMipmapLevel; + renderTargetData.activeCubeFace = renderContext.activeCubeFace; + renderTargetData.dimensions = renderTarget.dimensions; + renderTargetData.depthSlice = sliceIndex; + renderTargetData.loadOp = colorAttachments[ 0 ].loadOp; } @@ -47619,6 +63559,12 @@ class WebGPUBackend extends Backend { } + /** + * This method is executed at the beginning of a render call and prepares + * the WebGPU state for upcoming render calls + * + * @param {RenderContext} renderContext - The render context. + */ beginRender( renderContext ) { const renderContextData = this.get( renderContext ); @@ -47659,7 +63605,7 @@ class WebGPUBackend extends Backend { } else { - descriptor = this._getRenderPassDescriptor( renderContext ); + descriptor = this._getRenderPassDescriptor( renderContext, { loadOp: GPULoadOp.Load } ); } @@ -47778,6 +63724,12 @@ class WebGPUBackend extends Backend { } + /** + * This method is executed at the end of a render call and finalizes work + * after draw calls. + * + * @param {RenderContext} renderContext - The render context. + */ finishRender( renderContext ) { const renderContextData = this.get( renderContext ); @@ -47866,6 +63818,14 @@ class WebGPUBackend extends Backend { } + /** + * Returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ isOccluded( renderContext, object ) { const renderContextData = this.get( renderContext ); @@ -47874,6 +63834,14 @@ class WebGPUBackend extends Backend { } + /** + * This method processes the result of occlusion queries and writes it + * into render context data. + * + * @async + * @param {RenderContext} renderContext - The render context. + * @return {Promise} A Promise that resolves when the occlusion query results have been processed. + */ async resolveOccludedAsync( renderContext ) { const renderContextData = this.get( renderContext ); @@ -47896,7 +63864,7 @@ class WebGPUBackend extends Backend { for ( let i = 0; i < currentOcclusionQueryObjects.length; i ++ ) { - if ( results[ i ] !== BigInt( 0 ) ) { + if ( results[ i ] === BigInt( 0 ) ) { occluded.add( currentOcclusionQueryObjects[ i ] ); @@ -47912,6 +63880,11 @@ class WebGPUBackend extends Backend { } + /** + * Updates the viewport with the values from the given render context. + * + * @param {RenderContext} renderContext - The render context. + */ updateViewport( renderContext ) { const { currentPass } = this.get( renderContext ); @@ -47921,7 +63894,15 @@ class WebGPUBackend extends Backend { } - clear( color, depth, stencil, renderTargetData = null ) { + /** + * Performs a clear operation. + * + * @param {Boolean} color - Whether the color buffer should be cleared or not. + * @param {Boolean} depth - Whether the depth buffer should be cleared or not. + * @param {Boolean} stencil - Whether the stencil buffer should be cleared or not. + * @param {RenderContext?} [renderTargetContext=null] - The render context of the current set render target. + */ + clear( color, depth, stencil, renderTargetContext = null ) { const device = this.device; const renderer = this.renderer; @@ -47954,7 +63935,7 @@ class WebGPUBackend extends Backend { } - if ( renderTargetData === null ) { + if ( renderTargetContext === null ) { supportsDepth = renderer.depth; supportsStencil = renderer.stencil; @@ -47981,45 +63962,20 @@ class WebGPUBackend extends Backend { } else { - supportsDepth = renderTargetData.depth; - supportsStencil = renderTargetData.stencil; + supportsDepth = renderTargetContext.depth; + supportsStencil = renderTargetContext.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; + const descriptor = this._getRenderPassDescriptor( renderTargetContext, { loadOp: GPULoadOp.Clear, clearValue } ); - } else { - - view = textureView; - resolveTarget = undefined; - - } - - colorAttachments.push( { - view, - resolveTarget, - clearValue, - loadOp: GPULoadOp.Clear, - storeOp: GPUStoreOp.Store - } ); - - } + colorAttachments = descriptor.colorAttachments; } if ( supportsDepth || supportsStencil ) { - const depthTextureData = this.get( renderTargetData.depthTexture ); + const depthTextureData = this.get( renderTargetContext.depthTexture ); depthStencilAttachment = { view: depthTextureData.texture.createView() @@ -48069,7 +64025,7 @@ class WebGPUBackend extends Backend { // - const encoder = device.createCommandEncoder( {} ); + const encoder = device.createCommandEncoder( { label: 'clear' } ); const currentPass = encoder.beginRenderPass( { colorAttachments, depthStencilAttachment @@ -48083,21 +64039,37 @@ class WebGPUBackend extends Backend { // compute + /** + * This method is executed at the beginning of a compute call and + * prepares the state for upcoming compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ beginCompute( computeGroup ) { const groupGPU = this.get( computeGroup ); - const descriptor = {}; + const descriptor = { + label: 'computeGroup_' + computeGroup.id + }; this.initTimestampQuery( computeGroup, descriptor ); - groupGPU.cmdEncoderGPU = this.device.createCommandEncoder(); + groupGPU.cmdEncoderGPU = this.device.createCommandEncoder( { label: 'computeGroup_' + computeGroup.id } ); groupGPU.passEncoderGPU = groupGPU.cmdEncoderGPU.beginComputePass( descriptor ); } + /** + * Executes a compute command for the given compute node. + * + * @param {Node|Array} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @param {ComputePipeline} pipeline - The compute pipeline. + */ compute( computeGroup, computeNode, bindings, pipeline ) { const { passEncoderGPU } = this.get( computeGroup ); @@ -48145,6 +64117,12 @@ class WebGPUBackend extends Backend { } + /** + * This method is executed at the end of a compute call and + * finalizes work after compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ finishCompute( computeGroup ) { const groupData = this.get( computeGroup ); @@ -48157,6 +64135,13 @@ class WebGPUBackend extends Backend { } + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ async waitForGPU() { await this.device.queue.onSubmittedWorkDone(); @@ -48165,6 +64150,12 @@ class WebGPUBackend extends Backend { // render object + /** + * Executes a draw command for the given render object. + * + * @param {RenderObject} renderObject - The render object to draw. + * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. + */ draw( renderObject, info ) { const { object, context, pipeline } = renderObject; @@ -48285,14 +64276,20 @@ class WebGPUBackend extends Backend { 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 ); + if ( hasIndex === true ) { + + passEncoderGPU.drawIndexed( counts[ i ], count, starts[ i ] / index.array.BYTES_PER_ELEMENT, 0, firstInstance ); + + } else { + + passEncoderGPU.draw( counts[ i ], count, starts[ i ], firstInstance ); + + } } @@ -48342,6 +64339,12 @@ class WebGPUBackend extends Backend { // cache key + /** + * Returns `true` if the render pipeline requires an update. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render pipeline requires an update or not. + */ needsRenderUpdate( renderObject ) { const data = this.get( renderObject ); @@ -48398,6 +64401,12 @@ class WebGPUBackend extends Backend { } + /** + * Returns a cache key that is used to identify render pipelines. + * + * @param {RenderObject} renderObject - The render object. + * @return {String} The cache key. + */ getRenderCacheKey( renderObject ) { const { object, material } = renderObject; @@ -48426,83 +64435,142 @@ class WebGPUBackend extends Backend { // textures + /** + * Creates a GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( texture ) { this.textureUtils.createSampler( texture ); } + /** + * Destroys the GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to destroy the sampler for. + */ destroySampler( texture ) { this.textureUtils.destroySampler( texture ); } + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { this.textureUtils.createDefaultTexture( texture ); } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ createTexture( texture, options ) { this.textureUtils.createTexture( texture, options ); } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { this.textureUtils.updateTexture( texture, options ); } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { this.textureUtils.generateMipmaps( texture ); } + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { this.textureUtils.destroyTexture( texture ); } - copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); } - + /** + * Inits a time stamp query for the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object} descriptor - The query descriptor. + */ initTimestampQuery( renderContext, descriptor ) { if ( ! this.trackTimestamp ) return; const renderContextData = this.get( renderContext ); - if ( ! renderContextData.timeStampQuerySet ) { + // init query set if not exists + if ( ! renderContextData.timestampQuerySet ) { const type = renderContext.isComputeNode ? 'compute' : 'render'; - const timeStampQuerySet = this.device.createQuerySet( { type: 'timestamp', count: 2, label: `timestamp_${type}_${renderContext.id}` } ); - const timestampWrites = { - querySet: timeStampQuerySet, - beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins. - endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends. - }; + renderContextData.timestampQuerySet = this.device.createQuerySet( { type: 'timestamp', count: 2, label: `timestamp_${type}_${renderContext.id}` } ); - Object.assign( descriptor, { timestampWrites } ); + } - renderContextData.timeStampQuerySet = timeStampQuerySet; + // augment descriptor - } + descriptor.timestampWrites = { + querySet: renderContextData.timestampQuerySet, + beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins. + endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends. + }; } - // timestamp utils - + /** + * Prepares the timestamp buffer. + * + * @param {RenderContext} renderContext - The render context. + * @param {GPUCommandEncoder} encoder - The command encoder. + */ prepareTimestampBuffer( renderContext, encoder ) { if ( ! this.trackTimestamp ) return; @@ -48510,7 +64578,7 @@ class WebGPUBackend extends Backend { const renderContextData = this.get( renderContext ); - const size = 2 * BigInt64Array.BYTES_PER_ELEMENT; + const size = 2 * BigUint64Array.BYTES_PER_ELEMENT; if ( renderContextData.currentTimestampQueryBuffers === undefined ) { @@ -48532,7 +64600,7 @@ class WebGPUBackend extends Backend { const { resolveBuffer, resultBuffer } = renderContextData.currentTimestampQueryBuffers; - encoder.resolveQuerySet( renderContextData.timeStampQuerySet, 0, 2, resolveBuffer, 0 ); + encoder.resolveQuerySet( renderContextData.timestampQuerySet, 0, 2, resolveBuffer, 0 ); if ( resultBuffer.mapState === 'unmapped' ) { @@ -48542,6 +64610,14 @@ class WebGPUBackend extends Backend { } + /** + * Resolves the time stamp for the given render context and type. + * + * @async + * @param {RenderContext} renderContext - The render context. + * @param {String} type - The render context. + * @return {Promise} A Promise that resolves when the time stamp has been computed. + */ async resolveTimestampAsync( renderContext, type = 'render' ) { if ( ! this.trackTimestamp ) return; @@ -48554,18 +64630,15 @@ class WebGPUBackend extends Backend { if ( resultBuffer.mapState === 'unmapped' ) { - resultBuffer.mapAsync( GPUMapMode.READ ).then( () => { + await resultBuffer.mapAsync( GPUMapMode.READ ); - const times = new BigUint64Array( resultBuffer.getMappedRange() ); - const duration = Number( times[ 1 ] - times[ 0 ] ) / 1000000; + const times = new BigUint64Array( resultBuffer.getMappedRange() ); + const duration = Number( times[ 1 ] - times[ 0 ] ) / 1000000; - this.renderer.info.updateTimestamp( type, duration ); + this.renderer.info.updateTimestamp( type, duration ); - resultBuffer.unmap(); - - - } ); + resultBuffer.unmap(); } @@ -48573,6 +64646,13 @@ class WebGPUBackend extends Backend { // node builder + /** + * Returns a node builder for the given render object. + * + * @param {RenderObject} object - The render object. + * @param {Renderer} renderer - The renderer. + * @return {WGSLNodeBuilder} The node builder. + */ createNodeBuilder( object, renderer ) { return new WGSLNodeBuilder( object, renderer ); @@ -48581,17 +64661,27 @@ class WebGPUBackend extends Backend { // program + /** + * Creates a shader program from the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ createProgram( program ) { const programGPU = this.get( program ); programGPU.module = { - module: this.device.createShaderModule( { code: program.code, label: program.stage } ), + module: this.device.createShaderModule( { code: program.code, label: program.stage + ( program.name !== '' ? `_${ program.name }` : '' ) } ), entryPoint: 'main' }; } + /** + * Destroys the shader program of the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ destroyProgram( program ) { this.delete( program ); @@ -48600,18 +64690,35 @@ class WebGPUBackend extends Backend { // pipelines + /** + * Creates a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ createRenderPipeline( renderObject, promises ) { this.pipelineUtils.createRenderPipeline( renderObject, promises ); } + /** + * Creates a compute pipeline for the given compute node. + * + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ createComputePipeline( computePipeline, bindings ) { this.pipelineUtils.createComputePipeline( computePipeline, bindings ); } + /** + * Prepares the state for encoding render bundles. + * + * @param {RenderContext} renderContext - The render context. + */ beginBundle( renderContext ) { const renderContextData = this.get( renderContext ); @@ -48624,6 +64731,12 @@ class WebGPUBackend extends Backend { } + /** + * After processing render bundles this method finalizes related work. + * + * @param {RenderContext} renderContext - The render context. + * @param {RenderBundle} bundle - The render bundle. + */ finishBundle( renderContext, bundle ) { const renderContextData = this.get( renderContext ); @@ -48640,6 +64753,12 @@ class WebGPUBackend extends Backend { } + /** + * Adds a render bundle to the render context data. + * + * @param {RenderContext} renderContext - The render context. + * @param {RenderBundle} bundle - The render bundle to add. + */ addBundle( renderContext, bundle ) { const renderContextData = this.get( renderContext ); @@ -48650,18 +64769,39 @@ class WebGPUBackend extends Backend { // bindings + /** + * Creates bindings from the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ createBindings( bindGroup, bindings, cacheIndex, version ) { this.bindingUtils.createBindings( bindGroup, bindings, cacheIndex, version ); } + /** + * Updates the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ updateBindings( bindGroup, bindings, cacheIndex, version ) { this.bindingUtils.createBindings( bindGroup, bindings, cacheIndex, version ); } + /** + * Updates a buffer binding. + * + * @param {Buffer} binding - The buffer binding to update. + */ updateBinding( binding ) { this.bindingUtils.updateBinding( binding ); @@ -48670,36 +64810,66 @@ class WebGPUBackend extends Backend { // attributes + /** + * Creates the buffer of an indexed shader attribute. + * + * @param {BufferAttribute} attribute - The indexed buffer attribute. + */ createIndexAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Creates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Creates the GPU buffer of a storage attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createStorageAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Creates the GPU buffer of an indirect storage attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createIndirectStorageAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.STORAGE | GPUBufferUsage.INDIRECT | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Updates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to update. + */ updateAttribute( attribute ) { this.attributeUtils.updateAttribute( attribute ); } + /** + * Destroys the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to destroy. + */ destroyAttribute( attribute ) { this.attributeUtils.destroyAttribute( attribute ); @@ -48708,6 +64878,9 @@ class WebGPUBackend extends Backend { // canvas + /** + * Triggers an update of the default render pass descriptor. + */ updateSize() { this.colorBuffer = this.textureUtils.getColorBuffer(); @@ -48717,18 +64890,38 @@ class WebGPUBackend extends Backend { // utils public + /** + * Returns the maximum anisotropy texture filtering value. + * + * @return {Number} The maximum anisotropy texture filtering value. + */ getMaxAnisotropy() { return 16; } + /** + * Checks if the given feature is supported by the backend. + * + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ hasFeature( name ) { return this.device.features.has( name ); } + /** + * Copies data of the given source texture to the given destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { let dstX = 0; @@ -48787,6 +64980,13 @@ class WebGPUBackend extends Backend { } + /** + * Copies the current bound framebuffer to the given texture. + * + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ copyFramebufferToTexture( texture, renderContext, rectangle ) { const renderContextData = this.get( renderContext ); @@ -48921,8 +65121,19 @@ class IESSpotLight extends SpotLight { } +/** + * This version of a node library represents the standard version + * used in {@link WebGPURenderer}. It maps lights, tone mapping + * techniques and materials to node-based implementations. + * + * @private + * @augments NodeLibrary + */ class StandardNodeLibrary extends NodeLibrary { + /** + * Constructs a new standard node library. + */ constructor() { super(); @@ -48975,8 +65186,28 @@ const debugHandler = { }; */ + +/** + * This renderer is the new alternative of `WebGLRenderer`. `WebGPURenderer` has the ability + * to target different backends. By default, the renderer tries to use a WebGPU backend if the + * browser supports WebGPU. If not, `WebGPURenderer` falls backs to a WebGL 2 backend. + * + * @augments module:Renderer~Renderer + */ class WebGPURenderer extends Renderer { + /** + * Constructs a new WebGPU renderer. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. + */ constructor( parameters = {} ) { let BackendClass; @@ -49004,29 +65235,99 @@ class WebGPURenderer extends Renderer { //super( new Proxy( backend, debugHandler ) ); super( backend, parameters ); + /** + * The generic default value is overwritten with the + * standard node library for type mapping. + * + * @type {StandardNodeLibrary} + */ this.library = new StandardNodeLibrary(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGPURenderer = true; } } +/** + * A specialized group which enables applications access to the + * Render Bundle API of WebGPU. The group with all its descendant nodes + * are considered as one render bundle and processed as such by + * the renderer. + * + * This module is only fully supported by `WebGPURenderer` with a WebGPU backend. + * With a WebGL backend, the group can technically be rendered but without + * any performance improvements. + * + * @augments Group + */ class BundleGroup extends Group { + /** + * Constructs a new bundle group. + */ constructor() { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBundleGroup = true; + /** + * This property is only relevant for detecting types + * during serialization/deserialization. It should always + * match the class name. + * + * @type {String} + * @readonly + * @default 'BundleGroup' + */ this.type = 'BundleGroup'; + /** + * Whether the bundle is static or not. When set to `true`, the structure + * is assumed to be static and does not change. E.g. no new objects are + * added to the group + * + * If a change is required, an update can still be forced by setting the + * `needsUpdate` flag to `true`. + * + * @type {Boolean} + * @default true + */ this.static = true; + + /** + * The bundle group's version. + * + * @type {Number} + * @readonly + * @default 0 + */ this.version = 0; } + /** + * Set this property to `true` when the bundle group has changed. + * + * @type {Boolean} + * @default false + * @param {Boolean} value + */ set needsUpdate( value ) { if ( value === true ) this.version ++; @@ -49035,27 +65336,93 @@ class BundleGroup extends Group { } -const _material = /*@__PURE__*/ new NodeMaterial(); -const _quadMesh = /*@__PURE__*/ new QuadMesh( _material ); - +/** + * This module is responsible to manage the post processing setups in apps. + * You usually create a single instance of this class and use it to define + * the output of your post processing effect chain. + * ```js + * const postProcessing = new PostProcessing( renderer ); + * + * const scenePass = pass( scene, camera ); + * + * postProcessing.outputNode = scenePass; + * ``` + */ class PostProcessing { + /** + * Constructs a new post processing management module. + * + * @param {Renderer} renderer - A reference to the renderer. + * @param {Node} outputNode - An optional output node. + */ constructor( renderer, outputNode = vec4( 0, 0, 1, 1 ) ) { + /** + * A reference to the renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * A node which defines the final output of the post + * processing. This is usually the last node in a chain + * of effect nodes. + * + * @type {Node} + */ this.outputNode = outputNode; + /** + * Whether the default output tone mapping and color + * space transformation should be enabled or not. + * + * It is enabled by default by it must be disabled when + * effects must be executed after tone mapping and color + * space conversion. A typical example is FXAA which + * requires sRGB input. + * + * When set to `false`, the app must control the output + * transformation with `RenderOutputNode`. + * + * ```js + * const outputPass = renderOutput( scenePass ); + * ``` + * + * @type {Boolean} + */ this.outputColorTransform = true; + /** + * Must be set to `true` when the output node changes. + * + * @type {Node} + */ this.needsUpdate = true; - _material.name = 'PostProcessing'; + const material = new NodeMaterial(); + material.name = 'PostProcessing'; + + /** + * The full screen quad that is used to render + * the effects. + * + * @private + * @type {QuadMesh} + */ + this._quadMesh = new QuadMesh( material ); } + /** + * When `PostProcessing` is used to apply post processing effects, + * the application must use this version of `render()` inside + * its animation loop (not the one from the renderer). + */ render() { - this.update(); + this._update(); const renderer = this.renderer; @@ -49067,7 +65434,7 @@ class PostProcessing { // - _quadMesh.render( renderer ); + this._quadMesh.render( renderer ); // @@ -49076,7 +65443,21 @@ class PostProcessing { } - update() { + /** + * Frees internal resources. + */ + dispose() { + + this._quadMesh.material.dispose(); + + } + + /** + * Updates the state of the module. + * + * @private + */ + _update() { if ( this.needsUpdate === true ) { @@ -49085,8 +65466,8 @@ class PostProcessing { 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._quadMesh.material.fragmentNode = this.outputColorTransform === true ? renderOutput( this.outputNode, toneMapping, outputColorSpace ) : this.outputNode.context( { toneMapping, outputColorSpace } ); + this._quadMesh.material.needsUpdate = true; this.needsUpdate = false; @@ -49094,9 +65475,17 @@ class PostProcessing { } + /** + * When `PostProcessing` is used to apply post processing effects, + * the application must use this version of `renderAsync()` inside + * its animation loop (not the one from the renderer). + * + * @async + * @return {Promise} A Promise that resolves when the render has been finished. + */ async renderAsync() { - this.update(); + this._update(); const renderer = this.renderer; @@ -49108,7 +65497,7 @@ class PostProcessing { // - await _quadMesh.renderAsync( renderer ); + await this._quadMesh.renderAsync( renderer ); // @@ -49119,141 +65508,136 @@ class PostProcessing { } -// renderer state - -function saveRendererState( renderer, state = {} ) { - - state.toneMapping = renderer.toneMapping; - state.toneMappingExposure = renderer.toneMappingExposure; - state.outputColorSpace = renderer.outputColorSpace; - state.renderTarget = renderer.getRenderTarget(); - state.activeCubeFace = renderer.getActiveCubeFace(); - state.activeMipmapLevel = renderer.getActiveMipmapLevel(); - state.renderObjectFunction = renderer.getRenderObjectFunction(); - state.pixelRatio = renderer.getPixelRatio(); - state.mrt = renderer.getMRT(); - state.clearColor = renderer.getClearColor( state.clearColor || new Color() ); - state.clearAlpha = renderer.getClearAlpha(); - state.autoClear = renderer.autoClear; - state.scissorTest = renderer.getScissorTest(); - - return state; - -} - -function resetRendererState( renderer, state ) { - - state = saveRendererState( renderer, state ); - - renderer.setMRT( null ); - renderer.setRenderObjectFunction( null ); - renderer.setClearColor( 0x000000, 1 ); - renderer.autoClear = true; - - return state; - -} - -function restoreRendererState( renderer, state ) { - - renderer.toneMapping = state.toneMapping; - renderer.toneMappingExposure = state.toneMappingExposure; - renderer.outputColorSpace = state.outputColorSpace; - renderer.setRenderTarget( state.renderTarget, state.activeCubeFace, state.activeMipmapLevel ); - renderer.setRenderObjectFunction( state.renderObjectFunction ); - renderer.setPixelRatio( state.pixelRatio ); - renderer.setMRT( state.mrt ); - renderer.setClearColor( state.clearColor, state.clearAlpha ); - renderer.autoClear = state.autoClear; - renderer.setScissorTest( state.scissorTest ); - -} - -// renderer and scene state - -function saveRendererAndSceneState( renderer, scene, state = {} ) { - - state = saveRendererState( renderer, state ); - state.background = scene.background; - state.backgroundNode = scene.backgroundNode; - state.overrideMaterial = scene.overrideMaterial; - - return state; - -} - -function resetRendererAndSceneState( renderer, scene, state ) { - - state = saveRendererAndSceneState( renderer, scene, state ); - - scene.background = null; - scene.backgroundNode = null; - scene.overrideMaterial = null; - - return state; - -} - -function restoreRendererAndSceneState( renderer, scene, state ) { - - restoreRendererState( renderer, state ); - - scene.background = state.background; - scene.backgroundNode = state.backgroundNode; - scene.overrideMaterial = state.overrideMaterial; - -} - -var PostProcessingUtils = /*#__PURE__*/Object.freeze({ - __proto__: null, - resetRendererAndSceneState: resetRendererAndSceneState, - resetRendererState: resetRendererState, - restoreRendererAndSceneState: restoreRendererAndSceneState, - restoreRendererState: restoreRendererState, - saveRendererAndSceneState: saveRendererAndSceneState, - saveRendererState: saveRendererState -}); - +/** + * This special type of texture is intended for compute shaders. + * It can be used to compute the data of a texture with a compute shader. + * + * Note: This type of texture can only be used with `WebGPURenderer` + * and a WebGPU backend. + * + * @augments Texture + */ class StorageTexture extends Texture { + /** + * Constructs a new storage texture. + * + * @param {Number} [width=1] - The storage texture's width. + * @param {Number} [height=1] - The storage texture's height. + */ constructor( width = 1, height = 1 ) { super(); + /** + * The image object which just represents the texture's dimension. + * + * @type {{width: Number, height:Number}} + */ this.image = { width, height }; + /** + * The default `magFilter` for storage textures is `THREE.LinearFilter`. + * + * @type {Number} + */ this.magFilter = LinearFilter; + + /** + * The default `minFilter` for storage textures is `THREE.LinearFilter`. + * + * @type {Number} + */ this.minFilter = LinearFilter; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageTexture = true; } } +/** + * This special type of buffer attribute is intended for compute shaders. + * It can be used to encode draw parameters for indirect draw calls. + * + * Note: This type of buffer attribute can only be used with `WebGPURenderer` + * and a WebGPU backend. + * + * @augments StorageBufferAttribute + */ class IndirectStorageBufferAttribute extends StorageBufferAttribute { - constructor( array, itemSize ) { + /** + * Constructs a new storage buffer attribute. + * + * @param {Number|Uint32Array} count - The item count. It is also valid to pass a `Uint32Array` as an argument. + * The subsequent parameter is then obsolete. + * @param {Number} itemSize - The item size. + */ + constructor( count, itemSize ) { - super( array, itemSize, Uint32Array ); + super( count, itemSize, Uint32Array ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isIndirectStorageBufferAttribute = true; } } +/** + * A loader for loading node objects in the three.js JSON Object/Scene format. + * + * @augments Loader + */ class NodeLoader extends Loader { + /** + * Constructs a new node loader. + * + * @param {LoadingManager?} manager - A reference to a loading manager. + */ constructor( manager ) { super( manager ); + /** + * Represents a dictionary of textures. + * + * @type {Object} + */ this.textures = {}; + + /** + * Represents a dictionary of node types. + * + * @type {Object} + */ this.nodes = {}; } + /** + * Loads the node definitions from the given URL. + * + * @param {String} url - The path/URL of the file to be loaded. + * @param {Function} onLoad - Will be called when load completes. + * @param {Function} onProgress - Will be called while load progresses. + * @param {Function} onError - Will be called when errors are thrown during the loading process. + */ load( url, onLoad, onProgress, onError ) { const loader = new FileLoader( this.manager ); @@ -49286,6 +65670,12 @@ class NodeLoader extends Loader { } + /** + * Parse the node dependencies for the loaded node. + * + * @param {Object} json - The JSON definition + * @return {Object} A dictionary with node dependencies. + */ parseNodes( json ) { const nodes = {}; @@ -49320,6 +65710,12 @@ class NodeLoader extends Loader { } + /** + * Parses the node from the given JSON. + * + * @param {Object} json - The JSON definition + * @return {Node} The parsed node. + */ parse( json ) { const node = this.createNodeFromType( json.type ); @@ -49338,6 +65734,12 @@ class NodeLoader extends Loader { } + /** + * Defines the dictionary of textures. + * + * @param {Object} value - The texture library defines as ``. + * @return {NodeLoader} A reference to this loader. + */ setTextures( value ) { this.textures = value; @@ -49345,6 +65747,12 @@ class NodeLoader extends Loader { } + /** + * Defines the dictionary of node types. + * + * @param {Object} value - The node library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodes( value ) { this.nodes = value; @@ -49352,6 +65760,12 @@ class NodeLoader extends Loader { } + /** + * Creates a node object from the given type. + * + * @param {String} type - The node type. + * @return {Node} The created node instance. + */ createNodeFromType( type ) { if ( this.nodes[ type ] === undefined ) { @@ -49367,17 +65781,44 @@ class NodeLoader extends Loader { } +/** + * A special type of material loader for loading node materials. + * + * @augments MaterialLoader + */ class NodeMaterialLoader extends MaterialLoader { + /** + * Constructs a new node material loader. + * + * @param {LoadingManager?} manager - A reference to a loading manager. + */ constructor( manager ) { super( manager ); + /** + * Represents a dictionary of node types. + * + * @type {Object} + */ this.nodes = {}; + + /** + * Represents a dictionary of node material types. + * + * @type {Object} + */ this.nodeMaterials = {}; } + /** + * Parses the node material from the given JSON. + * + * @param {Object} json - The JSON definition + * @return {NodeMaterial}. The parsed material. + */ parse( json ) { const material = super.parse( json ); @@ -49397,6 +65838,12 @@ class NodeMaterialLoader extends MaterialLoader { } + /** + * Defines the dictionary of node types. + * + * @param {Object} value - The node library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodes( value ) { this.nodes = value; @@ -49404,6 +65851,12 @@ class NodeMaterialLoader extends MaterialLoader { } + /** + * Defines the dictionary of node material types. + * + * @param {Object} value - The node material library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodeMaterials( value ) { this.nodeMaterials = value; @@ -49411,6 +65864,12 @@ class NodeMaterialLoader extends MaterialLoader { } + /** + * Creates a node material from the given type. + * + * @param {String} type - The node material type. + * @return {Node} The created node material instance. + */ createMaterialFromType( type ) { const materialClass = this.nodeMaterials[ type ]; @@ -49427,19 +65886,53 @@ class NodeMaterialLoader extends MaterialLoader { } +/** + * A special type of object loader for loading 3D objects using + * node materials. + * + * @augments ObjectLoader + */ class NodeObjectLoader extends ObjectLoader { + /** + * Constructs a new node object loader. + * + * @param {LoadingManager?} manager - A reference to a loading manager. + */ constructor( manager ) { super( manager ); + /** + * Represents a dictionary of node types. + * + * @type {Object} + */ this.nodes = {}; + + /** + * Represents a dictionary of node material types. + * + * @type {Object} + */ this.nodeMaterials = {}; + /** + * A reference to hold the `nodes` JSON property. + * + * @private + * @type {Object?} + */ this._nodesJSON = null; } + /** + * Defines the dictionary of node types. + * + * @param {Object} value - The node library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodes( value ) { this.nodes = value; @@ -49447,6 +65940,12 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Defines the dictionary of node material types. + * + * @param {Object} value - The node material library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodeMaterials( value ) { this.nodeMaterials = value; @@ -49454,6 +65953,13 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Parses the node objects from the given JSON. + * + * @param {Object} json - The JSON definition + * @param {Function} onLoad - The onLoad callback function. + * @return {Object3D}. The parsed 3D object. + */ parse( json, onLoad ) { this._nodesJSON = json.nodes; @@ -49466,6 +65972,13 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Parses the node objects from the given JSON and textures. + * + * @param {Object} json - The JSON definition + * @param {Object} textures - The texture library. + * @return {Object}. The parsed nodes. + */ parseNodes( json, textures ) { if ( json !== undefined ) { @@ -49482,6 +65995,13 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Parses the node objects from the given JSON and textures. + * + * @param {Object} json - The JSON definition + * @param {Object} textures - The texture library. + * @return {Object}. The parsed materials. + */ parseMaterials( json, textures ) { const materials = {}; @@ -49511,20 +66031,69 @@ class NodeObjectLoader extends ObjectLoader { } +/** + * In earlier three.js versions, clipping was defined globally + * on the renderer or on material level. This special version of + * `THREE.Group` allows to encode the clipping state into the scene + * graph. Meaning if you create an instance of this group, all + * descendant 3D objects will be affected by the respective clipping + * planes. + * + * Note: `ClippingGroup` can only be used with `WebGPURenderer`. + * + * @augments Group + */ class ClippingGroup extends Group { + /** + * Constructs a new clipping group. + */ constructor() { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isClippingGroup = true; + + /** + * An array with clipping planes. + * + * @type {Array} + */ this.clippingPlanes = []; + + /** + * Whether clipping should be enabled or not. + * + * @type {Boolean} + * @default true + */ this.enabled = true; + + /** + * Whether the intersection of the clipping planes is used to clip objects, rather than their union. + * + * @type {Boolean} + * @default false + */ this.clipIntersection = false; + + /** + * Whether shadows should be clipped or not. + * + * @type {Boolean} + * @default false + */ this.clipShadows = false; } } -export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnalyticLightNode, ArrayElementNode, AssignNode, AttributeNode, BackSide, BasicEnvironmentNode, BasicShadowMap, BatchNode, BoxGeometry, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferNode, BumpMapNode, BundleGroup, BypassNode, ByteType, CacheNode, CineonToneMapping, ClampToEdgeWrapping, ClippingGroup, CodeNode, Color, ColorManagement, ColorSpaceNode, ComputeNode, ConstNode, ContextNode, ConvertNode, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureNode, CubeUVReflectionMapping, CullFaceBack, CullFaceFront, CullFaceNone, CustomBlending, DataArrayTexture, DataTexture, DecrementStencilOp, DecrementWrapStencilOp, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicDrawUsage, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectUVNode, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExpressionNode, FileLoader, Float16BufferAttribute, Float32BufferAttribute, FloatType, FogExp2Node, FogNode, FogRangeNode, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLSLNodeParser, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, Group, HalfFloatType, HemisphereLight, HemisphereLightNode, IESSpotLight, IESSpotLightNode, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, IndirectStorageBufferAttribute, InstanceNode, InstancedBufferAttribute, InstancedInterleavedBuffer, InstancedMeshNode, InstancedPointsNodeMaterial, IntType, InterleavedBuffer, InterleavedBufferAttribute, InvertStencilOp, IrradianceNode, JoinNode, KeepStencilOp, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, LightProbe, LightProbeNode, Lighting, LightingContextNode, LightingModel, LightingNode, LightsNode, Line2NodeMaterial, LineBasicMaterial, LineBasicNodeMaterial, LineDashedMaterial, LineDashedNodeMaterial, LinearFilter, LinearMipMapLinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, Loader, LoopNode, LuminanceAlphaFormat, LuminanceFormat, MRTNode, MatcapUVNode, Material, MaterialLoader, MaterialNode, MaterialReferenceNode, MathUtils, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, 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, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, Node, NodeAccess, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalBlending, NormalMapNode, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OneFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, OutputStructNode, PCFShadowMap, PMREMGenerator, PMREMNode, ParameterNode, PassNode, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, Plane, PointLight, PointLightNode, PointUVNode, PointsMaterial, PointsNodeMaterial, PostProcessing, PostProcessingUtils, PosterizeNode, PropertyNode, QuadMesh, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, 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, RGBFormat, RGBIntegerFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RTTNode, RangeNode, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceNode, ReflectorNode, ReinhardToneMapping, RemapNode, RenderOutputNode, RenderTarget, RendererReferenceNode, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RotateNode, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, SceneNode, ScreenNode, ScriptableNode, ScriptableValueNode, SetNode, ShadowBaseNode, ShadowMaterial, ShadowNode, ShadowNodeMaterial, ShortType, SkinningNode, SphereGeometry, SplitNode, SpotLight, SpotLightNode, SpriteMaterial, SpriteNodeMaterial, SpriteSheetUVNode, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StaticDrawUsage, StorageArrayElementNode, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTextureNode, SubtractEquation, SubtractiveBlending, TSL, TangentSpaceNormalMap, TempNode, Texture, Texture3DNode, TextureNode, TextureSizeNode, ToneMappingNode, ToonOutlinePassNode, TriplanarTexturesNode, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, UniformArrayNode, UniformGroupNode, UniformNode, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, VarNode, VaryingNode, Vector2, Vector3, Vector4, VertexColorNode, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGPUCoordinateSystem, WebGPURenderer, ZeroFactor, ZeroStencilOp, createCanvasElement, defaultBuildStages, defaultShaderStages, shaderStages, vectorComponents }; +export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnalyticLightNode, ArrayElementNode, AssignNode, AttributeNode, BackSide, BasicEnvironmentNode, BasicShadowMap, BatchNode, BoxGeometry, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferNode, BumpMapNode, BundleGroup, BypassNode, ByteType, CacheNode, Camera, CineonToneMapping, ClampToEdgeWrapping, ClippingGroup, CodeNode, Color, ColorManagement, ColorSpaceNode, ComputeNode, ConstNode, ContextNode, ConvertNode, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureNode, CubeUVReflectionMapping, CullFaceBack, CullFaceFront, CullFaceNone, CustomBlending, DataArrayTexture, DataTexture, DecrementStencilOp, DecrementWrapStencilOp, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicDrawUsage, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectUVNode, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExpressionNode, FileLoader, Float16BufferAttribute, Float32BufferAttribute, FloatType, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLSLNodeParser, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, Group, HalfFloatType, HemisphereLight, HemisphereLightNode, IESSpotLight, IESSpotLightNode, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, IndirectStorageBufferAttribute, InstanceNode, InstancedBufferAttribute, InstancedInterleavedBuffer, InstancedMeshNode, IntType, InterleavedBuffer, InterleavedBufferAttribute, InvertStencilOp, IrradianceNode, JoinNode, KeepStencilOp, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, LightProbe, LightProbeNode, Lighting, LightingContextNode, LightingModel, LightingNode, LightsNode, Line2NodeMaterial, LineBasicMaterial, LineBasicNodeMaterial, LineDashedMaterial, LineDashedNodeMaterial, LinearFilter, LinearMipMapLinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, Loader, LoopNode, LuminanceAlphaFormat, LuminanceFormat, MRTNode, MatcapUVNode, Material, MaterialLoader, MaterialNode, MaterialReferenceNode, MathUtils, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, MeshLambertMaterial, MeshLambertNodeMaterial, MeshMatcapMaterial, MeshMatcapNodeMaterial, MeshNormalMaterial, MeshNormalNodeMaterial, MeshPhongMaterial, MeshPhongNodeMaterial, MeshPhysicalMaterial, MeshPhysicalNodeMaterial, MeshSSSNodeMaterial, MeshStandardMaterial, MeshStandardNodeMaterial, MeshToonMaterial, MeshToonNodeMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, ModelNode, MorphNode, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, Node, NodeAccess, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalBlending, NormalMapNode, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OneFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, OutputStructNode, PCFShadowMap, PMREMGenerator, PMREMNode, ParameterNode, PassNode, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, Plane, PointLight, PointLightNode, PointUVNode, PointsMaterial, PointsNodeMaterial, PostProcessing, PosterizeNode, PropertyNode, QuadMesh, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, 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, RGBFormat, RGBIntegerFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RTTNode, RangeNode, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceNode, ReflectorNode, ReinhardToneMapping, RemapNode, RenderOutputNode, RenderTarget, RendererReferenceNode, RendererUtils, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RotateNode, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, SceneNode, ScreenNode, ScriptableNode, ScriptableValueNode, SetNode, ShadowBaseNode, ShadowMaterial, ShadowNode, ShadowNodeMaterial, ShortType, SkinningNode, SphereGeometry, SplitNode, SpotLight, SpotLightNode, SpriteMaterial, SpriteNodeMaterial, SpriteSheetUVNode, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StaticDrawUsage, StorageArrayElementNode, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTextureNode, SubtractEquation, SubtractiveBlending, TSL, TangentSpaceNormalMap, TempNode, Texture, Texture3DNode, TextureNode, TextureSizeNode, ToneMappingNode, ToonOutlinePassNode, TriplanarTexturesNode, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, UniformArrayNode, UniformGroupNode, UniformNode, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, VarNode, VaryingNode, Vector2, Vector3, Vector4, VertexColorNode, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGPUCoordinateSystem, WebGPURenderer, ZeroFactor, ZeroStencilOp, createCanvasElement, defaultBuildStages, defaultShaderStages, shaderStages, vectorComponents }; diff --git a/build/three.webgpu.min.js b/build/three.webgpu.min.js index 7dadf25d0dbe5c..4034603bd20a35 100644 --- a/build/three.webgpu.min.js +++ b/build/three.webgpu.min.js @@ -1,6 +1,6 @@ /** * @license - * Copyright 2010-2024 Three.js Authors + * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */ -import{Color as e,Vector2 as t,Vector3 as r,Vector4 as s,Matrix3 as i,Matrix4 as n,EventDispatcher as o,MathUtils as a,ColorManagement as u,SRGBTransfer as l,NoToneMapping as d,StaticDrawUsage as c,InterleavedBuffer as h,DynamicDrawUsage as p,InterleavedBufferAttribute as g,NoColorSpace as m,UnsignedIntType as f,IntType as y,WebGLCoordinateSystem as b,BackSide as x,CubeReflectionMapping as T,CubeRefractionMapping as _,WebGPUCoordinateSystem as v,TangentSpaceNormalMap as N,ObjectSpaceNormalMap as S,InstancedInterleavedBuffer as A,InstancedBufferAttribute as R,DataArrayTexture as C,FloatType as E,FramebufferTexture as w,LinearMipmapLinearFilter as M,DepthTexture as B,Material as U,NormalBlending as F,PointsMaterial as P,LineBasicMaterial as I,LineDashedMaterial as L,NoBlending as D,MeshNormalMaterial as V,WebGLCubeRenderTarget as O,BoxGeometry as G,Mesh as k,Scene as z,LinearFilter as $,CubeCamera as H,CubeTexture as W,EquirectangularReflectionMapping as j,EquirectangularRefractionMapping as q,AddOperation as K,MixOperation as X,MultiplyOperation as Y,MeshBasicMaterial as Q,MeshLambertMaterial as Z,MeshPhongMaterial as J,Texture as ee,MeshStandardMaterial as te,MeshPhysicalMaterial as re,MeshToonMaterial as se,MeshMatcapMaterial as ie,SpriteMaterial as ne,ShadowMaterial as oe,Uint32BufferAttribute as ae,Uint16BufferAttribute as ue,DoubleSide as le,DepthStencilFormat as de,DepthFormat as ce,UnsignedInt248Type as he,UnsignedByteType as pe,RenderTarget as ge,Plane as me,Object3D as fe,HalfFloatType as ye,LinearMipMapLinearFilter as be,OrthographicCamera as xe,BufferGeometry as Te,Float32BufferAttribute as _e,BufferAttribute as ve,UVMapping as Ne,Euler as Se,LinearSRGBColorSpace as Ae,LessCompare as Re,VSMShadowMap as Ce,RGFormat as Ee,BasicShadowMap as we,SphereGeometry as Me,CubeUVReflectionMapping as Be,PerspectiveCamera as Ue,RGBAFormat as Fe,LinearMipmapNearestFilter as Pe,NearestMipmapLinearFilter as Ie,Float16BufferAttribute as Le,REVISION as De,SRGBColorSpace as Ve,PCFShadowMap as Oe,FrontSide as Ge,Frustum as ke,DataTexture as ze,RedIntegerFormat as $e,RedFormat as He,RGIntegerFormat as We,RGBIntegerFormat as je,RGBFormat as qe,RGBAIntegerFormat as Ke,UnsignedShortType as Xe,ByteType as Ye,ShortType as Qe,createCanvasElement as Ze,AddEquation as Je,SubtractEquation as et,ReverseSubtractEquation as tt,ZeroFactor as rt,OneFactor as st,SrcColorFactor as it,SrcAlphaFactor as nt,SrcAlphaSaturateFactor as ot,DstColorFactor as at,DstAlphaFactor as ut,OneMinusSrcColorFactor as lt,OneMinusSrcAlphaFactor as dt,OneMinusDstColorFactor as ct,OneMinusDstAlphaFactor as ht,CullFaceNone as pt,CullFaceBack as gt,CullFaceFront as mt,CustomBlending as ft,MultiplyBlending as yt,SubtractiveBlending as bt,AdditiveBlending as xt,NotEqualDepth as Tt,GreaterDepth as _t,GreaterEqualDepth as vt,EqualDepth as Nt,LessEqualDepth as St,LessDepth as At,AlwaysDepth as Rt,NeverDepth as Ct,UnsignedShort4444Type as Et,UnsignedShort5551Type as wt,UnsignedInt5999Type as Mt,AlphaFormat as Bt,LuminanceFormat as Ut,LuminanceAlphaFormat as Ft,RGB_S3TC_DXT1_Format as Pt,RGBA_S3TC_DXT1_Format as It,RGBA_S3TC_DXT3_Format as Lt,RGBA_S3TC_DXT5_Format as Dt,RGB_PVRTC_4BPPV1_Format as Vt,RGB_PVRTC_2BPPV1_Format as Ot,RGBA_PVRTC_4BPPV1_Format as Gt,RGBA_PVRTC_2BPPV1_Format as kt,RGB_ETC1_Format as zt,RGB_ETC2_Format as $t,RGBA_ETC2_EAC_Format as Ht,RGBA_ASTC_4x4_Format as Wt,RGBA_ASTC_5x4_Format as jt,RGBA_ASTC_5x5_Format as qt,RGBA_ASTC_6x5_Format as Kt,RGBA_ASTC_6x6_Format as Xt,RGBA_ASTC_8x5_Format as Yt,RGBA_ASTC_8x6_Format as Qt,RGBA_ASTC_8x8_Format as Zt,RGBA_ASTC_10x5_Format as Jt,RGBA_ASTC_10x6_Format as er,RGBA_ASTC_10x8_Format as tr,RGBA_ASTC_10x10_Format as rr,RGBA_ASTC_12x10_Format as sr,RGBA_ASTC_12x12_Format as ir,RGBA_BPTC_Format as nr,RED_RGTC1_Format as or,SIGNED_RED_RGTC1_Format as ar,RED_GREEN_RGTC2_Format as ur,SIGNED_RED_GREEN_RGTC2_Format as lr,RepeatWrapping as dr,ClampToEdgeWrapping as cr,MirroredRepeatWrapping as hr,NearestFilter as pr,NearestMipmapNearestFilter as gr,NeverCompare as mr,AlwaysCompare as fr,LessEqualCompare as yr,EqualCompare as br,GreaterEqualCompare as xr,GreaterCompare as Tr,NotEqualCompare as _r,warnOnce as vr,NotEqualStencilFunc as Nr,GreaterStencilFunc as Sr,GreaterEqualStencilFunc as Ar,EqualStencilFunc as Rr,LessEqualStencilFunc as Cr,LessStencilFunc as Er,AlwaysStencilFunc as wr,NeverStencilFunc as Mr,DecrementWrapStencilOp as Br,IncrementWrapStencilOp as Ur,DecrementStencilOp as Fr,IncrementStencilOp as Pr,InvertStencilOp as Ir,ReplaceStencilOp as Lr,ZeroStencilOp as Dr,KeepStencilOp as Vr,MaxEquation as Or,MinEquation as Gr,SpotLight as kr,PointLight as zr,DirectionalLight as $r,RectAreaLight as Hr,AmbientLight as Wr,HemisphereLight as jr,LightProbe as qr,LinearToneMapping as Kr,ReinhardToneMapping as Xr,CineonToneMapping as Yr,ACESFilmicToneMapping as Qr,AgXToneMapping as Zr,NeutralToneMapping as Jr,Group as es,Loader as ts,FileLoader as rs,MaterialLoader as ss,ObjectLoader as is}from"./three.core.min.js";export{AdditiveAnimationBlendMode,AnimationAction,AnimationClip,AnimationLoader,AnimationMixer,AnimationObjectGroup,AnimationUtils,ArcCurve,ArrayCamera,ArrowHelper,AttachedBindMode,Audio,AudioAnalyser,AudioContext,AudioListener,AudioLoader,AxesHelper,BasicDepthPacking,BatchedMesh,Bone,BooleanKeyframeTrack,Box2,Box3,Box3Helper,BoxHelper,BufferGeometryLoader,Cache,Camera,CameraHelper,CanvasTexture,CapsuleGeometry,CatmullRomCurve3,CircleGeometry,Clock,ColorKeyframeTrack,CompressedArrayTexture,CompressedCubeTexture,CompressedTexture,CompressedTextureLoader,ConeGeometry,ConstantAlphaFactor,ConstantColorFactor,Controls,CubeTextureLoader,CubicBezierCurve,CubicBezierCurve3,CubicInterpolant,CullFaceFrontBack,Curve,CurvePath,CustomToneMapping,CylinderGeometry,Cylindrical,Data3DTexture,DataTextureLoader,DataUtils,DefaultLoadingManager,DetachedBindMode,DirectionalLightHelper,DiscreteInterpolant,DodecahedronGeometry,DynamicCopyUsage,DynamicReadUsage,EdgesGeometry,EllipseCurve,ExtrudeGeometry,Fog,FogExp2,GLBufferAttribute,GLSL1,GLSL3,GridHelper,HemisphereLightHelper,IcosahedronGeometry,ImageBitmapLoader,ImageLoader,ImageUtils,InstancedBufferGeometry,InstancedMesh,Int16BufferAttribute,Int32BufferAttribute,Int8BufferAttribute,Interpolant,InterpolateDiscrete,InterpolateLinear,InterpolateSmooth,KeyframeTrack,LOD,LatheGeometry,Layers,Light,Line,Line3,LineCurve,LineCurve3,LineLoop,LineSegments,LinearInterpolant,LinearMipMapNearestFilter,LinearTransfer,LoaderUtils,LoadingManager,LoopOnce,LoopPingPong,LoopRepeat,MOUSE,Matrix2,MeshDepthMaterial,MeshDistanceMaterial,NearestMipMapLinearFilter,NearestMipMapNearestFilter,NormalAnimationBlendMode,NumberKeyframeTrack,OctahedronGeometry,OneMinusConstantAlphaFactor,OneMinusConstantColorFactor,PCFSoftShadowMap,Path,PlaneGeometry,PlaneHelper,PointLightHelper,Points,PolarGridHelper,PolyhedronGeometry,PositionalAudio,PropertyBinding,PropertyMixer,QuadraticBezierCurve,QuadraticBezierCurve3,Quaternion,QuaternionKeyframeTrack,QuaternionLinearInterpolant,RGBADepthPacking,RGBDepthPacking,RGB_BPTC_SIGNED_Format,RGB_BPTC_UNSIGNED_Format,RGDepthPacking,RawShaderMaterial,Ray,Raycaster,RingGeometry,ShaderMaterial,Shape,ShapeGeometry,ShapePath,ShapeUtils,Skeleton,SkeletonHelper,SkinnedMesh,Source,Sphere,Spherical,SphericalHarmonics3,SplineCurve,SpotLightHelper,Sprite,StaticCopyUsage,StaticReadUsage,StereoCamera,StreamCopyUsage,StreamDrawUsage,StreamReadUsage,StringKeyframeTrack,TOUCH,TetrahedronGeometry,TextureLoader,TextureUtils,TorusGeometry,TorusKnotGeometry,Triangle,TriangleFanDrawMode,TriangleStripDrawMode,TrianglesDrawMode,TubeGeometry,Uint8BufferAttribute,Uint8ClampedBufferAttribute,Uniform,UniformsGroup,VectorKeyframeTrack,VideoTexture,WebGL3DRenderTarget,WebGLArrayRenderTarget,WebGLRenderTarget,WireframeGeometry,WrapAroundEnding,ZeroCurvatureEnding,ZeroSlopeEnding}from"./three.core.min.js";const ns=["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 os{constructor(e){this.renderObjects=new WeakMap,this.hasNode=this.containsNode(e),this.hasAnimation=!0===e.object.isSkinnedMesh,this.refreshUniforms=ns,this.renderId=0}firstInitialization(e){return!1===this.renderObjects.has(e)&&(this.getRenderObjectData(e),!0)}getRenderObjectData(e){let t=this.renderObjects.get(e);if(void 0===t){const{geometry:r,material:s,object:i}=e;if(t={material:this.getMaterialData(s),geometry:{attributes:this.getAttributesData(r.attributes),indexVersion:r.index?r.index.version:null,drawRange:{start:r.drawRange.start,count:r.drawRange.count}},worldMatrix:i.matrixWorld.clone()},i.center&&(t.center=i.center.clone()),i.morphTargetInfluences&&(t.morphTargetInfluences=i.morphTargetInfluences.slice()),null!==e.bundle&&(t.version=e.bundle.version),t.material.transmission>0){const{width:r,height:s}=e.context;t.bufferWidth=r,t.bufferHeight=s}this.renderObjects.set(e,t)}return t}getAttributesData(e){const t={};for(const r in e){const s=e[r];t[r]={version:s.version}}return t}containsNode(e){const t=e.material;for(const e in t)if(t[e]&&t[e].isNode)return!0;return null!==e.renderer.nodes.modelViewMatrix||null!==e.renderer.nodes.modelNormalViewMatrix}getMaterialData(e){const t={};for(const r of this.refreshUniforms){const s=e[r];null!=s&&("object"==typeof s&&void 0!==s.clone?!0===s.isTexture?t[r]={id:s.id,version:s.version}:t[r]=s.clone():t[r]=s)}return t}equals(e){const{object:t,material:r,geometry:s}=e,i=this.getRenderObjectData(e);if(!0!==i.worldMatrix.equals(t.matrixWorld))return i.worldMatrix.copy(t.matrixWorld),!1;const n=i.material;for(const e in n){const t=n[e],s=r[e];if(void 0!==t.equals){if(!1===t.equals(s))return t.copy(s),!1}else if(!0===s.isTexture){if(t.id!==s.id||t.version!==s.version)return t.id=s.id,t.version=s.version,!1}else if(t!==s)return n[e]=s,!1}if(n.transmission>0){const{width:t,height:r}=e.context;if(i.bufferWidth!==t||i.bufferHeight!==r)return i.bufferWidth=t,i.bufferHeight=r,!1}const o=i.geometry,a=s.attributes,u=o.attributes,l=Object.keys(u),d=Object.keys(a);if(l.length!==d.length)return i.geometry.attributes=this.getAttributesData(a),!1;for(const e of l){const t=u[e],r=a[e];if(void 0===r)return delete u[e],!1;if(t.version!==r.version)return t.version=r.version,!1}const c=s.index,h=o.indexVersion,p=c?c.version:null;if(h!==p)return o.indexVersion=p,!1;if(o.drawRange.start!==s.drawRange.start||o.drawRange.count!==s.drawRange.count)return o.drawRange.start=s.drawRange.start,o.drawRange.count=s.drawRange.count,!1;if(i.morphTargetInfluences){let e=!1;for(let r=0;r>>16,2246822507),r^=Math.imul(s^s>>>13,3266489909),s=Math.imul(s^s>>>16,2246822507),s^=Math.imul(r^r>>>13,3266489909),4294967296*(2097151&s)+(r>>>0)}const us=e=>as(e),ls=e=>as(e),ds=(...e)=>as(e);function cs(e,t=!1){const r=[];!0===e.isNode&&(r.push(e.id),e=e.getSelf());for(const{property:s,childNode:i}of hs(e))r.push(r,as(s.slice(0,-4)),i.getCacheKey(t));return as(r)}function*hs(e,t=!1){for(const r in e){if(!0===r.startsWith("_"))continue;const s=e[r];if(!0===Array.isArray(s))for(let e=0;ee.charCodeAt(0))).buffer}var Ts=Object.freeze({__proto__:null,arrayBufferToBase64:bs,base64ToArrayBuffer:xs,getCacheKey:cs,getLengthFromType:ms,getNodeChildren:hs,getTypeFromLength:gs,getValueFromType:ys,getValueType:fs,hash:ds,hashArray:ls,hashString:us});const _s={VERTEX:"vertex",FRAGMENT:"fragment"},vs={NONE:"none",FRAME:"frame",RENDER:"render",OBJECT:"object"},Ns={BOOLEAN:"bool",INTEGER:"int",FLOAT:"float",VECTOR2:"vec2",VECTOR3:"vec3",VECTOR4:"vec4",MATRIX2:"mat2",MATRIX3:"mat3",MATRIX4:"mat4"},Ss={READ_ONLY:"readOnly",WRITE_ONLY:"writeOnly",READ_WRITE:"readWrite"},As=["fragment","vertex"],Rs=["setup","analyze","generate"],Cs=[...As,"compute"],Es=["x","y","z","w"];let ws=0;class Ms extends o{static get type(){return"Node"}constructor(e=null){super(),this.nodeType=e,this.updateType=vs.NONE,this.updateBeforeType=vs.NONE,this.updateAfterType=vs.NONE,this.uuid=a.generateUUID(),this.version=0,this.global=!1,this.isNode=!0,this._cacheKey=null,this._cacheKeyVersion=0,Object.defineProperty(this,"id",{value:ws++})}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,vs.FRAME)}onRenderUpdate(e){return this.onUpdate(e,vs.RENDER)}onObjectUpdate(e){return this.onUpdate(e,vs.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 hs(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=ds(cs(this,e),this.customCacheKey()),this._cacheKeyVersion=this.version),this._cacheKey}customCacheKey(){return 0}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 r=0;for(const e of this.getChildren())t["node"+r++]=e;return null}analyze(e){if(1===e.increaseUsage(this)){const t=e.getNodeProperties(this);for(const r of Object.values(t))r&&!0===r.isNode&&r.build(e)}}generate(e,t){const{outputNode:r}=e.getNodeProperties(this);if(r&&!0===r.isNode)return r.build(e,t)}updateBefore(){console.warn("Abstract function.")}updateAfter(){console.warn("Abstract function.")}update(){console.warn("Abstract function.")}build(e,t=null){const r=this.getShared(e);if(this!==r)return r.build(e,t);e.addNode(this),e.addChain(this);let s=null;const i=e.getBuildStage();if("setup"===i){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 r of Object.values(t))r&&!0===r.isNode&&r.build(e)}}else if("analyze"===i)this.analyze(e);else if("generate"===i){if(1===this.generate.length){const r=this.getNodeType(e),i=e.getDataFromNode(this);s=i.snippet,void 0===s?(s=this.generate(e)||"",i.snippet=s):void 0!==i.flowCodes&&void 0!==e.context.nodeBlock&&e.addFlowCodeHierarchy(this,e.context.nodeBlock),s=e.format(s,r,t)}else s=this.generate(e,t)||""}return e.removeChain(this),e.addSequentialNode(this),s}getSerializeChildren(){return hs(this)}serialize(e){const t=this.getSerializeChildren(),r={};for(const{property:s,index:i,childNode:n}of t)void 0!==i?(void 0===r[s]&&(r[s]=Number.isInteger(i)?[]:{}),r[s][i]=n.toJSON(e.meta).uuid):r[s]=n.toJSON(e.meta).uuid;Object.keys(r).length>0&&(e.inputNodes=r)}deserialize(e){if(void 0!==e.inputNodes){const t=e.meta.nodes;for(const r in e.inputNodes)if(Array.isArray(e.inputNodes[r])){const s=[];for(const i of e.inputNodes[r])s.push(t[i]);this[r]=s}else if("object"==typeof e.inputNodes[r]){const s={};for(const i in e.inputNodes[r]){const n=e.inputNodes[r][i];s[i]=t[n]}this[r]=s}else{const s=e.inputNodes[r];this[r]=t[s]}}}toJSON(e){const{uuid:t,type:r}=this,s=void 0===e||"string"==typeof e;s&&(e={textures:{},images:{},nodes:{}});let i=e.nodes[t];function n(e){const t=[];for(const r in e){const s=e[r];delete s.metadata,t.push(s)}return t}if(void 0===i&&(i={uuid:t,type:r,meta:e,metadata:{version:4.6,type:"Node",generator:"Node.toJSON"}},!0!==s&&(e.nodes[i.uuid]=i),this.serialize(i),delete i.meta),s){const t=n(e.textures),r=n(e.images),s=n(e.nodes);t.length>0&&(i.textures=t),r.length>0&&(i.images=r),s.length>0&&(i.nodes=s)}return i}}class Bs extends Ms{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 Us extends Ms{static get type(){return"ConvertNode"}constructor(e,t){super(),this.node=e,this.convertTo=t}getNodeType(e){const t=this.node.getNodeType(e);let r=null;for(const s of this.convertTo.split("|"))null!==r&&e.getTypeLength(t)!==e.getTypeLength(s)||(r=s);return r}serialize(e){super.serialize(e),e.convertTo=this.convertTo}deserialize(e){super.deserialize(e),this.convertTo=e.convertTo}generate(e,t){const r=this.node,s=this.getNodeType(e),i=r.build(e,s);return e.format(i,s,t)}}class Fs extends Ms{static get type(){return"TempNode"}constructor(e=null){super(e),this.isTempNode=!0}hasDependencies(e){return e.getDataFromNode(this).usageCount>1}build(e,t){if("generate"===e.getBuildStage()){const r=e.getVectorType(this.getNodeType(e,t)),s=e.getDataFromNode(this);if(void 0!==s.propertyName)return e.format(s.propertyName,r,t);if("void"!==r&&"void"!==t&&this.hasDependencies(e)){const i=super.build(e,r),n=e.getVarFromNode(this,null,r),o=e.getPropertyName(n);return e.addLineFlowCode(`${o} = ${i}`,this),s.snippet=i,s.propertyName=o,e.format(s.propertyName,r,t)}}return super.build(e,t)}}class Ps extends Fs{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,r)=>t+e.getTypeLength(r.getNodeType(e))),0))}generate(e,t){const r=this.getNodeType(e),s=this.nodes,i=e.getComponentType(r),n=[];for(const t of s){let r=t.build(e);const s=e.getComponentType(t.getNodeType(e));s!==i&&(r=e.format(r,s,i)),n.push(r)}const o=`${e.getType(r)}( ${n.join(", ")} )`;return e.format(o,r,t)}}const Is=Es.join("");class Ls extends Ms{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(Es.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 r=this.node,s=e.getTypeLength(r.getNodeType(e));let i=null;if(s>1){let n=null;this.getVectorLength()>=s&&(n=e.getTypeFromLength(this.getVectorLength(),this.getComponentType(e)));const o=r.build(e,n);i=this.components.length===s&&this.components===Is.slice(0,this.components.length)?e.format(o,n,t):e.format(`${o}.${this.components}`,this.getNodeType(e),t)}else i=r.build(e,t);return i}serialize(e){super.serialize(e),e.components=this.components}deserialize(e){super.deserialize(e),this.components=e.components}}class Ds extends Fs{static get type(){return"SetNode"}constructor(e,t,r){super(),this.sourceNode=e,this.components=t,this.targetNode=r}getNodeType(e){return this.sourceNode.getNodeType(e)}generate(e){const{sourceNode:t,components:r,targetNode:s}=this,i=this.getNodeType(e),n=e.getComponentType(s.getNodeType(e)),o=e.getTypeFromLength(r.length,n),a=s.build(e,o),u=t.build(e,i),l=e.getTypeLength(i),d=[];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"),Ws=e=>Hs(e).split("").sort().join(""),js={setup(e,t){const r=t.shift();return e(yi(r),...t)},get(e,t,r){if("string"==typeof t&&void 0===e[t]){if(!0!==e.isStackNode&&"assign"===t)return(...e)=>(ks.assign(r,...e),r);if(zs.has(t)){const s=zs.get(t);return e.isStackNode?(...e)=>r.add(s(...e)):(...e)=>s(r,...e)}if("self"===t)return e;if(t.endsWith("Assign")&&zs.has(t.slice(0,t.length-6))){const s=zs.get(t.slice(0,t.length-6));return e.isStackNode?(...e)=>r.assign(e[0],s(...e)):(...e)=>r.assign(s(r,...e))}if(!0===/^[xyzwrgbastpq]{1,4}$/.test(t))return t=Hs(t),fi(new Ls(r,t));if(!0===/^set[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Ws(t.slice(3).toLowerCase()),r=>fi(new Ds(e,t,r));if(!0===/^flip[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Ws(t.slice(4).toLowerCase()),()=>fi(new Vs(fi(e),t));if("width"===t||"height"===t||"depth"===t)return"width"===t?t="x":"height"===t?t="y":"depth"===t&&(t="z"),fi(new Ls(e,t));if(!0===/^\d+$/.test(t))return fi(new Bs(r,new Gs(Number(t),"uint")))}return Reflect.get(e,t,r)},set:(e,t,r,s)=>"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,r,s):(s[t].assign(r),!0)},qs=new WeakMap,Ks=new WeakMap,Xs=function(e,t=null){for(const r in e)e[r]=fi(e[r],t);return e},Ys=function(e,t=null){const r=e.length;for(let s=0;sfi(null!==s?Object.assign(e,s):e);return null===t?(...t)=>i(new e(...bi(t))):null!==r?(r=fi(r),(...s)=>i(new e(t,...bi(s),r))):(...r)=>i(new e(t,...bi(r)))},Zs=function(e,...t){return fi(new e(...bi(t)))};class Js extends Ms{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:r}=this,s=e.getNodeProperties(t);if(s.onceOutput)return s.onceOutput;let i=null;if(t.layout){let s=Ks.get(e.constructor);void 0===s&&(s=new WeakMap,Ks.set(e.constructor,s));let n=s.get(t);void 0===n&&(n=fi(e.buildFunctionNode(t)),s.set(t,n)),null!==e.currentFunctionNode&&e.currentFunctionNode.includes.push(n),i=fi(n.call(r))}else{const s=t.jsFunc,n=null!==r?s(r,e):s(e);i=fi(n)}return t.once&&(s.onceOutput=i),i}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 ei extends Ms{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 yi(e),fi(new Js(this,e))}setup(){return this.call()}}const ti=[!1,!0],ri=[0,1,2,3],si=[-1,-2],ii=[.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],ni=new Map;for(const e of ti)ni.set(e,new Gs(e));const oi=new Map;for(const e of ri)oi.set(e,new Gs(e,"uint"));const ai=new Map([...oi].map((e=>new Gs(e.value,"int"))));for(const e of si)ai.set(e,new Gs(e,"int"));const ui=new Map([...ai].map((e=>new Gs(e.value))));for(const e of ii)ui.set(e,new Gs(e));for(const e of ii)ui.set(-e,new Gs(-e));const li={bool:ni,uint:oi,ints:ai,float:ui},di=new Map([...ni,...ui]),ci=(e,t)=>di.has(e)?di.get(e):!0===e.isNode?e:new Gs(e,t),hi=function(e,t=null){return(...r)=>{if((0===r.length||!["bool","float","int","uint"].includes(e)&&r.every((e=>"object"!=typeof e)))&&(r=[ys(e,...r)]),1===r.length&&null!==t&&t.has(r[0]))return fi(t.get(r[0]));if(1===r.length){const t=ci(r[0],e);return(e=>{try{return e.getNodeType()}catch(e){return}})(t)===e?fi(t):fi(new Us(t,e))}const s=r.map((e=>ci(e)));return fi(new Ps(s,e))}},pi=e=>"object"==typeof e&&null!==e?e.value:e,gi=e=>null!=e?e.nodeType||e.convertTo||("string"==typeof e?e:null):null;function mi(e,t){return new Proxy(new ei(e,t),js)}const fi=(e,t=null)=>function(e,t=null){const r=fs(e);if("node"===r){let t=qs.get(e);return void 0===t&&(t=new Proxy(e,js),qs.set(e,t),qs.set(t,t)),t}return null===t&&("float"===r||"boolean"===r)||r&&"shader"!==r&&"string"!==r?fi(ci(e,t)):"shader"===r?_i(e):e}(e,t),yi=(e,t=null)=>new Xs(e,t),bi=(e,t=null)=>new Ys(e,t),xi=(...e)=>new Qs(...e),Ti=(...e)=>new Zs(...e),_i=(e,t)=>{const r=new mi(e,t),s=(...e)=>{let t;return yi(e),t=e[0]&&e[0].isNode?[...e]:e[0],r.call(t)};return s.shaderNode=r,s.setLayout=e=>(r.setLayout(e),s),s.once=()=>(r.once=!0,s),s};$s("toGlobal",(e=>(e.global=!0,e)));const vi=e=>{ks=e},Ni=()=>ks,Si=(...e)=>ks.If(...e);function Ai(e){return ks&&ks.add(e),e}$s("append",Ai);const Ri=new hi("color"),Ci=new hi("float",li.float),Ei=new hi("int",li.ints),wi=new hi("uint",li.uint),Mi=new hi("bool",li.bool),Bi=new hi("vec2"),Ui=new hi("ivec2"),Fi=new hi("uvec2"),Pi=new hi("bvec2"),Ii=new hi("vec3"),Li=new hi("ivec3"),Di=new hi("uvec3"),Vi=new hi("bvec3"),Oi=new hi("vec4"),Gi=new hi("ivec4"),ki=new hi("uvec4"),zi=new hi("bvec4"),$i=new hi("mat2"),Hi=new hi("mat3"),Wi=new hi("mat4");$s("toColor",Ri),$s("toFloat",Ci),$s("toInt",Ei),$s("toUint",wi),$s("toBool",Mi),$s("toVec2",Bi),$s("toIVec2",Ui),$s("toUVec2",Fi),$s("toBVec2",Pi),$s("toVec3",Ii),$s("toIVec3",Li),$s("toUVec3",Di),$s("toBVec3",Vi),$s("toVec4",Oi),$s("toIVec4",Gi),$s("toUVec4",ki),$s("toBVec4",zi),$s("toMat2",$i),$s("toMat3",Hi),$s("toMat4",Wi);const ji=xi(Bs),qi=(e,t)=>fi(new Us(fi(e),t));$s("element",ji),$s("convert",qi);class Ki extends Ms{static get type(){return"UniformGroupNode"}constructor(e,t=!1,r=1){super("string"),this.name=e,this.shared=t,this.order=r,this.isUniformGroup=!0}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 Xi=e=>new Ki(e),Yi=(e,t=0)=>new Ki(e,!0,t),Qi=Yi("frame"),Zi=Yi("render"),Ji=Xi("object");class en extends Os{static get type(){return"UniformNode"}constructor(e,t=null){super(e,t),this.isUniformNode=!0,this.name="",this.groupNode=Ji}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 r=this.getSelf();return e=e.bind(r),super.onUpdate((t=>{const s=e(t,r);void 0!==s&&(this.value=s)}),t)}generate(e,t){const r=this.getNodeType(e),s=this.getUniformHash(e);let i=e.getNodeFromHash(s);void 0===i&&(e.setHashNode(this,s),i=this);const n=i.getInputType(e),o=e.getUniformFromNode(i,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,r,t)}}const tn=(e,t)=>{const r=gi(t||e),s=e&&!0===e.isNode?e.node&&e.node.value||e.value:e;return fi(new en(s,r))};class rn extends Ms{static get type(){return"PropertyNode"}constructor(e,t=null,r=!1){super(e),this.name=t,this.varying=r,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 sn=(e,t)=>fi(new rn(e,t)),nn=(e,t)=>fi(new rn(e,t,!0)),on=Ti(rn,"vec4","DiffuseColor"),an=Ti(rn,"vec3","EmissiveColor"),un=Ti(rn,"float","Roughness"),ln=Ti(rn,"float","Metalness"),dn=Ti(rn,"float","Clearcoat"),cn=Ti(rn,"float","ClearcoatRoughness"),hn=Ti(rn,"vec3","Sheen"),pn=Ti(rn,"float","SheenRoughness"),gn=Ti(rn,"float","Iridescence"),mn=Ti(rn,"float","IridescenceIOR"),fn=Ti(rn,"float","IridescenceThickness"),yn=Ti(rn,"float","AlphaT"),bn=Ti(rn,"float","Anisotropy"),xn=Ti(rn,"vec3","AnisotropyT"),Tn=Ti(rn,"vec3","AnisotropyB"),_n=Ti(rn,"color","SpecularColor"),vn=Ti(rn,"float","SpecularF90"),Nn=Ti(rn,"float","Shininess"),Sn=Ti(rn,"vec4","Output"),An=Ti(rn,"float","dashSize"),Rn=Ti(rn,"float","gapSize"),Cn=Ti(rn,"float","pointWidth"),En=Ti(rn,"float","IOR"),wn=Ti(rn,"float","Transmission"),Mn=Ti(rn,"float","Thickness"),Bn=Ti(rn,"float","AttenuationDistance"),Un=Ti(rn,"color","AttenuationColor"),Fn=Ti(rn,"float","Dispersion");class Pn extends Fs{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 r=e.getTypeLength(t.node.getNodeType(e));return Es.join("").slice(0,r)!==t.components}return!1}generate(e,t){const{targetNode:r,sourceNode:s}=this,i=this.needsSplitAssign(e),n=r.getNodeType(e),o=r.context({assign:!0}).build(e),a=s.build(e,n),u=s.getNodeType(e),l=e.getDataFromNode(this);let d;if(!0===l.initialized)"void"!==t&&(d=o);else if(i){const s=e.getVarFromNode(this,null,n),i=e.getPropertyName(s);e.addLineFlowCode(`${i} = ${a}`,this);const u=r.node.context({assign:!0}).build(e);for(let t=0;t{const s=r.type;let i;return i="pointer"===s?"&"+t.build(e):t.build(e,s),i};if(Array.isArray(i))for(let e=0;e(t=t.length>1||t[0]&&!0===t[0].isNode?bi(t):yi(t[0]),fi(new Ln(fi(e),t)));$s("call",Dn);class Vn extends Fs{static get type(){return"OperatorNode"}constructor(e,t,r,...s){if(super(),s.length>0){let i=new Vn(e,t,r);for(let t=0;t>"===r||"<<"===r)return e.getIntegerType(n);if("!"===r||"=="===r||"&&"===r||"||"===r||"^^"===r)return"bool";if("<"===r||">"===r||"<="===r||">="===r){const r=t?e.getTypeLength(t):Math.max(e.getTypeLength(n),e.getTypeLength(o));return r>1?`bvec${r}`:"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 r=this.op,s=this.aNode,i=this.bNode,n=this.getNodeType(e,t);let o=null,a=null;"void"!==n?(o=s.getNodeType(e),a=void 0!==i?i.getNodeType(e):null,"<"===r||">"===r||"<="===r||">="===r||"=="===r?e.isVector(o)?a=o:o!==a&&(o=a="float"):">>"===r||"<<"===r?(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 u=s.build(e,o),l=void 0!==i?i.build(e,a):null,d=e.getTypeLength(t),c=e.getFunctionOperator(r);return"void"!==t?"<"===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThan",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} < ${l} )`,n,t):"<="===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThanEqual",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} <= ${l} )`,n,t):">"===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThan",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} > ${l} )`,n,t):">="===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThanEqual",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} >= ${l} )`,n,t):"!"===r||"~"===r?e.format(`(${r}${u})`,o,t):c?e.format(`${c}( ${u}, ${l} )`,n,t):e.format(`( ${u} ${r} ${l} )`,n,t):"void"!==o?c?e.format(`${c}( ${u}, ${l} )`,n,t):e.format(`${u} ${r} ${l}`,n,t):void 0}serialize(e){super.serialize(e),e.op=this.op}deserialize(e){super.deserialize(e),this.op=e.op}}const On=xi(Vn,"+"),Gn=xi(Vn,"-"),kn=xi(Vn,"*"),zn=xi(Vn,"/"),$n=xi(Vn,"%"),Hn=xi(Vn,"=="),Wn=xi(Vn,"!="),jn=xi(Vn,"<"),qn=xi(Vn,">"),Kn=xi(Vn,"<="),Xn=xi(Vn,">="),Yn=xi(Vn,"&&"),Qn=xi(Vn,"||"),Zn=xi(Vn,"!"),Jn=xi(Vn,"^^"),eo=xi(Vn,"&"),to=xi(Vn,"~"),ro=xi(Vn,"|"),so=xi(Vn,"^"),io=xi(Vn,"<<"),no=xi(Vn,">>");$s("add",On),$s("sub",Gn),$s("mul",kn),$s("div",zn),$s("modInt",$n),$s("equal",Hn),$s("notEqual",Wn),$s("lessThan",jn),$s("greaterThan",qn),$s("lessThanEqual",Kn),$s("greaterThanEqual",Xn),$s("and",Yn),$s("or",Qn),$s("not",Zn),$s("xor",Jn),$s("bitAnd",eo),$s("bitNot",to),$s("bitOr",ro),$s("bitXor",so),$s("shiftLeft",io),$s("shiftRight",no);const oo=(...e)=>(console.warn("TSL.OperatorNode: .remainder() has been renamed to .modInt()."),$n(...e));$s("remainder",oo);class ao extends Fs{static get type(){return"MathNode"}constructor(e,t,r=null,s=null){super(),this.method=e,this.aNode=t,this.bNode=r,this.cNode=s}getInputType(e){const t=this.aNode.getNodeType(e),r=this.bNode?this.bNode.getNodeType(e):null,s=this.cNode?this.cNode.getNodeType(e):null,i=e.isMatrix(t)?0:e.getTypeLength(t),n=e.isMatrix(r)?0:e.getTypeLength(r),o=e.isMatrix(s)?0:e.getTypeLength(s);return i>n&&i>o?t:n>o?r:o>i?s:t}getNodeType(e){const t=this.method;return t===ao.LENGTH||t===ao.DISTANCE||t===ao.DOT?"float":t===ao.CROSS?"vec3":t===ao.ALL?"bool":t===ao.EQUALS?e.changeComponentType(this.aNode.getNodeType(e),"bool"):t===ao.MOD?this.aNode.getNodeType(e):this.getInputType(e)}generate(e,t){const r=this.method,s=this.getNodeType(e),i=this.getInputType(e),n=this.aNode,o=this.bNode,a=this.cNode,u=!0===e.renderer.isWebGLRenderer;if(r===ao.TRANSFORM_DIRECTION){let r=n,s=o;e.isMatrix(r.getNodeType(e))?s=Oi(Ii(s),0):r=Oi(Ii(r),0);const i=kn(r,s).xyz;return Ro(i).build(e,t)}if(r===ao.NEGATE)return e.format("( - "+n.build(e,i)+" )",s,t);if(r===ao.ONE_MINUS)return Gn(1,n).build(e,t);if(r===ao.RECIPROCAL)return zn(1,n).build(e,t);if(r===ao.DIFFERENCE)return Po(Gn(n,o)).build(e,t);{const l=[];return r===ao.CROSS||r===ao.MOD?l.push(n.build(e,s),o.build(e,s)):u&&r===ao.STEP?l.push(n.build(e,1===e.getTypeLength(n.getNodeType(e))?"float":i),o.build(e,i)):u&&(r===ao.MIN||r===ao.MAX)||r===ao.MOD?l.push(n.build(e,i),o.build(e,1===e.getTypeLength(o.getNodeType(e))?"float":i)):r===ao.REFRACT?l.push(n.build(e,i),o.build(e,i),a.build(e,"float")):r===ao.MIX?l.push(n.build(e,i),o.build(e,i),a.build(e,1===e.getTypeLength(a.getNodeType(e))?"float":i)):(l.push(n.build(e,i)),null!==o&&l.push(o.build(e,i)),null!==a&&l.push(a.build(e,i))),e.format(`${e.getMethod(r,s)}( ${l.join(", ")} )`,s,t)}}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}ao.ALL="all",ao.ANY="any",ao.EQUALS="equals",ao.RADIANS="radians",ao.DEGREES="degrees",ao.EXP="exp",ao.EXP2="exp2",ao.LOG="log",ao.LOG2="log2",ao.SQRT="sqrt",ao.INVERSE_SQRT="inversesqrt",ao.FLOOR="floor",ao.CEIL="ceil",ao.NORMALIZE="normalize",ao.FRACT="fract",ao.SIN="sin",ao.COS="cos",ao.TAN="tan",ao.ASIN="asin",ao.ACOS="acos",ao.ATAN="atan",ao.ABS="abs",ao.SIGN="sign",ao.LENGTH="length",ao.NEGATE="negate",ao.ONE_MINUS="oneMinus",ao.DFDX="dFdx",ao.DFDY="dFdy",ao.ROUND="round",ao.RECIPROCAL="reciprocal",ao.TRUNC="trunc",ao.FWIDTH="fwidth",ao.BITCAST="bitcast",ao.TRANSPOSE="transpose",ao.ATAN2="atan2",ao.MIN="min",ao.MAX="max",ao.MOD="mod",ao.STEP="step",ao.REFLECT="reflect",ao.DISTANCE="distance",ao.DIFFERENCE="difference",ao.DOT="dot",ao.CROSS="cross",ao.POW="pow",ao.TRANSFORM_DIRECTION="transformDirection",ao.MIX="mix",ao.CLAMP="clamp",ao.REFRACT="refract",ao.SMOOTHSTEP="smoothstep",ao.FACEFORWARD="faceforward";const uo=Ci(1e-6),lo=Ci(1e6),co=Ci(Math.PI),ho=Ci(2*Math.PI),po=xi(ao,ao.ALL),go=xi(ao,ao.ANY),mo=xi(ao,ao.EQUALS),fo=xi(ao,ao.RADIANS),yo=xi(ao,ao.DEGREES),bo=xi(ao,ao.EXP),xo=xi(ao,ao.EXP2),To=xi(ao,ao.LOG),_o=xi(ao,ao.LOG2),vo=xi(ao,ao.SQRT),No=xi(ao,ao.INVERSE_SQRT),So=xi(ao,ao.FLOOR),Ao=xi(ao,ao.CEIL),Ro=xi(ao,ao.NORMALIZE),Co=xi(ao,ao.FRACT),Eo=xi(ao,ao.SIN),wo=xi(ao,ao.COS),Mo=xi(ao,ao.TAN),Bo=xi(ao,ao.ASIN),Uo=xi(ao,ao.ACOS),Fo=xi(ao,ao.ATAN),Po=xi(ao,ao.ABS),Io=xi(ao,ao.SIGN),Lo=xi(ao,ao.LENGTH),Do=xi(ao,ao.NEGATE),Vo=xi(ao,ao.ONE_MINUS),Oo=xi(ao,ao.DFDX),Go=xi(ao,ao.DFDY),ko=xi(ao,ao.ROUND),zo=xi(ao,ao.RECIPROCAL),$o=xi(ao,ao.TRUNC),Ho=xi(ao,ao.FWIDTH),Wo=xi(ao,ao.BITCAST),jo=xi(ao,ao.TRANSPOSE),qo=xi(ao,ao.ATAN2),Ko=xi(ao,ao.MIN),Xo=xi(ao,ao.MAX),Yo=xi(ao,ao.MOD),Qo=xi(ao,ao.STEP),Zo=xi(ao,ao.REFLECT),Jo=xi(ao,ao.DISTANCE),ea=xi(ao,ao.DIFFERENCE),ta=xi(ao,ao.DOT),ra=xi(ao,ao.CROSS),sa=xi(ao,ao.POW),ia=xi(ao,ao.POW,2),na=xi(ao,ao.POW,3),oa=xi(ao,ao.POW,4),aa=xi(ao,ao.TRANSFORM_DIRECTION),ua=e=>kn(Io(e),sa(Po(e),1/3)),la=e=>ta(e,e),da=xi(ao,ao.MIX),ca=(e,t=0,r=1)=>fi(new ao(ao.CLAMP,fi(e),fi(t),fi(r))),ha=e=>ca(e),pa=xi(ao,ao.REFRACT),ga=xi(ao,ao.SMOOTHSTEP),ma=xi(ao,ao.FACEFORWARD),fa=_i((([e])=>{const t=ta(e.xy,Bi(12.9898,78.233)),r=Yo(t,co);return Co(Eo(r).mul(43758.5453))})),ya=(e,t,r)=>da(t,r,e),ba=(e,t,r)=>ga(t,r,e);$s("all",po),$s("any",go),$s("equals",mo),$s("radians",fo),$s("degrees",yo),$s("exp",bo),$s("exp2",xo),$s("log",To),$s("log2",_o),$s("sqrt",vo),$s("inverseSqrt",No),$s("floor",So),$s("ceil",Ao),$s("normalize",Ro),$s("fract",Co),$s("sin",Eo),$s("cos",wo),$s("tan",Mo),$s("asin",Bo),$s("acos",Uo),$s("atan",Fo),$s("abs",Po),$s("sign",Io),$s("length",Lo),$s("lengthSq",la),$s("negate",Do),$s("oneMinus",Vo),$s("dFdx",Oo),$s("dFdy",Go),$s("round",ko),$s("reciprocal",zo),$s("trunc",$o),$s("fwidth",Ho),$s("atan2",qo),$s("min",Ko),$s("max",Xo),$s("mod",Yo),$s("step",Qo),$s("reflect",Zo),$s("distance",Jo),$s("dot",ta),$s("cross",ra),$s("pow",sa),$s("pow2",ia),$s("pow3",na),$s("pow4",oa),$s("transformDirection",aa),$s("mix",ya),$s("clamp",ca),$s("refract",pa),$s("smoothstep",ba),$s("faceForward",ma),$s("difference",ea),$s("saturate",ha),$s("cbrt",ua),$s("transpose",jo),$s("rand",fa);class xa extends Ms{static get type(){return"ConditionalNode"}constructor(e,t,r=null){super(),this.condNode=e,this.ifNode=t,this.elseNode=r}getNodeType(e){const t=this.ifNode.getNodeType(e);if(null!==this.elseNode){const r=this.elseNode.getNodeType(e);if(e.getTypeLength(r)>e.getTypeLength(t))return r}return t}setup(e){const t=this.condNode.cache(),r=this.ifNode.cache(),s=this.elseNode?this.elseNode.cache():null,i=e.context.nodeBlock;e.getDataFromNode(r).parentNodeBlock=i,null!==s&&(e.getDataFromNode(s).parentNodeBlock=i);const n=e.getNodeProperties(this);n.condNode=t,n.ifNode=r.context({nodeBlock:r}),n.elseNode=s?s.context({nodeBlock:s}):null}generate(e,t){const r=this.getNodeType(e),s=e.getDataFromNode(this);if(void 0!==s.nodeProperty)return s.nodeProperty;const{condNode:i,ifNode:n,elseNode:o}=e.getNodeProperties(this),a="void"!==t,u=a?sn(r).build(e):"";s.nodeProperty=u;const l=i.build(e,"bool");e.addFlowCode(`\n${e.tab}if ( ${l} ) {\n\n`).addFlowTab();let d=n.build(e,r);if(d&&(d=a?u+" = "+d+";":"return "+d+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+d+"\n\n"+e.tab+"}"),null!==o){e.addFlowCode(" else {\n\n").addFlowTab();let t=o.build(e,r);t&&(t=a?u+" = "+t+";":"return "+t+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+t+"\n\n"+e.tab+"}\n\n")}else e.addFlowCode("\n\n");return e.format(u,r,t)}}const Ta=xi(xa);$s("select",Ta);const _a=(...e)=>(console.warn("TSL.ConditionalNode: cond() has been renamed to select()."),Ta(...e));$s("cond",_a);class va extends Ms{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 r=this.node.build(e);return e.setContext(t),r}generate(e,t){const r=e.getContext();e.setContext({...e.context,...this.value});const s=this.node.build(e,t);return e.setContext(r),s}}const Na=xi(va),Sa=(e,t)=>Na(e,{label:t});$s("context",Na),$s("label",Sa);class Aa extends Ms{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:r}=this,s=e.getVarFromNode(this,r,e.getVectorType(this.getNodeType(e))),i=e.getPropertyName(s),n=t.build(e,s.type);return e.addLineFlowCode(`${i} = ${n}`,this),i}}const Ra=xi(Aa);$s("toVar",((...e)=>Ra(...e).append()));const Ca=e=>(console.warn('TSL: "temp" is deprecated. Use ".toVar()" instead.'),Ra(e));$s("temp",Ca);class Ea extends Ms{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 r=t.varying;if(void 0===r){const s=this.name,i=this.getNodeType(e);t.varying=r=e.getVaryingFromNode(this,s,i),t.node=this.node}return r.needsInterpolation||(r.needsInterpolation="fragment"===e.shaderStage),r}setup(e){this.setupVarying(e)}analyze(e){return this.setupVarying(e),this.node.analyze(e)}generate(e){const t=e.getNodeProperties(this),r=this.setupVarying(e);if(void 0===t.propertyName){const s=this.getNodeType(e),i=e.getPropertyName(r,_s.VERTEX);e.flowNodeFromShaderStage(_s.VERTEX,this.node,s,i),t.propertyName=i}return e.getPropertyName(r)}}const wa=xi(Ea);$s("varying",wa);const Ma=_i((([e])=>{const t=e.mul(.9478672986).add(.0521327014).pow(2.4),r=e.mul(.0773993808),s=e.lessThanEqual(.04045);return da(t,r,s)})).setLayout({name:"sRGBTransferEOTF",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),Ba=_i((([e])=>{const t=e.pow(.41666).mul(1.055).sub(.055),r=e.mul(12.92),s=e.lessThanEqual(.0031308);return da(t,r,s)})).setLayout({name:"sRGBTransferOETF",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),Ua="WorkingColorSpace",Fa="OutputColorSpace";class Pa extends Fs{static get type(){return"ColorSpaceNode"}constructor(e,t,r){super("vec4"),this.colorNode=e,this.source=t,this.target=r}resolveColorSpace(e,t){return t===Ua?u.workingColorSpace:t===Fa?e.context.outputColorSpace||e.renderer.outputColorSpace:t}setup(e){const{colorNode:t}=this,r=this.resolveColorSpace(e,this.source),s=this.resolveColorSpace(e,this.target);let n=t;return!1!==u.enabled&&r!==s&&r&&s?(u.getTransfer(r)===l&&(n=Oi(Ma(n.rgb),n.a)),u.getPrimaries(r)!==u.getPrimaries(s)&&(n=Oi(Hi(u._getMatrix(new i,r,s)).mul(n.rgb),n.a)),u.getTransfer(s)===l&&(n=Oi(Ba(n.rgb),n.a)),n):n}}const Ia=e=>fi(new Pa(fi(e),Ua,Fa)),La=e=>fi(new Pa(fi(e),Fa,Ua)),Da=(e,t)=>fi(new Pa(fi(e),Ua,t)),Va=(e,t)=>fi(new Pa(fi(e),t,Ua));$s("toOutputColorSpace",Ia),$s("toWorkingColorSpace",La),$s("workingToColorSpace",Da),$s("colorSpaceToWorking",Va);let Oa=class extends Bs{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),r=this.referenceNode.getNodeType(),s=this.getNodeType();return e.format(t,r,s)}};class Ga extends Ms{static get type(){return"ReferenceBaseNode"}constructor(e,t,r=null,s=null){super(),this.property=e,this.uniformType=t,this.object=r,this.count=s,this.properties=e.split("."),this.reference=r,this.node=null,this.group=null,this.updateType=vs.OBJECT}setGroup(e){return this.group=e,this}element(e){return fi(new Oa(this,fi(e)))}setNodeType(e){const t=tn(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 r=e[t[0]];for(let e=1;efi(new ka(e,t,r));class $a extends Fs{static get type(){return"ToneMappingNode"}constructor(e,t=Wa,r=null){super("vec3"),this.toneMapping=e,this.exposureNode=t,this.colorNode=r}customCacheKey(){return ds(this.toneMapping)}setup(e){const t=this.colorNode||e.context.color,r=this.toneMapping;if(r===d)return t;let s=null;const i=e.renderer.library.getToneMappingFunction(r);return null!==i?s=Oi(i(t.rgb,this.exposureNode),t.a):(console.error("ToneMappingNode: Unsupported Tone Mapping configuration.",r),s=t),s}}const Ha=(e,t,r)=>fi(new $a(e,fi(t),fi(r))),Wa=za("toneMappingExposure","float");$s("toneMapping",((e,t,r)=>Ha(t,r,e)));class ja extends Os{static get type(){return"BufferAttributeNode"}constructor(e,t=null,r=0,s=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferStride=r,this.bufferOffset=s,this.usage=c,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),r=this.value,s=e.getTypeLength(t),i=this.bufferStride||s,n=this.bufferOffset,o=!0===r.isInterleavedBuffer?r:new h(r,i),a=new g(o,s,n);o.setUsage(this.usage),this.attribute=a,this.attribute.isInstancedBufferAttribute=this.instanced}generate(e){const t=this.getNodeType(e),r=e.getBufferAttributeFromNode(this,t),s=e.getPropertyName(r);let i=null;if("vertex"===e.shaderStage||"compute"===e.shaderStage)this.name=s,i=s;else{i=wa(this).build(e,t)}return i}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 qa=(e,t,r,s)=>fi(new ja(e,t,r,s)),Ka=(e,t,r,s)=>qa(e,t,r,s).setUsage(p),Xa=(e,t,r,s)=>qa(e,t,r,s).setInstanced(!0),Ya=(e,t,r,s)=>Ka(e,t,r,s).setInstanced(!0);$s("toAttribute",(e=>qa(e.value)));class Qa extends Ms{static get type(){return"ComputeNode"}constructor(e,t,r=[64]){super("void"),this.isComputeNode=!0,this.computeNode=e,this.count=t,this.workgroupSize=r,this.dispatchCount=0,this.version=1,this.updateBeforeType=vs.OBJECT,this.onInitFunction=null,this.updateDispatchCount()}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){!0===e&&this.version++}updateDispatchCount(){const{count:e,workgroupSize:t}=this;let r=t[0];for(let e=1;efi(new Qa(fi(e),t,r));$s("compute",Za);class Ja extends Ms{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 r=e.getCache(),s=e.getCacheFromNode(this,this.parent);e.setCache(s);const i=this.node.build(e,...t);return e.setCache(r),i}}const eu=(e,...t)=>fi(new Ja(fi(e),...t));$s("cache",eu);class tu extends Ms{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 ru=xi(tu);$s("bypass",ru);class su extends Ms{static get type(){return"RemapNode"}constructor(e,t,r,s=Ci(0),i=Ci(1)){super(),this.node=e,this.inLowNode=t,this.inHighNode=r,this.outLowNode=s,this.outHighNode=i,this.doClamp=!0}setup(){const{node:e,inLowNode:t,inHighNode:r,outLowNode:s,outHighNode:i,doClamp:n}=this;let o=e.sub(t).div(r.sub(t));return!0===n&&(o=o.clamp()),o.mul(i.sub(s)).add(s)}}const iu=xi(su,null,null,{doClamp:!1}),nu=xi(su);$s("remap",iu),$s("remapClamp",nu);class ou extends Ms{static get type(){return"ExpressionNode"}constructor(e="",t="void"){super(t),this.snippet=e}generate(e,t){const r=this.getNodeType(e),s=this.snippet;if("void"!==r)return e.format(`( ${s} )`,r,t);e.addLineFlowCode(s,this)}}const au=xi(ou),uu=e=>(e?Ta(e,au("discard")):au("discard")).append();$s("discard",uu);class lu extends Fs{static get type(){return"RenderOutputNode"}constructor(e,t,r){super("vec4"),this.colorNode=e,this.toneMapping=t,this.outputColorSpace=r,this.isRenderOutputNode=!0}setup({context:e}){let t=this.colorNode||e.color;const r=(null!==this.toneMapping?this.toneMapping:e.toneMapping)||d,s=(null!==this.outputColorSpace?this.outputColorSpace:e.outputColorSpace)||m;return r!==d&&(t=t.toneMapping(r)),s!==m&&s!==u.workingColorSpace&&(t=t.workingToColorSpace(s)),t}}const du=(e,t=null,r=null)=>fi(new lu(fi(e),t,r));$s("renderOutput",du);class cu extends Ms{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 r=this.getAttributeName(e);if(e.hasGeometryAttribute(r)){const s=e.geometry.getAttribute(r);t=e.getTypeFromAttribute(s)}else t="float"}return t}setAttributeName(e){return this._attributeName=e,this}getAttributeName(){return this._attributeName}generate(e){const t=this.getAttributeName(e),r=this.getNodeType(e);if(!0===e.hasGeometryAttribute(t)){const s=e.geometry.getAttribute(t),i=e.getTypeFromAttribute(s),n=e.getAttribute(t,i);if("vertex"===e.shaderStage)return e.format(n.name,i,r);return wa(this).build(e,r)}return console.warn(`AttributeNode: Vertex attribute "${t}" not found on geometry.`),e.generateConst(r)}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 hu=(e,t)=>fi(new cu(e,t)),pu=e=>hu("uv"+(e>0?e:""),"vec2");class gu extends Ms{static get type(){return"TextureSizeNode"}constructor(e,t=null){super("uvec2"),this.isTextureSizeNode=!0,this.textureNode=e,this.levelNode=t}generate(e,t){const r=this.textureNode.build(e,"property"),s=null===this.levelNode?"0":this.levelNode.build(e,"int");return e.format(`${e.getMethod("textureDimensions")}( ${r}, ${s} )`,this.getNodeType(e),t)}}const mu=xi(gu);class fu extends en{static get type(){return"MaxMipLevelNode"}constructor(e){super(0),this._textureNode=e,this.updateType=vs.FRAME}get textureNode(){return this._textureNode}get texture(){return this._textureNode.value}update(){const e=this.texture,t=e.images,r=t&&t.length>0?t[0]&&t[0].image||t[0]:e.image;if(r&&void 0!==r.width){const{width:e,height:t}=r;this.value=Math.log2(Math.max(e,t))}}}const yu=xi(fu);class bu extends en{static get type(){return"TextureNode"}constructor(e,t=null,r=null,s=null){super(e),this.isTextureNode=!0,this.uvNode=t,this.levelNode=r,this.biasNode=s,this.compareNode=null,this.depthNode=null,this.gradNode=null,this.sampler=!0,this.updateMatrix=!1,this.updateType=vs.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===f?"uvec4":this.value.type===y?"ivec4":"vec4"}getInputType(){return"texture"}getDefaultUV(){return pu(this.value.channel)}updateReference(){return this.value}getTransformedUV(e){return null===this._matrixUniform&&(this._matrixUniform=tn(this.value.matrix)),this._matrixUniform.mul(Ii(e,1)).xy}setUpdateMatrix(e){return this.updateMatrix=e,this.updateType=e?vs.FRAME:vs.NONE,this}setupUV(e,t){const r=this.value;return e.isFlipY()&&(r.image instanceof ImageBitmap&&!0===r.flipY||!0===r.isRenderTargetTexture||!0===r.isFramebufferTexture||!0===r.isDepthTexture)&&(t=this.sampler?t.flipY():t.setY(Ei(mu(this,this.levelNode).y).sub(t.y).sub(1))),t}setup(e){const t=e.getNodeProperties(this);t.referenceNode=this.referenceNode;let r=this.uvNode;null!==r&&!0!==e.context.forceUVContext||!e.context.getUV||(r=e.context.getUV(this)),r||(r=this.getDefaultUV()),!0===this.updateMatrix&&(r=this.getTransformedUV(r)),r=this.setupUV(e,r);let s=this.levelNode;null===s&&e.context.getTextureLevel&&(s=e.context.getTextureLevel(this)),t.uvNode=r,t.levelNode=s,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,r,s,i,n,o,a){const u=this.value;let l;return l=s?e.generateTextureLevel(u,t,r,s,n):i?e.generateTextureBias(u,t,r,i,n):a?e.generateTextureGrad(u,t,r,a,n):o?e.generateTextureCompare(u,t,r,o,n):!1===this.sampler?e.generateTextureLoad(u,t,r,n):e.generateTexture(u,t,r,n),l}generate(e,t){const r=e.getNodeProperties(this),s=this.value;if(!s||!0!==s.isTexture)throw new Error("TextureNode: Need a three.js texture.");const i=super.generate(e,"property");if("sampler"===t)return i+"_sampler";if(e.isReference(t))return i;{const n=e.getDataFromNode(this);let o=n.propertyName;if(void 0===o){const{uvNode:t,levelNode:s,biasNode:a,compareNode:u,depthNode:l,gradNode:d}=r,c=this.generateUV(e,t),h=s?s.build(e,"float"):null,p=a?a.build(e,"float"):null,g=l?l.build(e,"int"):null,m=u?u.build(e,"float"):null,f=d?[d[0].build(e,"vec2"),d[1].build(e,"vec2")]:null,y=e.getVarFromNode(this);o=e.getPropertyName(y);const b=this.generateSnippet(e,i,c,h,p,g,m,f);e.addLineFlowCode(`${o} = ${b}`,this),n.snippet=b,n.propertyName=o}let a=o;const u=this.getNodeType(e);return e.needsToWorkingColorSpace(s)&&(a=Va(au(a,u),s.colorSpace).setup(e).build(e,u)),e.format(a,u,t)}}setSampler(e){return this.sampler=e,this}getSampler(){return this.sampler}uv(e){return console.warn("THREE.TextureNode: .uv() has been renamed. Use .sample() instead."),this.sample(e)}sample(e){const t=this.clone();return t.uvNode=fi(e),t.referenceNode=this.getSelf(),fi(t)}blur(e){const t=this.clone();return t.biasNode=fi(e).mul(yu(t)),t.referenceNode=this.getSelf(),fi(t)}level(e){const t=this.clone();return t.levelNode=fi(e),t.referenceNode=this.getSelf(),fi(t)}size(e){return mu(this,e)}bias(e){const t=this.clone();return t.biasNode=fi(e),t.referenceNode=this.getSelf(),fi(t)}compare(e){const t=this.clone();return t.compareNode=fi(e),t.referenceNode=this.getSelf(),fi(t)}grad(e,t){const r=this.clone();return r.gradNode=[fi(e),fi(t)],r.referenceNode=this.getSelf(),fi(r)}depth(e){const t=this.clone();return t.depthNode=fi(e),t.referenceNode=this.getSelf(),fi(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 xu=xi(bu),Tu=(...e)=>xu(...e).setSampler(!1),_u=tn("float").label("cameraNear").setGroup(Zi).onRenderUpdate((({camera:e})=>e.near)),vu=tn("float").label("cameraFar").setGroup(Zi).onRenderUpdate((({camera:e})=>e.far)),Nu=tn("mat4").label("cameraProjectionMatrix").setGroup(Zi).onRenderUpdate((({camera:e})=>e.projectionMatrix)),Su=tn("mat4").label("cameraProjectionMatrixInverse").setGroup(Zi).onRenderUpdate((({camera:e})=>e.projectionMatrixInverse)),Au=tn("mat4").label("cameraViewMatrix").setGroup(Zi).onRenderUpdate((({camera:e})=>e.matrixWorldInverse)),Ru=tn("mat4").label("cameraWorldMatrix").setGroup(Zi).onRenderUpdate((({camera:e})=>e.matrixWorld)),Cu=tn("mat3").label("cameraNormalMatrix").setGroup(Zi).onRenderUpdate((({camera:e})=>e.normalMatrix)),Eu=tn(new r).label("cameraPosition").setGroup(Zi).onRenderUpdate((({camera:e},t)=>t.value.setFromMatrixPosition(e.matrixWorld)));class wu extends Ms{static get type(){return"Object3DNode"}constructor(e,t=null){super(),this.scope=e,this.object3d=t,this.updateType=vs.OBJECT,this._uniformNode=new en(null)}getNodeType(){const e=this.scope;return e===wu.WORLD_MATRIX?"mat4":e===wu.POSITION||e===wu.VIEW_POSITION||e===wu.DIRECTION||e===wu.SCALE?"vec3":void 0}update(e){const t=this.object3d,s=this._uniformNode,i=this.scope;if(i===wu.WORLD_MATRIX)s.value=t.matrixWorld;else if(i===wu.POSITION)s.value=s.value||new r,s.value.setFromMatrixPosition(t.matrixWorld);else if(i===wu.SCALE)s.value=s.value||new r,s.value.setFromMatrixScale(t.matrixWorld);else if(i===wu.DIRECTION)s.value=s.value||new r,t.getWorldDirection(s.value);else if(i===wu.VIEW_POSITION){const i=e.camera;s.value=s.value||new r,s.value.setFromMatrixPosition(t.matrixWorld),s.value.applyMatrix4(i.matrixWorldInverse)}}generate(e){const t=this.scope;return t===wu.WORLD_MATRIX?this._uniformNode.nodeType="mat4":t!==wu.POSITION&&t!==wu.VIEW_POSITION&&t!==wu.DIRECTION&&t!==wu.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}}wu.WORLD_MATRIX="worldMatrix",wu.POSITION="position",wu.SCALE="scale",wu.VIEW_POSITION="viewPosition",wu.DIRECTION="direction";const Mu=xi(wu,wu.DIRECTION),Bu=xi(wu,wu.WORLD_MATRIX),Uu=xi(wu,wu.POSITION),Fu=xi(wu,wu.SCALE),Pu=xi(wu,wu.VIEW_POSITION);class Iu extends wu{static get type(){return"ModelNode"}constructor(e){super(e)}update(e){this.object3d=e.object,super.update(e)}}const Lu=Ti(Iu,Iu.DIRECTION),Du=Ti(Iu,Iu.WORLD_MATRIX),Vu=Ti(Iu,Iu.POSITION),Ou=Ti(Iu,Iu.SCALE),Gu=Ti(Iu,Iu.VIEW_POSITION),ku=tn(new i).onObjectUpdate((({object:e},t)=>t.value.getNormalMatrix(e.matrixWorld))),zu=tn(new n).onObjectUpdate((({object:e},t)=>t.value.copy(e.matrixWorld).invert())),$u=Au.mul(Du).toVar("modelViewMatrix"),Hu=_i((e=>(e.context.isHighPrecisionModelViewMatrix=!0,tn("mat4").onObjectUpdate((({object:e,camera:t})=>e.modelViewMatrix.multiplyMatrices(t.matrixWorldInverse,e.matrixWorld)))))).once()().toVar("highPrecisionModelViewMatrix"),Wu=_i((e=>{const t=e.context.isHighPrecisionModelViewMatrix;return tn("mat3").onObjectUpdate((({object:e,camera:r})=>(!0!==t&&e.modelViewMatrix.multiplyMatrices(r.matrixWorldInverse,e.matrixWorld),e.normalMatrix.getNormalMatrix(e.modelViewMatrix))))})).once()().toVar("highPrecisionModelNormalMatrix"),ju=hu("position","vec3"),qu=ju.varying("positionLocal"),Ku=ju.varying("positionPrevious"),Xu=Du.mul(qu).xyz.varying("v_positionWorld"),Yu=qu.transformDirection(Du).varying("v_positionWorldDirection").normalize().toVar("positionWorldDirection"),Qu=$u.mul(qu).xyz.varying("v_positionView"),Zu=Qu.negate().varying("v_positionViewDirection").normalize().toVar("positionViewDirection");class Ju extends Ms{static get type(){return"FrontFacingNode"}constructor(){super("bool"),this.isFrontFacingNode=!0}generate(e){const{renderer:t,material:r}=e;return t.coordinateSystem===b&&r.side===x?"false":e.getFrontFacing()}}const el=Ti(Ju),tl=Ci(el).mul(2).sub(1),rl=hu("normal","vec3"),sl=_i((e=>!1===e.geometry.hasAttribute("normal")?(console.warn('TSL.NormalNode: Vertex attribute "normal" not found on geometry.'),Ii(0,1,0)):rl),"vec3").once()().toVar("normalLocal"),il=Qu.dFdx().cross(Qu.dFdy()).normalize().toVar("normalFlat"),nl=_i((e=>{let t;return t=!0===e.material.flatShading?il:wa(cl(sl),"v_normalView").normalize(),t}),"vec3").once()().toVar("normalView"),ol=wa(nl.transformDirection(Au),"v_normalWorld").normalize().toVar("normalWorld"),al=_i((e=>e.context.setupNormal()),"vec3").once()().mul(tl).toVar("transformedNormalView"),ul=al.transformDirection(Au).toVar("transformedNormalWorld"),ll=_i((e=>e.context.setupClearcoatNormal()),"vec3").once()().mul(tl).toVar("transformedClearcoatNormalView"),dl=_i((([e,t=Du])=>{const r=Hi(t),s=e.div(Ii(r[0].dot(r[0]),r[1].dot(r[1]),r[2].dot(r[2])));return r.mul(s).xyz})),cl=_i((([e],t)=>{const r=t.renderer.nodes.modelNormalViewMatrix;if(null!==r)return r.transformDirection(e);const s=ku.mul(e);return Au.transformDirection(s)})),hl=tn(0).onReference((({material:e})=>e)).onRenderUpdate((({material:e})=>e.refractionRatio)),pl=Zu.negate().reflect(al),gl=Zu.negate().refract(al,hl),ml=pl.transformDirection(Au).toVar("reflectVector"),fl=gl.transformDirection(Au).toVar("reflectVector");class yl extends bu{static get type(){return"CubeTextureNode"}constructor(e,t=null,r=null,s=null){super(e,t,r,s),this.isCubeTextureNode=!0}getInputType(){return"cubeTexture"}getDefaultUV(){const e=this.value;return e.mapping===T?ml:e.mapping===_?fl:(console.error('THREE.CubeTextureNode: Mapping "%s" not supported.',e.mapping),Ii(0,0,0))}setUpdateMatrix(){}setupUV(e,t){const r=this.value;return e.renderer.coordinateSystem!==v&&r.isRenderTargetTexture?t:Ii(t.x.negate(),t.yz)}generateUV(e,t){return t.build(e,"vec3")}}const bl=xi(yl);class xl extends en{static get type(){return"BufferNode"}constructor(e,t,r=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferCount=r}getElementType(e){return this.getNodeType(e)}getInputType(){return"buffer"}}const Tl=(e,t,r)=>fi(new xl(e,t,r));class _l extends Bs{static get type(){return"UniformArrayElementNode"}constructor(e,t){super(e,t),this.isArrayBufferElementNode=!0}generate(e){const t=super.generate(e),r=this.getNodeType(),s=this.node.getPaddedType();return e.format(t,s,r)}}class vl extends xl{static get type(){return"UniformArrayNode"}constructor(e,t=null){super(null),this.array=e,this.elementType=null===t?fs(e[0]):t,this.paddedType=this.getPaddedType(),this.updateType=vs.RENDER,this.isArrayBufferNode=!0}getNodeType(){return this.paddedType}getElementType(){return this.elementType}getPaddedType(){const e=this.elementType;let t="vec4";return"mat2"===e?t="mat2":!0===/mat/.test(e)?t="mat4":"i"===e.charAt(0)?t="ivec4":"u"===e.charAt(0)&&(t="uvec4"),t}update(){const{array:e,value:t}=this,r=this.elementType;if("float"===r||"int"===r||"uint"===r)for(let r=0;rfi(new vl(e,t));class Sl extends Bs{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),r=this.referenceNode.getNodeType(),s=this.getNodeType();return e.format(t,r,s)}}class Al extends Ms{static get type(){return"ReferenceNode"}constructor(e,t,r=null,s=null){super(),this.property=e,this.uniformType=t,this.object=r,this.count=s,this.properties=e.split("."),this.reference=r,this.node=null,this.group=null,this.name=null,this.updateType=vs.OBJECT}element(e){return fi(new Sl(this,fi(e)))}setGroup(e){return this.group=e,this}label(e){return this.name=e,this}setNodeType(e){let t=null;t=null!==this.count?Tl(null,e,this.count):Array.isArray(this.getValueFromReference())?Nl(null,e):"texture"===e?xu(null):"cubeTexture"===e?bl(null):tn(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 r=e[t[0]];for(let e=1;efi(new Al(e,t,r)),Cl=(e,t,r,s)=>fi(new Al(e,t,s,r));class El extends Al{static get type(){return"MaterialReferenceNode"}constructor(e,t,r=null){super(e,t,r),this.material=r,this.isMaterialReferenceNode=!0}updateReference(e){return this.reference=null!==this.material?this.material:e.material,this.reference}}const wl=(e,t,r)=>fi(new El(e,t,r)),Ml=_i((e=>(!1===e.geometry.hasAttribute("tangent")&&e.geometry.computeTangents(),hu("tangent","vec4"))))(),Bl=Ml.xyz.toVar("tangentLocal"),Ul=$u.mul(Oi(Bl,0)).xyz.varying("v_tangentView").normalize().toVar("tangentView"),Fl=Ul.transformDirection(Au).varying("v_tangentWorld").normalize().toVar("tangentWorld"),Pl=Ul.toVar("transformedTangentView"),Il=Pl.transformDirection(Au).normalize().toVar("transformedTangentWorld"),Ll=e=>e.mul(Ml.w).xyz,Dl=wa(Ll(rl.cross(Ml)),"v_bitangentGeometry").normalize().toVar("bitangentGeometry"),Vl=wa(Ll(sl.cross(Bl)),"v_bitangentLocal").normalize().toVar("bitangentLocal"),Ol=wa(Ll(nl.cross(Ul)),"v_bitangentView").normalize().toVar("bitangentView"),Gl=wa(Ll(ol.cross(Fl)),"v_bitangentWorld").normalize().toVar("bitangentWorld"),kl=Ll(al.cross(Pl)).normalize().toVar("transformedBitangentView"),zl=kl.transformDirection(Au).normalize().toVar("transformedBitangentWorld"),$l=Hi(Ul,Ol,nl),Hl=Zu.mul($l),Wl=(()=>{let e=Tn.cross(Zu);return e=e.cross(Tn).normalize(),e=da(e,al,bn.mul(un.oneMinus()).oneMinus().pow2().pow2()).normalize(),e})(),jl=_i((e=>{const{eye_pos:t,surf_norm:r,mapN:s,uv:i}=e,n=t.dFdx(),o=t.dFdy(),a=i.dFdx(),u=i.dFdy(),l=r,d=o.cross(l),c=l.cross(n),h=d.mul(a.x).add(c.mul(u.x)),p=d.mul(a.y).add(c.mul(u.y)),g=h.dot(h).max(p.dot(p)),m=tl.mul(g.inverseSqrt());return On(h.mul(s.x,m),p.mul(s.y,m),l.mul(s.z)).normalize()}));class ql extends Fs{static get type(){return"NormalMapNode"}constructor(e,t=null){super("vec3"),this.node=e,this.scaleNode=t,this.normalMapType=N}setup(e){const{normalMapType:t,scaleNode:r}=this;let s=this.node.mul(2).sub(1);null!==r&&(s=Ii(s.xy.mul(r),s.z));let i=null;if(t===S)i=cl(s);else if(t===N){i=!0===e.hasGeometryAttribute("tangent")?$l.mul(s).normalize():jl({eye_pos:Qu,surf_norm:nl,mapN:s,uv:pu()})}return i}}const Kl=xi(ql),Xl=_i((({textureNode:e,bumpScale:t})=>{const r=t=>e.cache().context({getUV:e=>t(e.uvNode||pu()),forceUVContext:!0}),s=Ci(r((e=>e)));return Bi(Ci(r((e=>e.add(e.dFdx())))).sub(s),Ci(r((e=>e.add(e.dFdy())))).sub(s)).mul(t)})),Yl=_i((e=>{const{surf_pos:t,surf_norm:r,dHdxy:s}=e,i=t.dFdx().normalize(),n=r,o=t.dFdy().normalize().cross(n),a=n.cross(i),u=i.dot(o).mul(tl),l=u.sign().mul(s.x.mul(o).add(s.y.mul(a)));return u.abs().mul(r).sub(l).normalize()}));class Ql extends Fs{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=Xl({textureNode:this.textureNode,bumpScale:e});return Yl({surf_pos:Qu,surf_norm:nl,dHdxy:t})}}const Zl=xi(Ql),Jl=new Map;class ed extends Ms{static get type(){return"MaterialNode"}constructor(e){super(),this.scope=e}getCache(e,t){let r=Jl.get(e);return void 0===r&&(r=wl(e,t),Jl.set(e,r)),r}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,r=this.scope;let s=null;if(r===ed.COLOR){const e=void 0!==t.color?this.getColor(r):Ii();s=t.map&&!0===t.map.isTexture?e.mul(this.getTexture("map")):e}else if(r===ed.OPACITY){const e=this.getFloat(r);s=t.alphaMap&&!0===t.alphaMap.isTexture?e.mul(this.getTexture("alpha")):e}else if(r===ed.SPECULAR_STRENGTH)s=t.specularMap&&!0===t.specularMap.isTexture?this.getTexture("specular").r:Ci(1);else if(r===ed.SPECULAR_INTENSITY){const e=this.getFloat(r);s=t.specularMap?e.mul(this.getTexture(r).a):e}else if(r===ed.SPECULAR_COLOR){const e=this.getColor(r);s=t.specularColorMap&&!0===t.specularColorMap.isTexture?e.mul(this.getTexture(r).rgb):e}else if(r===ed.ROUGHNESS){const e=this.getFloat(r);s=t.roughnessMap&&!0===t.roughnessMap.isTexture?e.mul(this.getTexture(r).g):e}else if(r===ed.METALNESS){const e=this.getFloat(r);s=t.metalnessMap&&!0===t.metalnessMap.isTexture?e.mul(this.getTexture(r).b):e}else if(r===ed.EMISSIVE){const e=this.getFloat("emissiveIntensity"),i=this.getColor(r).mul(e);s=t.emissiveMap&&!0===t.emissiveMap.isTexture?i.mul(this.getTexture(r)):i}else if(r===ed.NORMAL)t.normalMap?(s=Kl(this.getTexture("normal"),this.getCache("normalScale","vec2")),s.normalMapType=t.normalMapType):s=t.bumpMap?Zl(this.getTexture("bump").r,this.getFloat("bumpScale")):nl;else if(r===ed.CLEARCOAT){const e=this.getFloat(r);s=t.clearcoatMap&&!0===t.clearcoatMap.isTexture?e.mul(this.getTexture(r).r):e}else if(r===ed.CLEARCOAT_ROUGHNESS){const e=this.getFloat(r);s=t.clearcoatRoughnessMap&&!0===t.clearcoatRoughnessMap.isTexture?e.mul(this.getTexture(r).r):e}else if(r===ed.CLEARCOAT_NORMAL)s=t.clearcoatNormalMap?Kl(this.getTexture(r),this.getCache(r+"Scale","vec2")):nl;else if(r===ed.SHEEN){const e=this.getColor("sheenColor").mul(this.getFloat("sheen"));s=t.sheenColorMap&&!0===t.sheenColorMap.isTexture?e.mul(this.getTexture("sheenColor").rgb):e}else if(r===ed.SHEEN_ROUGHNESS){const e=this.getFloat(r);s=t.sheenRoughnessMap&&!0===t.sheenRoughnessMap.isTexture?e.mul(this.getTexture(r).a):e,s=s.clamp(.07,1)}else if(r===ed.ANISOTROPY)if(t.anisotropyMap&&!0===t.anisotropyMap.isTexture){const e=this.getTexture(r);s=$i(Vd.x,Vd.y,Vd.y.negate(),Vd.x).mul(e.rg.mul(2).sub(Bi(1)).normalize().mul(e.b))}else s=Vd;else if(r===ed.IRIDESCENCE_THICKNESS){const e=Rl("1","float",t.iridescenceThicknessRange);if(t.iridescenceThicknessMap){const i=Rl("0","float",t.iridescenceThicknessRange);s=e.sub(i).mul(this.getTexture(r).g).add(i)}else s=e}else if(r===ed.TRANSMISSION){const e=this.getFloat(r);s=t.transmissionMap?e.mul(this.getTexture(r).r):e}else if(r===ed.THICKNESS){const e=this.getFloat(r);s=t.thicknessMap?e.mul(this.getTexture(r).g):e}else if(r===ed.IOR)s=this.getFloat(r);else if(r===ed.LIGHT_MAP)s=this.getTexture(r).rgb.mul(this.getFloat("lightMapIntensity"));else if(r===ed.AO_MAP)s=this.getTexture(r).r.sub(1).mul(this.getFloat("aoMapIntensity")).add(1);else{const t=this.getNodeType(e);s=this.getCache(r,t)}return s}}ed.ALPHA_TEST="alphaTest",ed.COLOR="color",ed.OPACITY="opacity",ed.SHININESS="shininess",ed.SPECULAR="specular",ed.SPECULAR_STRENGTH="specularStrength",ed.SPECULAR_INTENSITY="specularIntensity",ed.SPECULAR_COLOR="specularColor",ed.REFLECTIVITY="reflectivity",ed.ROUGHNESS="roughness",ed.METALNESS="metalness",ed.NORMAL="normal",ed.CLEARCOAT="clearcoat",ed.CLEARCOAT_ROUGHNESS="clearcoatRoughness",ed.CLEARCOAT_NORMAL="clearcoatNormal",ed.EMISSIVE="emissive",ed.ROTATION="rotation",ed.SHEEN="sheen",ed.SHEEN_ROUGHNESS="sheenRoughness",ed.ANISOTROPY="anisotropy",ed.IRIDESCENCE="iridescence",ed.IRIDESCENCE_IOR="iridescenceIOR",ed.IRIDESCENCE_THICKNESS="iridescenceThickness",ed.IOR="ior",ed.TRANSMISSION="transmission",ed.THICKNESS="thickness",ed.ATTENUATION_DISTANCE="attenuationDistance",ed.ATTENUATION_COLOR="attenuationColor",ed.LINE_SCALE="scale",ed.LINE_DASH_SIZE="dashSize",ed.LINE_GAP_SIZE="gapSize",ed.LINE_WIDTH="linewidth",ed.LINE_DASH_OFFSET="dashOffset",ed.POINT_WIDTH="pointWidth",ed.DISPERSION="dispersion",ed.LIGHT_MAP="light",ed.AO_MAP="ao";const td=Ti(ed,ed.ALPHA_TEST),rd=Ti(ed,ed.COLOR),sd=Ti(ed,ed.SHININESS),id=Ti(ed,ed.EMISSIVE),nd=Ti(ed,ed.OPACITY),od=Ti(ed,ed.SPECULAR),ad=Ti(ed,ed.SPECULAR_INTENSITY),ud=Ti(ed,ed.SPECULAR_COLOR),ld=Ti(ed,ed.SPECULAR_STRENGTH),dd=Ti(ed,ed.REFLECTIVITY),cd=Ti(ed,ed.ROUGHNESS),hd=Ti(ed,ed.METALNESS),pd=Ti(ed,ed.NORMAL).context({getUV:null}),gd=Ti(ed,ed.CLEARCOAT),md=Ti(ed,ed.CLEARCOAT_ROUGHNESS),fd=Ti(ed,ed.CLEARCOAT_NORMAL).context({getUV:null}),yd=Ti(ed,ed.ROTATION),bd=Ti(ed,ed.SHEEN),xd=Ti(ed,ed.SHEEN_ROUGHNESS),Td=Ti(ed,ed.ANISOTROPY),_d=Ti(ed,ed.IRIDESCENCE),vd=Ti(ed,ed.IRIDESCENCE_IOR),Nd=Ti(ed,ed.IRIDESCENCE_THICKNESS),Sd=Ti(ed,ed.TRANSMISSION),Ad=Ti(ed,ed.THICKNESS),Rd=Ti(ed,ed.IOR),Cd=Ti(ed,ed.ATTENUATION_DISTANCE),Ed=Ti(ed,ed.ATTENUATION_COLOR),wd=Ti(ed,ed.LINE_SCALE),Md=Ti(ed,ed.LINE_DASH_SIZE),Bd=Ti(ed,ed.LINE_GAP_SIZE),Ud=Ti(ed,ed.LINE_WIDTH),Fd=Ti(ed,ed.LINE_DASH_OFFSET),Pd=Ti(ed,ed.POINT_WIDTH),Id=Ti(ed,ed.DISPERSION),Ld=Ti(ed,ed.LIGHT_MAP),Dd=Ti(ed,ed.AO_MAP),Vd=tn(new t).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 Od extends Fs{static get type(){return"ModelViewProjectionNode"}constructor(e=null){super("vec4"),this.positionNode=e}setup(e){if("fragment"===e.shaderStage)return wa(e.context.mvp);const t=this.positionNode||qu,r=e.renderer.nodes.modelViewMatrix||$u;return Nu.mul(r).mul(t)}}const Gd=xi(Od);class kd extends Ms{static get type(){return"IndexNode"}constructor(e){super("uint"),this.scope=e,this.isIndexNode=!0}generate(e){const t=this.getNodeType(e),r=this.scope;let s,i;if(r===kd.VERTEX)s=e.getVertexIndex();else if(r===kd.INSTANCE)s=e.getInstanceIndex();else if(r===kd.DRAW)s=e.getDrawIndex();else if(r===kd.INVOCATION_LOCAL)s=e.getInvocationLocalIndex();else if(r===kd.INVOCATION_SUBGROUP)s=e.getInvocationSubgroupIndex();else{if(r!==kd.SUBGROUP)throw new Error("THREE.IndexNode: Unknown scope: "+r);s=e.getSubgroupIndex()}if("vertex"===e.shaderStage||"compute"===e.shaderStage)i=s;else{i=wa(this).build(e,t)}return i}}kd.VERTEX="vertex",kd.INSTANCE="instance",kd.SUBGROUP="subgroup",kd.INVOCATION_LOCAL="invocationLocal",kd.INVOCATION_SUBGROUP="invocationSubgroup",kd.DRAW="draw";const zd=Ti(kd,kd.VERTEX),$d=Ti(kd,kd.INSTANCE),Hd=Ti(kd,kd.SUBGROUP),Wd=Ti(kd,kd.INVOCATION_SUBGROUP),jd=Ti(kd,kd.INVOCATION_LOCAL),qd=Ti(kd,kd.DRAW);class Kd extends Ms{static get type(){return"InstanceNode"}constructor(e,t,r){super("void"),this.count=e,this.instanceMatrix=t,this.instanceColor=r,this.instanceMatrixNode=null,this.instanceColorNode=null,this.updateType=vs.FRAME,this.buffer=null,this.bufferColor=null}setup(e){const{count:t,instanceMatrix:r,instanceColor:s}=this;let{instanceMatrixNode:i,instanceColorNode:n}=this;if(null===i){if(t<=1e3)i=Tl(r.array,"mat4",Math.max(t,1)).element($d);else{const e=new A(r.array,16,1);this.buffer=e;const t=r.usage===p?Ya:Xa,s=[t(e,"vec4",16,0),t(e,"vec4",16,4),t(e,"vec4",16,8),t(e,"vec4",16,12)];i=Wi(...s)}this.instanceMatrixNode=i}if(s&&null===n){const e=new R(s.array,3),t=s.usage===p?Ya:Xa;this.bufferColor=e,n=Ii(t(e,"vec3",3,0)),this.instanceColorNode=n}const o=i.mul(qu).xyz;if(qu.assign(o),e.hasGeometryAttribute("normal")){const e=dl(sl,i);sl.assign(e)}null!==this.instanceColorNode&&nn("vec3","vInstanceColor").assign(this.instanceColorNode)}update(){this.instanceMatrix.usage!==p&&null!==this.buffer&&this.instanceMatrix.version!==this.buffer.version&&(this.buffer.version=this.instanceMatrix.version),this.instanceColor&&this.instanceColor.usage!==p&&null!==this.bufferColor&&this.instanceColor.version!==this.bufferColor.version&&(this.bufferColor.version=this.instanceColor.version)}}const Xd=xi(Kd);class Yd extends Kd{static get type(){return"InstancedMeshNode"}constructor(e){const{count:t,instanceMatrix:r,instanceColor:s}=e;super(t,r,s),this.instanceMesh=e}}const Qd=xi(Yd);class Zd extends Ms{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=$d:this.batchingIdNode=qd);const t=_i((([e])=>{const t=mu(Tu(this.batchMesh._indirectTexture),0),r=Ei(e).modInt(Ei(t)),s=Ei(e).div(Ei(t));return Tu(this.batchMesh._indirectTexture,Ui(r,s)).x})).setLayout({name:"getIndirectIndex",type:"uint",inputs:[{name:"id",type:"int"}]}),r=t(Ei(this.batchingIdNode)),s=this.batchMesh._matricesTexture,i=mu(Tu(s),0),n=Ci(r).mul(4).toInt().toVar(),o=n.modInt(i),a=n.div(Ei(i)),u=Wi(Tu(s,Ui(o,a)),Tu(s,Ui(o.add(1),a)),Tu(s,Ui(o.add(2),a)),Tu(s,Ui(o.add(3),a))),l=this.batchMesh._colorsTexture;if(null!==l){const e=_i((([e])=>{const t=mu(Tu(l),0).x,r=e,s=r.modInt(t),i=r.div(t);return Tu(l,Ui(s,i)).rgb})).setLayout({name:"getBatchingColor",type:"vec3",inputs:[{name:"id",type:"int"}]}),t=e(r);nn("vec3","vBatchColor").assign(t)}const d=Hi(u);qu.assign(u.mul(qu));const c=sl.div(Ii(d[0].dot(d[0]),d[1].dot(d[1]),d[2].dot(d[2]))),h=d.mul(c).xyz;sl.assign(h),e.hasGeometryAttribute("tangent")&&Bl.mulAssign(d)}}const Jd=xi(Zd),ec=new WeakMap;class tc extends Ms{static get type(){return"SkinningNode"}constructor(e,t=!1){let r,s,i;super("void"),this.skinnedMesh=e,this.useReference=t,this.updateType=vs.OBJECT,this.skinIndexNode=hu("skinIndex","uvec4"),this.skinWeightNode=hu("skinWeight","vec4"),t?(r=Rl("bindMatrix","mat4"),s=Rl("bindMatrixInverse","mat4"),i=Cl("skeleton.boneMatrices","mat4",e.skeleton.bones.length)):(r=tn(e.bindMatrix,"mat4"),s=tn(e.bindMatrixInverse,"mat4"),i=Tl(e.skeleton.boneMatrices,"mat4",e.skeleton.bones.length)),this.bindMatrixNode=r,this.bindMatrixInverseNode=s,this.boneMatricesNode=i,this.previousBoneMatricesNode=null}getSkinnedPosition(e=this.boneMatricesNode,t=qu){const{skinIndexNode:r,skinWeightNode:s,bindMatrixNode:i,bindMatrixInverseNode:n}=this,o=e.element(r.x),a=e.element(r.y),u=e.element(r.z),l=e.element(r.w),d=i.mul(t),c=On(o.mul(s.x).mul(d),a.mul(s.y).mul(d),u.mul(s.z).mul(d),l.mul(s.w).mul(d));return n.mul(c).xyz}getSkinnedNormal(e=this.boneMatricesNode,t=sl){const{skinIndexNode:r,skinWeightNode:s,bindMatrixNode:i,bindMatrixInverseNode:n}=this,o=e.element(r.x),a=e.element(r.y),u=e.element(r.z),l=e.element(r.w);let d=On(s.x.mul(o),s.y.mul(a),s.z.mul(u),s.w.mul(l));return d=n.mul(d).mul(i),d.transformDirection(t).xyz}getPreviousSkinnedPosition(e){const t=e.object;return null===this.previousBoneMatricesNode&&(t.skeleton.previousBoneMatrices=new Float32Array(t.skeleton.boneMatrices),this.previousBoneMatricesNode=Cl("skeleton.previousBoneMatrices","mat4",t.skeleton.bones.length)),this.getSkinnedPosition(this.previousBoneMatricesNode,Ku)}needsPreviousBoneMatrices(e){const t=e.renderer.getMRT();return t&&t.has("velocity")}setup(e){this.needsPreviousBoneMatrices(e)&&Ku.assign(this.getPreviousSkinnedPosition(e));const t=this.getSkinnedPosition();if(qu.assign(t),e.hasGeometryAttribute("normal")){const t=this.getSkinnedNormal();sl.assign(t),e.hasGeometryAttribute("tangent")&&Bl.assign(t)}}generate(e,t){if("void"!==t)return qu.build(e,t)}update(e){const t=(this.useReference?e.object:this.skinnedMesh).skeleton;ec.get(t)!==e.frameId&&(ec.set(t,e.frameId),null!==this.previousBoneMatricesNode&&t.previousBoneMatrices.set(t.boneMatrices),t.update())}}const rc=e=>fi(new tc(e,!0));class sc extends Ms{static get type(){return"LoopNode"}constructor(e=[]){super(),this.params=e}getVarName(e){return String.fromCharCode("i".charCodeAt(0)+e)}getProperties(e){const t=e.getNodeProperties(this);if(void 0!==t.stackNode)return t;const r={};for(let e=0,t=this.params.length-1;eNumber(n)?">=":"<"));const d={start:i,end:n,condition:u},c=d.start,h=d.end;let p="",g="",m="";l||(l="int"===a||"uint"===a?u.includes("<")?"++":"--":u.includes("<")?"+= 1.":"-= 1."),p+=e.getVar(a,o)+" = "+c,g+=o+" "+u+" "+h,m+=o+" "+l;const f=`for ( ${p}; ${g}; ${m} )`;e.addFlowCode((0===t?"\n":"")+e.tab+f+" {\n\n").addFlowTab()}const i=s.build(e,"void"),n=t.returnsNode?t.returnsNode.build(e):"";e.removeFlowTab().addFlowCode("\n"+e.tab+i);for(let t=0,r=this.params.length-1;tfi(new sc(bi(e,"int"))).append(),nc=()=>au("break").append(),oc=new WeakMap,ac=new s,uc=_i((({bufferMap:e,influence:t,stride:r,width:s,depth:i,offset:n})=>{const o=Ei(zd).mul(r).add(n),a=o.div(s),u=o.sub(a.mul(s));return Tu(e,Ui(u,a)).depth(i).mul(t)}));class lc extends Ms{static get type(){return"MorphNode"}constructor(e){super("void"),this.mesh=e,this.morphBaseInfluence=tn(1),this.updateType=vs.OBJECT}setup(e){const{geometry:r}=e,s=void 0!==r.morphAttributes.position,i=r.hasAttribute("normal")&&void 0!==r.morphAttributes.normal,n=r.morphAttributes.position||r.morphAttributes.normal||r.morphAttributes.color,o=void 0!==n?n.length:0,{texture:a,stride:u,size:l}=function(e){const r=void 0!==e.morphAttributes.position,s=void 0!==e.morphAttributes.normal,i=void 0!==e.morphAttributes.color,n=e.morphAttributes.position||e.morphAttributes.normal||e.morphAttributes.color,o=void 0!==n?n.length:0;let a=oc.get(e);if(void 0===a||a.count!==o){void 0!==a&&a.texture.dispose();const u=e.morphAttributes.position||[],l=e.morphAttributes.normal||[],d=e.morphAttributes.color||[];let c=0;!0===r&&(c=1),!0===s&&(c=2),!0===i&&(c=3);let h=e.attributes.position.count*c,p=1;const g=4096;h>g&&(p=Math.ceil(h/g),h=g);const m=new Float32Array(h*p*4*o),f=new C(m,h,p,o);f.type=E,f.needsUpdate=!0;const y=4*c;for(let x=0;x{const t=Ci(0).toVar();this.mesh.count>1&&null!==this.mesh.morphTexture&&void 0!==this.mesh.morphTexture?t.assign(Tu(this.mesh.morphTexture,Ui(Ei(e).add(1),Ei($d))).r):t.assign(Rl("morphTargetInfluences","float").element(e).toVar()),!0===s&&qu.addAssign(uc({bufferMap:a,influence:t,stride:u,width:d,depth:e,offset:Ei(0)})),!0===i&&sl.addAssign(uc({bufferMap:a,influence:t,stride:u,width:d,depth:e,offset:Ei(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 dc=xi(lc);class cc extends Ms{static get type(){return"LightingNode"}constructor(){super("vec3"),this.isLightingNode=!0}}class hc extends cc{static get type(){return"AONode"}constructor(e=null){super(),this.aoNode=e}setup(e){e.context.ambientOcclusion.mulAssign(this.aoNode)}}class pc extends va{static get type(){return"LightingContextNode"}constructor(e,t=null,r=null,s=null){super(e),this.lightingModel=t,this.backdropNode=r,this.backdropAlphaNode=s,this._value=null}getContext(){const{backdropNode:e,backdropAlphaNode:t}=this,r={directDiffuse:Ii().toVar("directDiffuse"),directSpecular:Ii().toVar("directSpecular"),indirectDiffuse:Ii().toVar("indirectDiffuse"),indirectSpecular:Ii().toVar("indirectSpecular")};return{radiance:Ii().toVar("radiance"),irradiance:Ii().toVar("irradiance"),iblIrradiance:Ii().toVar("iblIrradiance"),ambientOcclusion:Ci(1).toVar("ambientOcclusion"),reflectedLight:r,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 gc=xi(pc);class mc extends cc{static get type(){return"IrradianceNode"}constructor(e){super(),this.node=e}setup(e){e.context.irradiance.addAssign(this.node)}}let fc,yc;class bc extends Ms{static get type(){return"ScreenNode"}constructor(e){super(),this.scope=e,this.isViewportNode=!0}getNodeType(){return this.scope===bc.VIEWPORT?"vec4":"vec2"}getUpdateType(){let e=vs.NONE;return this.scope!==bc.SIZE&&this.scope!==bc.VIEWPORT||(e=vs.RENDER),this.updateType=e,e}update({renderer:e}){const t=e.getRenderTarget();this.scope===bc.VIEWPORT?null!==t?yc.copy(t.viewport):(e.getViewport(yc),yc.multiplyScalar(e.getPixelRatio())):null!==t?(fc.width=t.width,fc.height=t.height):e.getDrawingBufferSize(fc)}setup(){const e=this.scope;let r=null;return r=e===bc.SIZE?tn(fc||(fc=new t)):e===bc.VIEWPORT?tn(yc||(yc=new s)):Bi(_c.div(Tc)),r}generate(e){if(this.scope===bc.COORDINATE){let t=e.getFragCoord();if(e.isFlipY()){const r=e.getNodeProperties(Tc).outputNode.build(e);t=`${e.getType("vec2")}( ${t}.x, ${r}.y - ${t}.y )`}return t}return super.generate(e)}}bc.COORDINATE="coordinate",bc.VIEWPORT="viewport",bc.SIZE="size",bc.UV="uv";const xc=Ti(bc,bc.UV),Tc=Ti(bc,bc.SIZE),_c=Ti(bc,bc.COORDINATE),vc=Ti(bc,bc.VIEWPORT),Nc=vc.zw,Sc=_c.sub(vc.xy),Ac=Sc.div(Nc),Rc=_i((()=>(console.warn('TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.'),Tc)),"vec2").once()(),Cc=_i((()=>(console.warn('TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.'),xc)),"vec2").once()(),Ec=_i((()=>(console.warn('TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.'),xc.flipY())),"vec2").once()(),wc=new t;class Mc extends bu{static get type(){return"ViewportTextureNode"}constructor(e=xc,t=null,r=null){null===r&&((r=new w).minFilter=M),super(r,e,t),this.generateMipmaps=!1,this.isOutputTextureNode=!0,this.updateBeforeType=vs.FRAME}updateBefore(e){const t=e.renderer;t.getDrawingBufferSize(wc);const r=this.value;r.image.width===wc.width&&r.image.height===wc.height||(r.image.width=wc.width,r.image.height=wc.height,r.needsUpdate=!0);const s=r.generateMipmaps;r.generateMipmaps=this.generateMipmaps,t.copyFramebufferToTexture(r),r.generateMipmaps=s}clone(){const e=new this.constructor(this.uvNode,this.levelNode,this.value);return e.generateMipmaps=this.generateMipmaps,e}}const Bc=xi(Mc),Uc=xi(Mc,null,null,{generateMipmaps:!0});let Fc=null;class Pc extends Mc{static get type(){return"ViewportDepthTextureNode"}constructor(e=xc,t=null){null===Fc&&(Fc=new B),super(e,t,Fc)}}const Ic=xi(Pc);class Lc extends Ms{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===Lc.DEPTH_BASE?e.getFragDepth():super.generate(e)}setup({camera:e}){const{scope:t}=this,r=this.valueNode;let s=null;if(t===Lc.DEPTH_BASE)null!==r&&(s=kc().assign(r));else if(t===Lc.DEPTH)s=e.isPerspectiveCamera?Vc(Qu.z,_u,vu):Dc(Qu.z,_u,vu);else if(t===Lc.LINEAR_DEPTH)if(null!==r)if(e.isPerspectiveCamera){const e=Oc(r,_u,vu);s=Dc(e,_u,vu)}else s=r;else s=Dc(Qu.z,_u,vu);return s}}Lc.DEPTH_BASE="depthBase",Lc.DEPTH="depth",Lc.LINEAR_DEPTH="linearDepth";const Dc=(e,t,r)=>e.add(t).div(t.sub(r)),Vc=(e,t,r)=>t.add(e).mul(r).div(r.sub(t).mul(e)),Oc=(e,t,r)=>t.mul(r).div(r.sub(t).mul(e).sub(r)),Gc=(e,t,r)=>{t=t.max(1e-6).toVar();const s=_o(e.negate().div(t)),i=_o(r.div(t));return s.div(i)},kc=xi(Lc,Lc.DEPTH_BASE),zc=Ti(Lc,Lc.DEPTH),$c=xi(Lc,Lc.LINEAR_DEPTH),Hc=$c(Ic());zc.assign=e=>kc(e);const Wc=xi(class extends Ms{constructor(e){super("float"),this.name=e,this.isBuiltinNode=!0}generate(){return this.name}});class jc extends Ms{static get type(){return"ClippingNode"}constructor(e=jc.DEFAULT){super(),this.scope=e}setup(e){super.setup(e);const t=e.clippingContext,{intersectionPlanes:r,unionPlanes:s}=t;return this.hardwareClipping=e.material.hardwareClipping,this.scope===jc.ALPHA_TO_COVERAGE?this.setupAlphaToCoverage(r,s):this.scope===jc.HARDWARE?this.setupHardwareClipping(s,e):this.setupDefault(r,s)}setupAlphaToCoverage(e,t){return _i((()=>{const r=Ci().toVar("distanceToPlane"),s=Ci().toVar("distanceToGradient"),i=Ci(1).toVar("clipOpacity"),n=t.length;if(!this.hardwareClipping&&n>0){const e=Nl(t);ic(n,(({i:t})=>{const n=e.element(t);r.assign(Qu.dot(n.xyz).negate().add(n.w)),s.assign(r.fwidth().div(2)),i.mulAssign(ga(s.negate(),s,r))}))}const o=e.length;if(o>0){const t=Nl(e),n=Ci(1).toVar("intersectionClipOpacity");ic(o,(({i:e})=>{const i=t.element(e);r.assign(Qu.dot(i.xyz).negate().add(i.w)),s.assign(r.fwidth().div(2)),n.mulAssign(ga(s.negate(),s,r).oneMinus())})),i.mulAssign(n.oneMinus())}on.a.mulAssign(i),on.a.equal(0).discard()}))()}setupDefault(e,t){return _i((()=>{const r=t.length;if(!this.hardwareClipping&&r>0){const e=Nl(t);ic(r,(({i:t})=>{const r=e.element(t);Qu.dot(r.xyz).greaterThan(r.w).discard()}))}const s=e.length;if(s>0){const t=Nl(e),r=Mi(!0).toVar("clipped");ic(s,(({i:e})=>{const s=t.element(e);r.assign(Qu.dot(s.xyz).greaterThan(s.w).and(r))})),r.discard()}}))()}setupHardwareClipping(e,t){const r=e.length;return t.enableHardwareClipping(r),_i((()=>{const s=Nl(e),i=Wc(t.getClipDistance());ic(r,(({i:e})=>{const t=s.element(e),r=Qu.dot(t.xyz).sub(t.w).negate();i.element(e).assign(r)}))}))()}}jc.ALPHA_TO_COVERAGE="alphaToCoverage",jc.DEFAULT="default",jc.HARDWARE="hardware";const qc=_i((([e])=>Co(kn(1e4,Eo(kn(17,e.x).add(kn(.1,e.y)))).mul(On(.1,Po(Eo(kn(13,e.y).add(e.x)))))))),Kc=_i((([e])=>qc(Bi(qc(e.xy),e.z)))),Xc=_i((([e])=>{const t=Xo(Lo(Oo(e.xyz)),Lo(Go(e.xyz))),r=Ci(1).div(Ci(.05).mul(t)).toVar("pixScale"),s=Bi(xo(So(_o(r))),xo(Ao(_o(r)))),i=Bi(Kc(So(s.x.mul(e.xyz))),Kc(So(s.y.mul(e.xyz)))),n=Co(_o(r)),o=On(kn(n.oneMinus(),i.x),kn(n,i.y)),a=Ko(n,n.oneMinus()),u=Ii(o.mul(o).div(kn(2,a).mul(Gn(1,a))),o.sub(kn(.5,a)).div(Gn(1,a)),Gn(1,Gn(1,o).mul(Gn(1,o)).div(kn(2,a).mul(Gn(1,a))))),l=o.lessThan(a.oneMinus()).select(o.lessThan(a).select(u.x,u.y),u.z);return ca(l,1e-6,1)})).setLayout({name:"getAlphaHashThreshold",type:"float",inputs:[{name:"position",type:"vec3"}]});class Yc extends U{static get type(){return"NodeMaterial"}get type(){return this.constructor.type}set type(e){}constructor(){super(),this.isNodeMaterial=!0,this.forceSinglePass=!1,this.fog=!0,this.lights=!1,this.hardwareClipping=!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.geometryNode=null,this.depthNode=null,this.shadowPositionNode=null,this.receivedShadowNode=null,this.castShadowNode=null,this.outputNode=null,this.mrtNode=null,this.fragmentNode=null,this.vertexNode=null}customProgramCacheKey(){return this.type+cs(this)}build(e){this.setup(e)}setupObserver(e){return new os(e)}setup(e){e.context.setupNormal=()=>this.setupNormal(e);const t=e.renderer,r=t.getRenderTarget();let s;e.addStack(),e.stack.outputNode=this.vertexNode||this.setupPosition(e),null!==this.geometryNode&&(e.stack.outputNode=e.stack.outputNode.bypass(this.geometryNode)),e.addFlow("vertex",e.removeStack()),e.addStack();const i=this.setupClipping(e);if(!0===this.depthWrite&&(null!==r?!0===r.depthBuffer&&this.setupDepth(e):!0===t.depth&&this.setupDepth(e)),null===this.fragmentNode){this.setupDiffuseColor(e),this.setupVariants(e);const n=this.setupLighting(e);null!==i&&e.stack.add(i);const o=Oi(n,on.a).max(0);if(s=this.setupOutput(e,o),Sn.assign(s),null!==this.outputNode&&(s=this.outputNode),null!==r){const e=t.getMRT(),r=this.mrtNode;null!==e?(s=e,null!==r&&(s=e.merge(r))):null!==r&&(s=r)}}else{let t=this.fragmentNode;!0!==t.isOutputStructNode&&(t=Oi(t)),s=this.setupOutput(e,t)}e.stack.outputNode=s,e.addFlow("fragment",e.removeStack()),e.monitor=this.setupObserver(e)}setupClipping(e){if(null===e.clippingContext)return null;const{unionPlanes:t,intersectionPlanes:r}=e.clippingContext;let s=null;if(t.length>0||r.length>0){const t=e.renderer.samples;this.alphaToCoverage&&t>1?s=fi(new jc(jc.ALPHA_TO_COVERAGE)):e.stack.add(fi(new jc))}return s}setupHardwareClipping(e){if(this.hardwareClipping=!1,null===e.clippingContext)return;const t=e.clippingContext.unionPlanes.length;t>0&&t<=8&&e.isAvailable("clipDistance")&&(e.stack.add(fi(new jc(jc.HARDWARE))),this.hardwareClipping=!0)}setupDepth(e){const{renderer:t,camera:r}=e;let s=this.depthNode;if(null===s){const e=t.getMRT();e&&e.has("depth")?s=e.get("depth"):!0===t.logarithmicDepthBuffer&&(s=r.isPerspectiveCamera?Gc(Qu.z,_u,vu):Dc(Qu.z,_u,vu))}null!==s&&zc.assign(s).append()}setupPosition(e){const{object:t}=e,r=t.geometry;if(e.addStack(),(r.morphAttributes.position||r.morphAttributes.normal||r.morphAttributes.color)&&dc(t).append(),!0===t.isSkinnedMesh&&rc(t).append(),this.displacementMap){const e=wl("displacementMap","texture"),t=wl("displacementScale","float"),r=wl("displacementBias","float");qu.addAssign(sl.normalize().mul(e.x.mul(t).add(r)))}t.isBatchedMesh&&Jd(t).append(),t.isInstancedMesh&&t.instanceMatrix&&!0===t.instanceMatrix.isInstancedBufferAttribute&&Qd(t).append(),null!==this.positionNode&&qu.assign(this.positionNode),this.setupHardwareClipping(e);const s=Gd();return e.context.vertex=e.removeStack(),e.context.mvp=s,s}setupDiffuseColor({object:e,geometry:t}){let r=this.colorNode?Oi(this.colorNode):rd;if(!0===this.vertexColors&&t.hasAttribute("color")&&(r=Oi(r.xyz.mul(hu("color","vec3")),r.a)),e.instanceColor){r=nn("vec3","vInstanceColor").mul(r)}if(e.isBatchedMesh&&e._colorsTexture){r=nn("vec3","vBatchColor").mul(r)}on.assign(r);const s=this.opacityNode?Ci(this.opacityNode):nd;if(on.a.assign(on.a.mul(s)),null!==this.alphaTestNode||this.alphaTest>0){const e=null!==this.alphaTestNode?Ci(this.alphaTestNode):td;on.a.lessThanEqual(e).discard()}!0===this.alphaHash&&on.a.lessThan(Xc(qu)).discard(),!1===this.transparent&&this.blending===F&&!1===this.alphaToCoverage&&on.a.assign(1)}setupVariants(){}setupOutgoingLight(){return!0===this.lights?Ii(0):on.rgb}setupNormal(){return this.normalNode?Ii(this.normalNode):pd}setupEnvironment(){let e=null;return this.envNode?e=this.envNode:this.envMap&&(e=this.envMap.isCubeTexture?wl("envMap","cubeTexture"):wl("envMap","texture")),e}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new mc(Ld)),t}setupLights(e){const t=[],r=this.setupEnvironment(e);r&&r.isLightingNode&&t.push(r);const s=this.setupLightMap(e);if(s&&s.isLightingNode&&t.push(s),null!==this.aoNode||e.material.aoMap){const e=null!==this.aoNode?this.aoNode:Dd;t.push(new hc(e))}let i=this.lightsNode||e.lightsNode;return t.length>0&&(i=e.renderer.lighting.createNode([...i.getLights(),...t])),i}setupLightingModel(){}setupLighting(e){const{material:t}=e,{backdropNode:r,backdropAlphaNode:s,emissiveNode:i}=this,n=!0===this.lights||null!==this.lightsNode?this.setupLights(e):null;let o=this.setupOutgoingLight(e);if(n&&n.getScope().hasLights){const t=this.setupLightingModel(e);o=gc(n,t,r,s)}else null!==r&&(o=Ii(null!==s?da(o,r,s):r));return(i&&!0===i.isNode||t.emissive&&!0===t.emissive.isColor)&&(an.assign(Ii(i||id)),o=o.add(an)),o}setupOutput(e,t){if(!0===this.fog){const r=e.fogNode;r&&(t=Oi(r.mix(t.rgb,r.colorNode),t.a))}return t}setDefaultValues(e){for(const t in e){const r=e[t];void 0===this[t]&&(this[t]=r,r&&r.clone&&(this[t]=r.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 r=U.prototype.toJSON.call(this,e),s=hs(this);r.inputNodes={};for(const{property:t,childNode:i}of s)r.inputNodes[t]=i.toJSON(e).uuid;function i(e){const t=[];for(const r in e){const s=e[r];delete s.metadata,t.push(s)}return t}if(t){const t=i(e.textures),s=i(e.images),n=i(e.nodes);t.length>0&&(r.textures=t),s.length>0&&(r.images=s),n.length>0&&(r.nodes=n)}return r}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.geometryNode=e.geometryNode,this.depthNode=e.depthNode,this.shadowPositionNode=e.shadowPositionNode,this.receivedShadowNode=e.receivedShadowNode,this.castShadowNode=e.castShadowNode,this.outputNode=e.outputNode,this.mrtNode=e.mrtNode,this.fragmentNode=e.fragmentNode,this.vertexNode=e.vertexNode,super.copy(e)}}const Qc=new P;class Zc extends Yc{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(Qc),this.setValues(e)}setup(e){this.setupShaders(e),super.setup(e)}setupShaders({renderer:e}){const t=this.alphaToCoverage,r=this.useColor;this.vertexNode=_i((()=>{const e=hu("instancePosition").xyz,t=Oi($u.mul(Oi(e,1))),r=vc.z.div(vc.w),s=Nu.mul(t),i=ju.xy.toVar();return i.mulAssign(this.pointWidthNode?this.pointWidthNode:Pd),i.assign(i.div(vc.z)),i.y.assign(i.y.mul(r)),i.assign(i.mul(s.w)),s.addAssign(Oi(i,0,0)),s}))(),this.fragmentNode=_i((()=>{const s=Ci(1).toVar(),i=la(pu().mul(2).sub(1));if(t&&e.samples>1){const e=Ci(i.fwidth()).toVar();s.assign(ga(e.oneMinus(),e.add(1),i).oneMinus())}else i.greaterThan(1).discard();let n;if(this.pointColorNode)n=this.pointColorNode;else if(r){n=hu("instanceColor").mul(rd)}else n=rd;return s.mulAssign(nd),Oi(n,s)}))()}get alphaToCoverage(){return this.useAlphaToCoverage}set alphaToCoverage(e){this.useAlphaToCoverage!==e&&(this.useAlphaToCoverage=e,this.needsUpdate=!0)}}const Jc=new I;class eh extends Yc{static get type(){return"LineBasicNodeMaterial"}constructor(e){super(),this.isLineBasicNodeMaterial=!0,this.lights=!1,this.setDefaultValues(Jc),this.setValues(e)}}const th=new L;class rh extends Yc{static get type(){return"LineDashedNodeMaterial"}constructor(e){super(),this.isLineDashedNodeMaterial=!0,this.lights=!1,this.setDefaultValues(th),this.dashOffset=0,this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setupVariants(){const e=this.offsetNode?Ci(this.offsetNodeNode):Fd,t=this.dashScaleNode?Ci(this.dashScaleNode):wd,r=this.dashSizeNode?Ci(this.dashSizeNode):Md,s=this.dashSizeNode?Ci(this.dashGapNode):Bd;An.assign(r),Rn.assign(s);const i=wa(hu("lineDistance").mul(t));(e?i.add(e):i).mod(An.add(Rn)).greaterThan(An).discard()}}let sh=null;class ih extends Mc{static get type(){return"ViewportSharedTextureNode"}constructor(e=xc,t=null){null===sh&&(sh=new w),super(e,t,sh)}updateReference(){return this}}const nh=xi(ih),oh=new L;class ah extends Yc{static get type(){return"Line2NodeMaterial"}constructor(e={}){super(),this.lights=!1,this.setDefaultValues(oh),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.blending=D,this.setValues(e)}setup(e){this.setupShaders(e),super.setup(e)}setupShaders({renderer:e}){const t=this.alphaToCoverage,r=this.useColor,s=this.dashed,i=this.worldUnits,n=_i((({start:e,end:t})=>{const r=Nu.element(2).element(2),s=Nu.element(3).element(2).mul(-.5).div(r).sub(e.z).div(t.z.sub(e.z));return Oi(da(e.xyz,t.xyz,s),t.w)})).setLayout({name:"trimSegment",type:"vec4",inputs:[{name:"start",type:"vec4"},{name:"end",type:"vec4"}]});this.vertexNode=_i((()=>{const e=hu("instanceStart"),t=hu("instanceEnd"),r=Oi($u.mul(Oi(e,1))).toVar("start"),o=Oi($u.mul(Oi(t,1))).toVar("end");if(s){const e=this.dashScaleNode?Ci(this.dashScaleNode):wd,t=this.offsetNode?Ci(this.offsetNodeNode):Fd,r=hu("instanceDistanceStart"),s=hu("instanceDistanceEnd");let i=ju.y.lessThan(.5).select(e.mul(r),e.mul(s));i=i.add(t),nn("float","lineDistance").assign(i)}i&&(nn("vec3","worldStart").assign(r.xyz),nn("vec3","worldEnd").assign(o.xyz));const a=vc.z.div(vc.w),u=Nu.element(2).element(3).equal(-1);Si(u,(()=>{Si(r.z.lessThan(0).and(o.z.greaterThan(0)),(()=>{o.assign(n({start:r,end:o}))})).ElseIf(o.z.lessThan(0).and(r.z.greaterThanEqual(0)),(()=>{r.assign(n({start:o,end:r}))}))}));const l=Nu.mul(r),d=Nu.mul(o),c=l.xyz.div(l.w),h=d.xyz.div(d.w),p=h.xy.sub(c.xy).toVar();p.x.assign(p.x.mul(a)),p.assign(p.normalize());const g=Oi().toVar();if(i){const e=o.xyz.sub(r.xyz).normalize(),t=da(r.xyz,o.xyz,.5).normalize(),i=e.cross(t).normalize(),n=e.cross(i),a=nn("vec4","worldPos");a.assign(ju.y.lessThan(.5).select(r,o));const u=Ud.mul(.5);a.addAssign(Oi(ju.x.lessThan(0).select(i.mul(u),i.mul(u).negate()),0)),s||(a.addAssign(Oi(ju.y.lessThan(.5).select(e.mul(u).negate(),e.mul(u)),0)),a.addAssign(Oi(n.mul(u),0)),Si(ju.y.greaterThan(1).or(ju.y.lessThan(0)),(()=>{a.subAssign(Oi(n.mul(2).mul(u),0))}))),g.assign(Nu.mul(a));const l=Ii().toVar();l.assign(ju.y.lessThan(.5).select(c,h)),g.z.assign(l.z.mul(g.w))}else{const e=Bi(p.y,p.x.negate()).toVar("offset");p.x.assign(p.x.div(a)),e.x.assign(e.x.div(a)),e.assign(ju.x.lessThan(0).select(e.negate(),e)),Si(ju.y.lessThan(0),(()=>{e.assign(e.sub(p))})).ElseIf(ju.y.greaterThan(1),(()=>{e.assign(e.add(p))})),e.assign(e.mul(Ud)),e.assign(e.div(vc.w)),g.assign(ju.y.lessThan(.5).select(l,d)),e.assign(e.mul(g.w)),g.assign(g.add(Oi(e,0,0)))}return g}))();const o=_i((({p1:e,p2:t,p3:r,p4:s})=>{const i=e.sub(r),n=s.sub(r),o=t.sub(e),a=i.dot(n),u=n.dot(o),l=i.dot(o),d=n.dot(n),c=o.dot(o).mul(d).sub(u.mul(u)),h=a.mul(u).sub(l.mul(d)).div(c).clamp(),p=a.add(u.mul(h)).div(d).clamp();return Bi(h,p)}));if(this.colorNode=_i((()=>{const n=pu();if(s){const e=this.dashSizeNode?Ci(this.dashSizeNode):Md,t=this.dashSizeNode?Ci(this.dashGapNode):Bd;An.assign(e),Rn.assign(t);const r=nn("float","lineDistance");n.y.lessThan(-1).or(n.y.greaterThan(1)).discard(),r.mod(An.add(Rn)).greaterThan(An).discard()}const a=Ci(1).toVar("alpha");if(i){const r=nn("vec3","worldStart"),i=nn("vec3","worldEnd"),n=nn("vec4","worldPos").xyz.normalize().mul(1e5),u=i.sub(r),l=o({p1:r,p2:i,p3:Ii(0,0,0),p4:n}),d=r.add(u.mul(l.x)),c=n.mul(l.y),h=d.sub(c).length().div(Ud);if(!s)if(t&&e.samples>1){const e=h.fwidth();a.assign(ga(e.negate().add(.5),e.add(.5),h).oneMinus())}else h.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)),r=e.mul(e).add(t.mul(t)),s=Ci(r.fwidth()).toVar("dlen");Si(n.y.abs().greaterThan(1),(()=>{a.assign(ga(s.oneMinus(),s.add(1),r).oneMinus())}))}else Si(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 u;if(this.lineColorNode)u=this.lineColorNode;else if(r){const e=hu("instanceColorStart"),t=hu("instanceColorEnd");u=ju.y.lessThan(.5).select(e,t).mul(rd)}else u=rd;return Oi(u,a)}))(),this.transparent){const e=this.opacityNode?Ci(this.opacityNode):nd;this.outputNode=Oi(this.colorNode.rgb.mul(e).add(nh().rgb.mul(e.oneMinus())),this.colorNode.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 uh=e=>fi(e).mul(.5).add(.5),lh=new V;class dh extends Yc{static get type(){return"MeshNormalNodeMaterial"}constructor(e){super(),this.lights=!1,this.isMeshNormalNodeMaterial=!0,this.setDefaultValues(lh),this.setValues(e)}setupDiffuseColor(){const e=this.opacityNode?Ci(this.opacityNode):nd;on.assign(Oi(uh(al),e))}}class ch extends Fs{static get type(){return"EquirectUVNode"}constructor(e=Yu){super("vec2"),this.dirNode=e}setup(){const e=this.dirNode,t=e.z.atan2(e.x).mul(1/(2*Math.PI)).add(.5),r=e.y.clamp(-1,1).asin().mul(1/Math.PI).add(.5);return Bi(t,r)}}const hh=xi(ch);class ph extends O{constructor(e=1,t={}){super(e,t),this.isCubeRenderTarget=!0}fromEquirectangularTexture(e,t){const r=t.minFilter,s=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 i=new G(5,5,5),n=hh(Yu),o=new Yc;o.colorNode=xu(t,n,0),o.side=x,o.blending=D;const a=new k(i,o),u=new z;u.add(a),t.minFilter===M&&(t.minFilter=$);const l=new H(1,10,this),d=e.getMRT();return e.setMRT(null),l.update(e,u),e.setMRT(d),t.minFilter=r,t.currentGenerateMipmaps=s,a.geometry.dispose(),a.material.dispose(),this}}const gh=new WeakMap;class mh extends Fs{static get type(){return"CubeMapNode"}constructor(e){super("vec3"),this.envNode=e,this._cubeTexture=null,this._cubeTextureNode=bl();const t=new W;t.isRenderTargetTexture=!0,this._defaultTexture=t,this.updateBeforeType=vs.RENDER}updateBefore(e){const{renderer:t,material:r}=e,s=this.envNode;if(s.isTextureNode||s.isMaterialReferenceNode){const e=s.isTextureNode?s.value:r[s.property];if(e&&e.isTexture){const r=e.mapping;if(r===j||r===q){if(gh.has(e)){const t=gh.get(e);yh(t,e.mapping),this._cubeTexture=t}else{const r=e.image;if(function(e){return null!=e&&e.height>0}(r)){const s=new ph(r.height);s.fromEquirectangularTexture(t,e),yh(s.texture,e.mapping),this._cubeTexture=s.texture,gh.set(e,s.texture),e.addEventListener("dispose",fh)}else this._cubeTexture=this._defaultTexture}this._cubeTextureNode.value=this._cubeTexture}else this._cubeTextureNode=this.envNode}}}setup(e){return this.updateBefore(e),this._cubeTextureNode}}function fh(e){const t=e.target;t.removeEventListener("dispose",fh);const r=gh.get(t);void 0!==r&&(gh.delete(t),r.dispose())}function yh(e,t){t===j?e.mapping=T:t===q&&(e.mapping=_)}const bh=xi(mh);class xh extends cc{static get type(){return"BasicEnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){e.context.environment=bh(this.envNode)}}class Th extends cc{static get type(){return"BasicLightMapNode"}constructor(e=null){super(),this.lightMapNode=e}setup(e){const t=Ci(1/Math.PI);e.context.irradianceLightMap=this.lightMapNode.mul(t)}}class _h{start(){}finish(){}direct(){}directRectArea(){}indirect(){}ambientOcclusion(){}}class vh extends _h{constructor(){super()}indirect(e,t,r){const s=e.ambientOcclusion,i=e.reflectedLight,n=r.context.irradianceLightMap;i.indirectDiffuse.assign(Oi(0)),n?i.indirectDiffuse.addAssign(n):i.indirectDiffuse.addAssign(Oi(1,1,1,0)),i.indirectDiffuse.mulAssign(s),i.indirectDiffuse.mulAssign(on.rgb)}finish(e,t,r){const s=r.material,i=e.outgoingLight,n=r.context.environment;if(n)switch(s.combine){case Y:i.rgb.assign(da(i.rgb,i.rgb.mul(n.rgb),ld.mul(dd)));break;case X:i.rgb.assign(da(i.rgb,n.rgb,ld.mul(dd)));break;case K:i.rgb.addAssign(n.rgb.mul(ld.mul(dd)));break;default:console.warn("THREE.BasicLightingModel: Unsupported .combine value:",s.combine)}}}const Nh=new Q;class Sh extends Yc{static get type(){return"MeshBasicNodeMaterial"}constructor(e){super(),this.isMeshBasicNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Nh),this.setValues(e)}setupNormal(){return nl}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new xh(t):null}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new Th(Ld)),t}setupOutgoingLight(){return on.rgb}setupLightingModel(){return new vh}}const Ah=_i((({f0:e,f90:t,dotVH:r})=>{const s=r.mul(-5.55473).sub(6.98316).mul(r).exp2();return e.mul(s.oneMinus()).add(t.mul(s))})),Rh=_i((e=>e.diffuseColor.mul(1/Math.PI))),Ch=_i((({dotNH:e})=>Nn.mul(Ci(.5)).add(1).mul(Ci(1/Math.PI)).mul(e.pow(Nn)))),Eh=_i((({lightDirection:e})=>{const t=e.add(Zu).normalize(),r=al.dot(t).clamp(),s=Zu.dot(t).clamp(),i=Ah({f0:_n,f90:1,dotVH:s}),n=Ci(.25),o=Ch({dotNH:r});return i.mul(n).mul(o)}));class wh extends vh{constructor(e=!0){super(),this.specular=e}direct({lightDirection:e,lightColor:t,reflectedLight:r}){const s=al.dot(e).clamp().mul(t);r.directDiffuse.addAssign(s.mul(Rh({diffuseColor:on.rgb}))),!0===this.specular&&r.directSpecular.addAssign(s.mul(Eh({lightDirection:e})).mul(ld))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:r}){r.indirectDiffuse.addAssign(t.mul(Rh({diffuseColor:on}))),r.indirectDiffuse.mulAssign(e)}}const Mh=new Z;class Bh extends Yc{static get type(){return"MeshLambertNodeMaterial"}constructor(e){super(),this.isMeshLambertNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Mh),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new xh(t):null}setupLightingModel(){return new wh(!1)}}const Uh=new J;class Fh extends Yc{static get type(){return"MeshPhongNodeMaterial"}constructor(e){super(),this.isMeshPhongNodeMaterial=!0,this.lights=!0,this.shininessNode=null,this.specularNode=null,this.setDefaultValues(Uh),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new xh(t):null}setupLightingModel(){return new wh}setupVariants(){const e=(this.shininessNode?Ci(this.shininessNode):sd).max(1e-4);Nn.assign(e);const t=this.specularNode||od;_n.assign(t)}copy(e){return this.shininessNode=e.shininessNode,this.specularNode=e.specularNode,super.copy(e)}}const Ph=_i((e=>{if(!1===e.geometry.hasAttribute("normal"))return Ci(0);const t=nl.dFdx().abs().max(nl.dFdy().abs());return t.x.max(t.y).max(t.z)})),Ih=_i((e=>{const{roughness:t}=e,r=Ph();let s=t.max(.0525);return s=s.add(r),s=s.min(1),s})),Lh=_i((({alpha:e,dotNL:t,dotNV:r})=>{const s=e.pow2(),i=t.mul(s.add(s.oneMinus().mul(r.pow2())).sqrt()),n=r.mul(s.add(s.oneMinus().mul(t.pow2())).sqrt());return zn(.5,i.add(n).max(uo))})).setLayout({name:"V_GGX_SmithCorrelated",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNL",type:"float"},{name:"dotNV",type:"float"}]}),Dh=_i((({alphaT:e,alphaB:t,dotTV:r,dotBV:s,dotTL:i,dotBL:n,dotNV:o,dotNL:a})=>{const u=a.mul(Ii(e.mul(r),t.mul(s),o).length()),l=o.mul(Ii(e.mul(i),t.mul(n),a).length());return zn(.5,u.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"}]}),Vh=_i((({alpha:e,dotNH:t})=>{const r=e.pow2(),s=t.pow2().mul(r.oneMinus()).oneMinus();return r.div(s.pow2()).mul(1/Math.PI)})).setLayout({name:"D_GGX",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNH",type:"float"}]}),Oh=Ci(1/Math.PI),Gh=_i((({alphaT:e,alphaB:t,dotNH:r,dotTH:s,dotBH:i})=>{const n=e.mul(t),o=Ii(t.mul(s),e.mul(i),n.mul(r)),a=o.dot(o),u=n.div(a);return Oh.mul(n.mul(u.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"}]}),kh=_i((e=>{const{lightDirection:t,f0:r,f90:s,roughness:i,f:n,USE_IRIDESCENCE:o,USE_ANISOTROPY:a}=e,u=e.normalView||al,l=i.pow2(),d=t.add(Zu).normalize(),c=u.dot(t).clamp(),h=u.dot(Zu).clamp(),p=u.dot(d).clamp(),g=Zu.dot(d).clamp();let m,f,y=Ah({f0:r,f90:s,dotVH:g});if(pi(o)&&(y=gn.mix(y,n)),pi(a)){const e=xn.dot(t),r=xn.dot(Zu),s=xn.dot(d),i=Tn.dot(t),n=Tn.dot(Zu),o=Tn.dot(d);m=Dh({alphaT:yn,alphaB:l,dotTV:r,dotBV:n,dotTL:e,dotBL:i,dotNV:h,dotNL:c}),f=Gh({alphaT:yn,alphaB:l,dotNH:p,dotTH:s,dotBH:o})}else m=Lh({alpha:l,dotNL:c,dotNV:h}),f=Vh({alpha:l,dotNH:p});return y.mul(m).mul(f)})),zh=_i((({roughness:e,dotNV:t})=>{const r=Oi(-1,-.0275,-.572,.022),s=Oi(1,.0425,1.04,-.04),i=e.mul(r).add(s),n=i.x.mul(i.x).min(t.mul(-9.28).exp2()).mul(i.x).add(i.y);return Bi(-1.04,1.04).mul(n).add(i.zw)})).setLayout({name:"DFGApprox",type:"vec2",inputs:[{name:"roughness",type:"float"},{name:"dotNV",type:"vec3"}]}),$h=_i((e=>{const{dotNV:t,specularColor:r,specularF90:s,roughness:i}=e,n=zh({dotNV:t,roughness:i});return r.mul(n.x).add(s.mul(n.y))})),Hh=_i((({f:e,f90:t,dotVH:r})=>{const s=r.oneMinus().saturate(),i=s.mul(s),n=s.mul(i,i).clamp(0,.9999);return e.sub(Ii(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"}]}),Wh=_i((({roughness:e,dotNH:t})=>{const r=e.pow2(),s=Ci(1).div(r),i=t.pow2().oneMinus().max(.0078125);return Ci(2).add(s).mul(i.pow(s.mul(.5))).div(2*Math.PI)})).setLayout({name:"D_Charlie",type:"float",inputs:[{name:"roughness",type:"float"},{name:"dotNH",type:"float"}]}),jh=_i((({dotNV:e,dotNL:t})=>Ci(1).div(Ci(4).mul(t.add(e).sub(t.mul(e)))))).setLayout({name:"V_Neubelt",type:"float",inputs:[{name:"dotNV",type:"float"},{name:"dotNL",type:"float"}]}),qh=_i((({lightDirection:e})=>{const t=e.add(Zu).normalize(),r=al.dot(e).clamp(),s=al.dot(Zu).clamp(),i=al.dot(t).clamp(),n=Wh({roughness:pn,dotNH:i}),o=jh({dotNV:s,dotNL:r});return hn.mul(n).mul(o)})),Kh=_i((({N:e,V:t,roughness:r})=>{const s=e.dot(t).saturate(),i=Bi(r,s.oneMinus().sqrt());return i.assign(i.mul(.984375).add(.0078125)),i})).setLayout({name:"LTC_Uv",type:"vec2",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"roughness",type:"float"}]}),Xh=_i((({f:e})=>{const t=e.length();return Xo(t.mul(t).add(e.z).div(t.add(1)),0)})).setLayout({name:"LTC_ClippedSphereFormFactor",type:"float",inputs:[{name:"f",type:"vec3"}]}),Yh=_i((({v1:e,v2:t})=>{const r=e.dot(t),s=r.abs().toVar(),i=s.mul(.0145206).add(.4965155).mul(s).add(.8543985).toVar(),n=s.add(4.1616724).mul(s).add(3.417594).toVar(),o=i.div(n),a=r.greaterThan(0).select(o,Xo(r.mul(r).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"}]}),Qh=_i((({N:e,V:t,P:r,mInv:s,p0:i,p1:n,p2:o,p3:a})=>{const u=n.sub(i).toVar(),l=a.sub(i).toVar(),d=u.cross(l),c=Ii().toVar();return Si(d.dot(r.sub(i)).greaterThanEqual(0),(()=>{const u=t.sub(e.mul(t.dot(e))).normalize(),l=e.cross(u).negate(),d=s.mul(Hi(u,l,e).transpose()).toVar(),h=d.mul(i.sub(r)).normalize().toVar(),p=d.mul(n.sub(r)).normalize().toVar(),g=d.mul(o.sub(r)).normalize().toVar(),m=d.mul(a.sub(r)).normalize().toVar(),f=Ii(0).toVar();f.addAssign(Yh({v1:h,v2:p})),f.addAssign(Yh({v1:p,v2:g})),f.addAssign(Yh({v1:g,v2:m})),f.addAssign(Yh({v1:m,v2:h})),c.assign(Ii(Xh({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"}]}),Zh=1/6,Jh=e=>kn(Zh,kn(e,kn(e,e.negate().add(3)).sub(3)).add(1)),ep=e=>kn(Zh,kn(e,kn(e,kn(3,e).sub(6))).add(4)),tp=e=>kn(Zh,kn(e,kn(e,kn(-3,e).add(3)).add(3)).add(1)),rp=e=>kn(Zh,sa(e,3)),sp=e=>Jh(e).add(ep(e)),ip=e=>tp(e).add(rp(e)),np=e=>On(-1,ep(e).div(Jh(e).add(ep(e)))),op=e=>On(1,rp(e).div(tp(e).add(rp(e)))),ap=(e,t,r)=>{const s=e.uvNode,i=kn(s,t.zw).add(.5),n=So(i),o=Co(i),a=sp(o.x),u=ip(o.x),l=np(o.x),d=op(o.x),c=np(o.y),h=op(o.y),p=Bi(n.x.add(l),n.y.add(c)).sub(.5).mul(t.xy),g=Bi(n.x.add(d),n.y.add(c)).sub(.5).mul(t.xy),m=Bi(n.x.add(l),n.y.add(h)).sub(.5).mul(t.xy),f=Bi(n.x.add(d),n.y.add(h)).sub(.5).mul(t.xy),y=sp(o.y).mul(On(a.mul(e.sample(p).level(r)),u.mul(e.sample(g).level(r)))),b=ip(o.y).mul(On(a.mul(e.sample(m).level(r)),u.mul(e.sample(f).level(r))));return y.add(b)},up=_i((([e,t=Ci(3)])=>{const r=Bi(e.size(Ei(t))),s=Bi(e.size(Ei(t.add(1)))),i=zn(1,r),n=zn(1,s),o=ap(e,Oi(i,r),So(t)),a=ap(e,Oi(n,s),Ao(t));return Co(t).mix(o,a)})),lp=_i((([e,t,r,s,i])=>{const n=Ii(pa(t.negate(),Ro(e),zn(1,s))),o=Ii(Lo(i[0].xyz),Lo(i[1].xyz),Lo(i[2].xyz));return Ro(n).mul(r.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"}]}),dp=_i((([e,t])=>e.mul(ca(t.mul(2).sub(2),0,1)))).setLayout({name:"applyIorToRoughness",type:"float",inputs:[{name:"roughness",type:"float"},{name:"ior",type:"float"}]}),cp=Uc(),hp=Uc(),pp=_i((([e,t,r],{material:s})=>{const i=(s.side===x?cp:hp).sample(e),n=_o(Tc.x).mul(dp(t,r));return up(i,n)})),gp=_i((([e,t,r])=>(Si(r.notEqual(0),(()=>{const s=To(t).negate().div(r);return bo(s.negate().mul(e))})),Ii(1)))).setLayout({name:"volumeAttenuation",type:"vec3",inputs:[{name:"transmissionDistance",type:"float"},{name:"attenuationColor",type:"vec3"},{name:"attenuationDistance",type:"float"}]}),mp=_i((([e,t,r,s,i,n,o,a,u,l,d,c,h,p,g])=>{let m,f;if(g){m=Oi().toVar(),f=Ii().toVar();const i=d.sub(1).mul(g.mul(.025)),n=Ii(d.sub(i),d,d.add(i));ic({start:0,end:3},(({i:i})=>{const d=n.element(i),g=lp(e,t,c,d,a),y=o.add(g),b=l.mul(u.mul(Oi(y,1))),x=Bi(b.xy.div(b.w)).toVar();x.addAssign(1),x.divAssign(2),x.assign(Bi(x.x,x.y.oneMinus()));const T=pp(x,r,d);m.element(i).assign(T.element(i)),m.a.addAssign(T.a),f.element(i).assign(s.element(i).mul(gp(Lo(g),h,p).element(i)))})),m.a.divAssign(3)}else{const i=lp(e,t,c,d,a),n=o.add(i),g=l.mul(u.mul(Oi(n,1))),y=Bi(g.xy.div(g.w)).toVar();y.addAssign(1),y.divAssign(2),y.assign(Bi(y.x,y.y.oneMinus())),m=pp(y,r,d),f=s.mul(gp(Lo(i),h,p))}const y=f.rgb.mul(m.rgb),b=e.dot(t).clamp(),x=Ii($h({dotNV:b,specularColor:i,specularF90:n,roughness:r})),T=f.r.add(f.g,f.b).div(3);return Oi(x.oneMinus().mul(y),m.a.oneMinus().mul(T).oneMinus())})),fp=Hi(3.2404542,-.969266,.0556434,-1.5371385,1.8760108,-.2040259,-.4985314,.041556,1.0572252),yp=(e,t)=>e.sub(t).div(e.add(t)).pow2(),bp=_i((({outsideIOR:e,eta2:t,cosTheta1:r,thinFilmThickness:s,baseF0:i})=>{const n=da(e,t,ga(0,.03,s)),o=e.div(n).pow2().mul(r.pow2().oneMinus()).oneMinus();Si(o.lessThan(0),(()=>Ii(1)));const a=o.sqrt(),u=yp(n,e),l=Ah({f0:u,f90:1,dotVH:r}),d=l.oneMinus(),c=n.lessThan(e).select(Math.PI,0),h=Ci(Math.PI).sub(c),p=(e=>{const t=e.sqrt();return Ii(1).add(t).div(Ii(1).sub(t))})(i.clamp(0,.9999)),g=yp(p,n.toVec3()),m=Ah({f0:g,f90:1,dotVH:a}),f=Ii(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(s,a,2),b=Ii(h).add(f),x=l.mul(m).clamp(1e-5,.9999),T=x.sqrt(),_=d.pow2().mul(m).div(Ii(1).sub(x)),v=l.add(_).toVar(),N=_.sub(d).toVar();return ic({start:1,end:2,condition:"<=",name:"m"},(({m:e})=>{N.mulAssign(T);const t=((e,t)=>{const r=e.mul(2*Math.PI*1e-9),s=Ii(54856e-17,44201e-17,52481e-17),i=Ii(1681e3,1795300,2208400),n=Ii(43278e5,93046e5,66121e5),o=Ci(9747e-17*Math.sqrt(2*Math.PI*45282e5)).mul(r.mul(2239900).add(t.x).cos()).mul(r.pow2().mul(-45282e5).exp());let a=s.mul(n.mul(2*Math.PI).sqrt()).mul(i.mul(r).add(t).cos()).mul(r.pow2().negate().mul(n).exp());return a=Ii(a.x.add(o),a.y,a.z).div(1.0685e-7),fp.mul(a)})(Ci(e).mul(y),Ci(e).mul(b)).mul(2);v.addAssign(N.mul(t))})),v.max(Ii(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"}]}),xp=_i((({normal:e,viewDir:t,roughness:r})=>{const s=e.dot(t).saturate(),i=r.pow2(),n=Ta(r.lessThan(.25),Ci(-339.2).mul(i).add(Ci(161.4).mul(r)).sub(25.9),Ci(-8.48).mul(i).add(Ci(14.3).mul(r)).sub(9.95)),o=Ta(r.lessThan(.25),Ci(44).mul(i).sub(Ci(23.7).mul(r)).add(3.26),Ci(1.97).mul(i).sub(Ci(3.27).mul(r)).add(.72));return Ta(r.lessThan(.25),0,Ci(.1).mul(r).sub(.025)).add(n.mul(s).add(o).exp()).mul(1/Math.PI).saturate()})),Tp=Ii(.04),_p=Ci(1);class vp extends _h{constructor(e=!1,t=!1,r=!1,s=!1,i=!1,n=!1){super(),this.clearcoat=e,this.sheen=t,this.iridescence=r,this.anisotropy=s,this.transmission=i,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=Ii().toVar("clearcoatRadiance"),this.clearcoatSpecularDirect=Ii().toVar("clearcoatSpecularDirect"),this.clearcoatSpecularIndirect=Ii().toVar("clearcoatSpecularIndirect")),!0===this.sheen&&(this.sheenSpecularDirect=Ii().toVar("sheenSpecularDirect"),this.sheenSpecularIndirect=Ii().toVar("sheenSpecularIndirect")),!0===this.iridescence){const e=al.dot(Zu).clamp();this.iridescenceFresnel=bp({outsideIOR:Ci(1),eta2:mn,cosTheta1:e,thinFilmThickness:fn,baseF0:_n}),this.iridescenceF0=Hh({f:this.iridescenceFresnel,f90:1,dotVH:e})}if(!0===this.transmission){const t=Xu,r=Eu.sub(Xu).normalize(),s=ul;e.backdrop=mp(s,r,un,on,_n,vn,t,Du,Au,Nu,En,Mn,Un,Bn,this.dispersion?Fn:null),e.backdropAlpha=wn,on.a.mulAssign(da(1,e.backdrop.a,wn))}}computeMultiscattering(e,t,r){const s=al.dot(Zu).clamp(),i=zh({roughness:un,dotNV:s}),n=(this.iridescenceF0?gn.mix(_n,this.iridescenceF0):_n).mul(i.x).add(r.mul(i.y)),o=i.x.add(i.y).oneMinus(),a=_n.add(_n.oneMinus().mul(.047619)),u=n.mul(a).div(o.mul(a).oneMinus());e.addAssign(n),t.addAssign(u.mul(o))}direct({lightDirection:e,lightColor:t,reflectedLight:r}){const s=al.dot(e).clamp().mul(t);if(!0===this.sheen&&this.sheenSpecularDirect.addAssign(s.mul(qh({lightDirection:e}))),!0===this.clearcoat){const r=ll.dot(e).clamp().mul(t);this.clearcoatSpecularDirect.addAssign(r.mul(kh({lightDirection:e,f0:Tp,f90:_p,roughness:cn,normalView:ll})))}r.directDiffuse.addAssign(s.mul(Rh({diffuseColor:on.rgb}))),r.directSpecular.addAssign(s.mul(kh({lightDirection:e,f0:_n,f90:1,roughness:un,iridescence:this.iridescence,f:this.iridescenceFresnel,USE_IRIDESCENCE:this.iridescence,USE_ANISOTROPY:this.anisotropy})))}directRectArea({lightColor:e,lightPosition:t,halfWidth:r,halfHeight:s,reflectedLight:i,ltc_1:n,ltc_2:o}){const a=t.add(r).sub(s),u=t.sub(r).sub(s),l=t.sub(r).add(s),d=t.add(r).add(s),c=al,h=Zu,p=Qu.toVar(),g=Kh({N:c,V:h,roughness:un}),m=n.sample(g).toVar(),f=o.sample(g).toVar(),y=Hi(Ii(m.x,0,m.y),Ii(0,1,0),Ii(m.z,0,m.w)).toVar(),b=_n.mul(f.x).add(_n.oneMinus().mul(f.y)).toVar();i.directSpecular.addAssign(e.mul(b).mul(Qh({N:c,V:h,P:p,mInv:y,p0:a,p1:u,p2:l,p3:d}))),i.directDiffuse.addAssign(e.mul(on).mul(Qh({N:c,V:h,P:p,mInv:Hi(1,0,0,0,1,0,0,0,1),p0:a,p1:u,p2:l,p3:d})))}indirect(e,t,r){this.indirectDiffuse(e,t,r),this.indirectSpecular(e,t,r),this.ambientOcclusion(e,t,r)}indirectDiffuse({irradiance:e,reflectedLight:t}){t.indirectDiffuse.addAssign(e.mul(Rh({diffuseColor:on})))}indirectSpecular({radiance:e,iblIrradiance:t,reflectedLight:r}){if(!0===this.sheen&&this.sheenSpecularIndirect.addAssign(t.mul(hn,xp({normal:al,viewDir:Zu,roughness:pn}))),!0===this.clearcoat){const e=ll.dot(Zu).clamp(),t=$h({dotNV:e,specularColor:Tp,specularF90:_p,roughness:cn});this.clearcoatSpecularIndirect.addAssign(this.clearcoatRadiance.mul(t))}const s=Ii().toVar("singleScattering"),i=Ii().toVar("multiScattering"),n=t.mul(1/Math.PI);this.computeMultiscattering(s,i,vn);const o=s.add(i),a=on.mul(o.r.max(o.g).max(o.b).oneMinus());r.indirectSpecular.addAssign(e.mul(s)),r.indirectSpecular.addAssign(i.mul(n)),r.indirectDiffuse.addAssign(a.mul(n))}ambientOcclusion({ambientOcclusion:e,reflectedLight:t}){const r=al.dot(Zu).clamp().add(e),s=un.mul(-16).oneMinus().negate().exp2(),i=e.sub(r.pow(s).oneMinus()).clamp();!0===this.clearcoat&&this.clearcoatSpecularIndirect.mulAssign(e),!0===this.sheen&&this.sheenSpecularIndirect.mulAssign(e),t.indirectDiffuse.mulAssign(e),t.indirectSpecular.mulAssign(i)}finish(e){const{outgoingLight:t}=e;if(!0===this.clearcoat){const e=ll.dot(Zu).clamp(),r=Ah({dotVH:e,f0:Tp,f90:_p}),s=t.mul(dn.mul(r).oneMinus()).add(this.clearcoatSpecularDirect.add(this.clearcoatSpecularIndirect).mul(dn));t.assign(s)}if(!0===this.sheen){const e=hn.r.max(hn.g).max(hn.b).mul(.157).oneMinus(),r=t.mul(e).add(this.sheenSpecularDirect,this.sheenSpecularIndirect);t.assign(r)}}}const Np=Ci(1),Sp=Ci(-2),Ap=Ci(.8),Rp=Ci(-1),Cp=Ci(.4),Ep=Ci(2),wp=Ci(.305),Mp=Ci(3),Bp=Ci(.21),Up=Ci(4),Fp=Ci(4),Pp=Ci(16),Ip=_i((([e])=>{const t=Ii(Po(e)).toVar(),r=Ci(-1).toVar();return Si(t.x.greaterThan(t.z),(()=>{Si(t.x.greaterThan(t.y),(()=>{r.assign(Ta(e.x.greaterThan(0),0,3))})).Else((()=>{r.assign(Ta(e.y.greaterThan(0),1,4))}))})).Else((()=>{Si(t.z.greaterThan(t.y),(()=>{r.assign(Ta(e.z.greaterThan(0),2,5))})).Else((()=>{r.assign(Ta(e.y.greaterThan(0),1,4))}))})),r})).setLayout({name:"getFace",type:"float",inputs:[{name:"direction",type:"vec3"}]}),Lp=_i((([e,t])=>{const r=Bi().toVar();return Si(t.equal(0),(()=>{r.assign(Bi(e.z,e.y).div(Po(e.x)))})).ElseIf(t.equal(1),(()=>{r.assign(Bi(e.x.negate(),e.z.negate()).div(Po(e.y)))})).ElseIf(t.equal(2),(()=>{r.assign(Bi(e.x.negate(),e.y).div(Po(e.z)))})).ElseIf(t.equal(3),(()=>{r.assign(Bi(e.z.negate(),e.y).div(Po(e.x)))})).ElseIf(t.equal(4),(()=>{r.assign(Bi(e.x.negate(),e.z).div(Po(e.y)))})).Else((()=>{r.assign(Bi(e.x,e.y).div(Po(e.z)))})),kn(.5,r.add(1))})).setLayout({name:"getUV",type:"vec2",inputs:[{name:"direction",type:"vec3"},{name:"face",type:"float"}]}),Dp=_i((([e])=>{const t=Ci(0).toVar();return Si(e.greaterThanEqual(Ap),(()=>{t.assign(Np.sub(e).mul(Rp.sub(Sp)).div(Np.sub(Ap)).add(Sp))})).ElseIf(e.greaterThanEqual(Cp),(()=>{t.assign(Ap.sub(e).mul(Ep.sub(Rp)).div(Ap.sub(Cp)).add(Rp))})).ElseIf(e.greaterThanEqual(wp),(()=>{t.assign(Cp.sub(e).mul(Mp.sub(Ep)).div(Cp.sub(wp)).add(Ep))})).ElseIf(e.greaterThanEqual(Bp),(()=>{t.assign(wp.sub(e).mul(Up.sub(Mp)).div(wp.sub(Bp)).add(Mp))})).Else((()=>{t.assign(Ci(-2).mul(_o(kn(1.16,e))))})),t})).setLayout({name:"roughnessToMip",type:"float",inputs:[{name:"roughness",type:"float"}]}),Vp=_i((([e,t])=>{const r=e.toVar();r.assign(kn(2,r).sub(1));const s=Ii(r,1).toVar();return Si(t.equal(0),(()=>{s.assign(s.zyx)})).ElseIf(t.equal(1),(()=>{s.assign(s.xzy),s.xz.mulAssign(-1)})).ElseIf(t.equal(2),(()=>{s.x.mulAssign(-1)})).ElseIf(t.equal(3),(()=>{s.assign(s.zyx),s.xz.mulAssign(-1)})).ElseIf(t.equal(4),(()=>{s.assign(s.xzy),s.xy.mulAssign(-1)})).ElseIf(t.equal(5),(()=>{s.z.mulAssign(-1)})),s})).setLayout({name:"getDirection",type:"vec3",inputs:[{name:"uv",type:"vec2"},{name:"face",type:"float"}]}),Op=_i((([e,t,r,s,i,n])=>{const o=Ci(r),a=Ii(t),u=ca(Dp(o),Sp,n),l=Co(u),d=So(u),c=Ii(Gp(e,a,d,s,i,n)).toVar();return Si(l.notEqual(0),(()=>{const t=Ii(Gp(e,a,d.add(1),s,i,n)).toVar();c.assign(da(c,t,l))})),c})),Gp=_i((([e,t,r,s,i,n])=>{const o=Ci(r).toVar(),a=Ii(t),u=Ci(Ip(a)).toVar(),l=Ci(Xo(Fp.sub(o),0)).toVar();o.assign(Xo(o,Fp));const d=Ci(xo(o)).toVar(),c=Bi(Lp(a,u).mul(d.sub(2)).add(1)).toVar();return Si(u.greaterThan(2),(()=>{c.y.addAssign(d),u.subAssign(3)})),c.x.addAssign(u.mul(d)),c.x.addAssign(l.mul(kn(3,Pp))),c.y.addAssign(kn(4,xo(n).sub(d))),c.x.mulAssign(s),c.y.mulAssign(i),e.sample(c).grad(Bi(),Bi())})),kp=_i((({envMap:e,mipInt:t,outputDirection:r,theta:s,axis:i,CUBEUV_TEXEL_WIDTH:n,CUBEUV_TEXEL_HEIGHT:o,CUBEUV_MAX_MIP:a})=>{const u=wo(s),l=r.mul(u).add(i.cross(r).mul(Eo(s))).add(i.mul(i.dot(r).mul(u.oneMinus())));return Gp(e,l,t,n,o,a)})),zp=_i((({n:e,latitudinal:t,poleAxis:r,outputDirection:s,weights:i,samples:n,dTheta:o,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c})=>{const h=Ii(Ta(t,r,ra(r,s))).toVar();Si(po(h.equals(Ii(0))),(()=>{h.assign(Ii(s.z,0,s.x.negate()))})),h.assign(Ro(h));const p=Ii().toVar();return p.addAssign(i.element(Ei(0)).mul(kp({theta:0,axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c}))),ic({start:Ei(1),end:e},(({i:e})=>{Si(e.greaterThanEqual(n),(()=>{nc()}));const t=Ci(o.mul(Ci(e))).toVar();p.addAssign(i.element(e).mul(kp({theta:t.mul(-1),axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c}))),p.addAssign(i.element(e).mul(kp({theta:t,axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c})))})),Oi(p,1)}));let $p=null;const Hp=new WeakMap;function Wp(e){let t=Hp.get(e);if((void 0!==t?t.pmremVersion:-1)!==e.pmremVersion){const r=e.image;if(e.isCubeTexture){if(!function(e){if(null==e)return!1;let t=0;const r=6;for(let s=0;s0}(r))return null;t=$p.fromEquirectangular(e,t)}t.pmremVersion=e.pmremVersion,Hp.set(e,t)}return t.texture}class jp extends Fs{static get type(){return"PMREMNode"}constructor(e,t=null,r=null){super("vec3"),this._value=e,this._pmrem=null,this.uvNode=t,this.levelNode=r,this._generator=null;const s=new ee;s.isRenderTargetTexture=!0,this._texture=xu(s),this._width=tn(0),this._height=tn(0),this._maxMip=tn(0),this.updateBeforeType=vs.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,r=1/e;return{texelWidth:1/(3*Math.max(Math.pow(2,t),112)),texelHeight:r,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,r=this._value;t!==r.pmremVersion&&(e=!0===r.isPMREMTexture?r:Wp(r),null!==e&&(this._pmrem=e,this.updateFromTexture(e)))}setup(e){null===$p&&($p=e.createPMREMGenerator()),this.updateBefore(e);let t=this.uvNode;null===t&&e.context.getUV&&(t=e.context.getUV(this));const r=this.value;e.renderer.coordinateSystem===b&&!0!==r.isPMREMTexture&&!0===r.isRenderTargetTexture&&(t=Ii(t.x.negate(),t.yz)),t=Ii(t.x,t.y.negate(),t.z);let s=this.levelNode;return null===s&&e.context.getTextureLevel&&(s=e.context.getTextureLevel(this)),Op(this._texture,t,s,this._width,this._height,this._maxMip)}}const qp=xi(jp),Kp=new WeakMap;class Xp extends cc{static get type(){return"EnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){const{material:t}=e;let r=this.envNode;if(r.isTextureNode||r.isMaterialReferenceNode){const e=r.isTextureNode?r.value:t[r.property];let s=Kp.get(e);void 0===s&&(s=qp(e),Kp.set(e,s)),r=s}const s=t.envMap?Rl("envMapIntensity","float",e.material):Rl("environmentIntensity","float",e.scene),i=!0===t.useAnisotropy||t.anisotropy>0?Wl:al,n=r.context(Yp(un,i)).mul(s),o=r.context(Qp(ul)).mul(Math.PI).mul(s),a=eu(n),u=eu(o);e.context.radiance.addAssign(a),e.context.iblIrradiance.addAssign(u);const l=e.context.lightingModel.clearcoatRadiance;if(l){const e=r.context(Yp(cn,ll)).mul(s),t=eu(e);l.addAssign(t)}}}const Yp=(e,t)=>{let r=null;return{getUV:()=>(null===r&&(r=Zu.negate().reflect(t),r=e.mul(e).mix(r,t).normalize(),r=r.transformDirection(Au)),r),getTextureLevel:()=>e}},Qp=e=>({getUV:()=>e,getTextureLevel:()=>Ci(1)}),Zp=new te;class Jp extends Yc{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(Zp),this.setValues(e)}setupEnvironment(e){let t=super.setupEnvironment(e);return null===t&&e.environmentNode&&(t=e.environmentNode),t?new Xp(t):null}setupLightingModel(){return new vp}setupSpecular(){const e=da(Ii(.04),on.rgb,ln);_n.assign(e),vn.assign(1)}setupVariants(){const e=this.metalnessNode?Ci(this.metalnessNode):hd;ln.assign(e);let t=this.roughnessNode?Ci(this.roughnessNode):cd;t=Ih({roughness:t}),un.assign(t),this.setupSpecular(),on.assign(Oi(on.rgb.mul(e.oneMinus()),on.a))}copy(e){return this.emissiveNode=e.emissiveNode,this.metalnessNode=e.metalnessNode,this.roughnessNode=e.roughnessNode,super.copy(e)}}const eg=new re;class tg extends Jp{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(eg),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?Ci(this.iorNode):Rd;En.assign(e),_n.assign(da(Ko(ia(En.sub(1).div(En.add(1))).mul(ud),Ii(1)).mul(ad),on.rgb,ln)),vn.assign(da(ad,1,ln))}setupLightingModel(){return new vp(this.useClearcoat,this.useSheen,this.useIridescence,this.useAnisotropy,this.useTransmission,this.useDispersion)}setupVariants(e){if(super.setupVariants(e),this.useClearcoat){const e=this.clearcoatNode?Ci(this.clearcoatNode):gd,t=this.clearcoatRoughnessNode?Ci(this.clearcoatRoughnessNode):md;dn.assign(e),cn.assign(Ih({roughness:t}))}if(this.useSheen){const e=this.sheenNode?Ii(this.sheenNode):bd,t=this.sheenRoughnessNode?Ci(this.sheenRoughnessNode):xd;hn.assign(e),pn.assign(t)}if(this.useIridescence){const e=this.iridescenceNode?Ci(this.iridescenceNode):_d,t=this.iridescenceIORNode?Ci(this.iridescenceIORNode):vd,r=this.iridescenceThicknessNode?Ci(this.iridescenceThicknessNode):Nd;gn.assign(e),mn.assign(t),fn.assign(r)}if(this.useAnisotropy){const e=(this.anisotropyNode?Bi(this.anisotropyNode):Td).toVar();bn.assign(e.length()),Si(bn.equal(0),(()=>{e.assign(Bi(1,0))})).Else((()=>{e.divAssign(Bi(bn)),bn.assign(bn.saturate())})),yn.assign(bn.pow2().mix(un.pow2(),1)),xn.assign($l[0].mul(e.x).add($l[1].mul(e.y))),Tn.assign($l[1].mul(e.x).sub($l[0].mul(e.y)))}if(this.useTransmission){const e=this.transmissionNode?Ci(this.transmissionNode):Sd,t=this.thicknessNode?Ci(this.thicknessNode):Ad,r=this.attenuationDistanceNode?Ci(this.attenuationDistanceNode):Cd,s=this.attenuationColorNode?Ii(this.attenuationColorNode):Ed;if(wn.assign(e),Mn.assign(t),Bn.assign(r),Un.assign(s),this.useDispersion){const e=this.dispersionNode?Ci(this.dispersionNode):Id;Fn.assign(e)}}}setupClearcoatNormal(){return this.clearcoatNormalNode?Ii(this.clearcoatNormalNode):fd}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 rg extends vp{constructor(e,t,r,s){super(e,t,r),this.useSSS=s}direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i){if(!0===this.useSSS){const s=i.material,{thicknessColorNode:n,thicknessDistortionNode:o,thicknessAmbientNode:a,thicknessAttenuationNode:u,thicknessPowerNode:l,thicknessScaleNode:d}=s,c=e.add(al.mul(o)).normalize(),h=Ci(Zu.dot(c.negate()).saturate().pow(l).mul(d)),p=Ii(h.add(a).mul(n));r.directDiffuse.addAssign(p.mul(u.mul(t)))}super.direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i)}}class sg extends tg{static get type(){return"MeshSSSNodeMaterial"}constructor(e){super(e),this.thicknessColorNode=null,this.thicknessDistortionNode=Ci(.1),this.thicknessAmbientNode=Ci(0),this.thicknessAttenuationNode=Ci(.1),this.thicknessPowerNode=Ci(2),this.thicknessScaleNode=Ci(10)}get useSSS(){return null!==this.thicknessColorNode}setupLightingModel(){return new rg(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 ig=_i((({normal:e,lightDirection:t,builder:r})=>{const s=e.dot(t),i=Bi(s.mul(.5).add(.5),0);if(r.material.gradientMap){const e=wl("gradientMap","texture").context({getUV:()=>i});return Ii(e.r)}{const e=i.fwidth().mul(.5);return da(Ii(.7),Ii(1),ga(Ci(.7).sub(e.x),Ci(.7).add(e.x),i.x))}}));class ng extends _h{direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i){const n=ig({normal:rl,lightDirection:e,builder:i}).mul(t);r.directDiffuse.addAssign(n.mul(Rh({diffuseColor:on.rgb})))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:r}){r.indirectDiffuse.addAssign(t.mul(Rh({diffuseColor:on}))),r.indirectDiffuse.mulAssign(e)}}const og=new se;class ag extends Yc{static get type(){return"MeshToonNodeMaterial"}constructor(e){super(),this.isMeshToonNodeMaterial=!0,this.lights=!0,this.setDefaultValues(og),this.setValues(e)}setupLightingModel(){return new ng}}class ug extends Fs{static get type(){return"MatcapUVNode"}constructor(){super("vec2")}setup(){const e=Ii(Zu.z,0,Zu.x.negate()).normalize(),t=Zu.cross(e);return Bi(e.dot(al),t.dot(al)).mul(.495).add(.5)}}const lg=Ti(ug),dg=new ie;class cg extends Yc{static get type(){return"MeshMatcapNodeMaterial"}constructor(e){super(),this.lights=!1,this.isMeshMatcapNodeMaterial=!0,this.setDefaultValues(dg),this.setValues(e)}setupVariants(e){const t=lg;let r;r=e.material.matcap?wl("matcap","texture").context({getUV:()=>t}):Ii(da(.2,.8,t.y)),on.rgb.mulAssign(r.rgb)}}const hg=new P;class pg extends Yc{static get type(){return"PointsNodeMaterial"}constructor(e){super(),this.isPointsNodeMaterial=!0,this.lights=!1,this.transparent=!0,this.sizeNode=null,this.setDefaultValues(hg),this.setValues(e)}copy(e){return this.sizeNode=e.sizeNode,super.copy(e)}}class gg extends Fs{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:r}=this;if("vec2"===this.getNodeType(e)){const e=t.cos(),s=t.sin();return $i(e,s,s.negate(),e).mul(r)}{const e=t,s=Wi(Oi(1,0,0,0),Oi(0,wo(e.x),Eo(e.x).negate(),0),Oi(0,Eo(e.x),wo(e.x),0),Oi(0,0,0,1)),i=Wi(Oi(wo(e.y),0,Eo(e.y),0),Oi(0,1,0,0),Oi(Eo(e.y).negate(),0,wo(e.y),0),Oi(0,0,0,1)),n=Wi(Oi(wo(e.z),Eo(e.z).negate(),0,0),Oi(Eo(e.z),wo(e.z),0,0),Oi(0,0,1,0),Oi(0,0,0,1));return s.mul(i).mul(n).mul(Oi(r,1)).xyz}}}const mg=xi(gg),fg=new ne;class yg extends Yc{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(fg),this.setValues(e)}setupPosition({object:e,camera:t,context:r}){const s=this.sizeAttenuation,{positionNode:i,rotationNode:n,scaleNode:o}=this,a=qu;let u=$u.mul(Ii(i||0)),l=Bi(Du[0].xyz.length(),Du[1].xyz.length());if(null!==o&&(l=l.mul(o)),!s)if(t.isPerspectiveCamera)l=l.mul(u.z.negate());else{const e=Ci(2).div(Nu.element(1).element(1));l=l.mul(e.mul(2))}let d=a.xy;if(e.center&&!0===e.center.isVector2){const e=((e,t,r)=>fi(new Ga(e,t,r)))("center","vec2");d=d.sub(e.sub(.5))}d=d.mul(l);const c=Ci(n||yd),h=mg(d,c);u=Oi(u.xy.add(h),u.zw);const p=Nu.mul(u);return r.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 bg extends _h{constructor(){super(),this.shadowNode=Ci(1).toVar("shadowMask")}direct({shadowMask:e}){this.shadowNode.mulAssign(e)}finish(e){on.a.mulAssign(this.shadowNode.oneMinus()),e.outgoingLight.rgb.assign(on.rgb)}}const xg=new oe;class Tg extends Yc{static get type(){return"ShadowNodeMaterial"}constructor(e){super(),this.isShadowNodeMaterial=!0,this.lights=!0,this.setDefaultValues(xg),this.setValues(e)}setupLightingModel(){return new bg}}const _g=_i((({texture:e,uv:t})=>{const r=1e-4,s=Ii().toVar();return Si(t.x.lessThan(r),(()=>{s.assign(Ii(1,0,0))})).ElseIf(t.y.lessThan(r),(()=>{s.assign(Ii(0,1,0))})).ElseIf(t.z.lessThan(r),(()=>{s.assign(Ii(0,0,1))})).ElseIf(t.x.greaterThan(.9999),(()=>{s.assign(Ii(-1,0,0))})).ElseIf(t.y.greaterThan(.9999),(()=>{s.assign(Ii(0,-1,0))})).ElseIf(t.z.greaterThan(.9999),(()=>{s.assign(Ii(0,0,-1))})).Else((()=>{const r=.01,i=e.sample(t.add(Ii(-.01,0,0))).r.sub(e.sample(t.add(Ii(r,0,0))).r),n=e.sample(t.add(Ii(0,-.01,0))).r.sub(e.sample(t.add(Ii(0,r,0))).r),o=e.sample(t.add(Ii(0,0,-.01))).r.sub(e.sample(t.add(Ii(0,0,r))).r);s.assign(Ii(i,n,o))})),s.normalize()}));class vg extends bu{static get type(){return"Texture3DNode"}constructor(e,t=null,r=null){super(e,t,r),this.isTexture3DNode=!0}getInputType(){return"texture3D"}getDefaultUV(){return Ii(.5,.5,.5)}setUpdateMatrix(){}setupUV(e,t){return t}generateUV(e,t){return t.build(e,"vec3")}normal(e){return _g({texture:this,uv:e})}}const Ng=xi(vg);class Sg extends Yc{static get type(){return"VolumeNodeMaterial"}constructor(e={}){super(),this.lights=!1,this.isVolumeNodeMaterial=!0,this.testNode=null,this.setValues(e)}setup(e){const t=Ng(this.map,null,0),r=_i((({orig:e,dir:t})=>{const r=Ii(-.5),s=Ii(.5),i=t.reciprocal(),n=r.sub(e).mul(i),o=s.sub(e).mul(i),a=Ko(n,o),u=Xo(n,o),l=Xo(a.x,Xo(a.y,a.z)),d=Ko(u.x,Ko(u.y,u.z));return Bi(l,d)}));this.fragmentNode=_i((()=>{const e=wa(Ii(zu.mul(Oi(Eu,1)))),s=wa(ju.sub(e)).normalize(),i=Bi(r({orig:e,dir:s})).toVar();i.x.greaterThan(i.y).discard(),i.assign(Bi(Xo(i.x,0),i.y));const n=Ii(e.add(i.x.mul(s))).toVar(),o=Ii(s.abs().reciprocal()).toVar(),a=Ci(Ko(o.x,Ko(o.y,o.z))).toVar("delta");a.divAssign(wl("steps","float"));const u=Oi(wl("base","color"),0).toVar();return ic({type:"float",start:i.x,end:i.y,update:"+= delta"},(()=>{const e=sn("float","d").assign(t.sample(n.add(.5)).r);null!==this.testNode?this.testNode({map:t,mapValue:e,probe:n,finalColor:u}).append():(u.a.assign(1),nc()),n.addAssign(s.mul(a))})),u.a.equal(0).discard(),Oi(u)}))(),super.setup(e)}}class Ag{constructor(e,t){this.nodes=e,this.info=t,this._context=self,this._animationLoop=null,this._requestId=null}start(){const e=(t,r)=>{this._requestId=this._context.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,r)};e()}stop(){this._context.cancelAnimationFrame(this._requestId),this._requestId=null}setAnimationLoop(e){this._animationLoop=e}setContext(e){this._context=e}dispose(){this.stop()}}class Rg{constructor(){this.weakMap=new WeakMap}get(e){let t=this.weakMap;for(let r=0;r{this.dispose()},this.material.addEventListener("dispose",this.onMaterialDispose)}updateClipping(e){this.clippingContext=e}get clippingNeedsUpdate(){return null!==this.clippingContext&&this.clippingContext.cacheKey!==this.clippingContextCacheKey&&(this.clippingContextCacheKey=this.clippingContext.cacheKey,!0)}get hardwareClippingPlanes(){return!0===this.material.hardwareClipping?this.clippingContext.unionClippingCount: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)}getIndirect(){return this._geometries.getIndirect(this)}getChainArray(){return[this.object,this.material,this.context,this.lightsNode]}setGeometry(e){this.geometry=e,this.attributes=null}getAttributes(){if(null!==this.attributes)return this.attributes;const e=this.getNodeBuilderState().nodeAttributes,t=this.geometry,r=[],s=new Set;for(const i of e){const e=i.node&&i.node.attribute?i.node.attribute:t.getAttribute(i.name);if(void 0===e)continue;r.push(e);const n=e.isInterleavedBufferAttribute?e.data:e;s.add(n)}return this.attributes=r,this.vertexBuffers=Array.from(s.values()),r}getVertexBuffers(){return null===this.vertexBuffers&&this.getAttributes(),this.vertexBuffers}getDrawParameters(){const{object:e,material:t,geometry:r,group:s,drawRange:i}=this,n=this.drawParams||(this.drawParams={vertexCount:0,firstVertex:0,instanceCount:0,firstInstance:0}),o=this.getIndex(),a=null!==o,u=r.isInstancedBufferGeometry?r.instanceCount:e.count>1?e.count:1;if(0===u)return null;if(n.instanceCount=u,!0===e.isBatchedMesh)return n;let l=1;!0!==t.wireframe||e.isPoints||e.isLineSegments||e.isLine||e.isLineLoop||(l=2);let d=i.start*l,c=(i.start+i.count)*l;null!==s&&(d=Math.max(d,s.start*l),c=Math.min(c,(s.start+s.count)*l));const h=r.attributes.position;let p=1/0;a?p=o.count:null!=h&&(p=h.count),d=Math.max(d,0),c=Math.min(c,p);const g=c-d;return g<0||g===1/0?null:(n.vertexCount=g,n.firstVertex=d,n)}getGeometryCacheKey(){const{geometry:e}=this;let t="";for(const r of Object.keys(e.attributes).sort()){const s=e.attributes[r];t+=r+",",s.data&&(t+=s.data.stride+","),s.offset&&(t+=s.offset+","),s.itemSize&&(t+=s.itemSize+","),s.normalized&&(t+="n,")}return e.index&&(t+="index,"),t}getMaterialCacheKey(){const{object:e,material:t}=this;let r=t.customProgramCacheKey();for(const e of function(e){const t=Object.keys(e);let r=Object.getPrototypeOf(e);for(;r;){const e=Object.getOwnPropertyDescriptors(r);for(const r in e)if(void 0!==e[r]){const s=e[r];s&&"function"==typeof s.get&&t.push(r)}r=Object.getPrototypeOf(r)}return t}(t)){if(/^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test(e))continue;const s=t[e];let i;if(null!==s){const e=typeof s;"number"===e?i=0!==s?"1":"0":"object"===e?(i="{",s.isTexture&&(i+=s.mapping),i+="}"):i=String(s)}else i=String(s);r+=i+","}return r+=this.clippingContextCacheKey+",",e.geometry&&(r+=this.getGeometryCacheKey()),e.skeleton&&(r+=e.skeleton.bones.length+","),e.morphTargetInfluences&&(r+=e.morphTargetInfluences.length+","),e.isBatchedMesh&&(r+=e._matricesTexture.uuid+",",null!==e._colorsTexture&&(r+=e._colorsTexture.uuid+",")),e.count>1&&(r+=e.uuid+","),r+=e.receiveShadow+",",us(r)}get needsGeometryUpdate(){return this.geometry.id!==this.object.geometry.id}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 wg=[];class Mg{constructor(e,t,r,s,i,n){this.renderer=e,this.nodes=t,this.geometries=r,this.pipelines=s,this.bindings=i,this.info=n,this.chainMaps={}}get(e,t,r,s,i,n,o,a){const u=this.getChainMap(a);wg[0]=e,wg[1]=t,wg[2]=n,wg[3]=i;let l=u.get(wg);return void 0===l?(l=this.createRenderObject(this.nodes,this.geometries,this.renderer,e,t,r,s,i,n,o,a),u.set(wg,l)):(l.updateClipping(o),l.needsGeometryUpdate&&l.setGeometry(e.geometry),(l.version!==t.version||l.needsUpdate)&&(l.initialCacheKey!==l.getCacheKey()?(l.dispose(),l=this.get(e,t,r,s,i,n,o,a)):l.version=t.version)),l}getChainMap(e="default"){return this.chainMaps[e]||(this.chainMaps[e]=new Rg)}dispose(){this.chainMaps={}}createRenderObject(e,t,r,s,i,n,o,a,u,l,d){const c=this.getChainMap(d),h=new Eg(e,t,r,s,i,n,o,a,u,l);return h.onDispose=()=>{this.pipelines.delete(h),this.bindings.delete(h),this.nodes.delete(h),c.delete(h.getChainArray())},h}}class Bg{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 Ug=1,Fg=2,Pg=3,Ig=4,Lg=16;class Dg extends Bg{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 r=this.get(e);if(void 0===r.version)t===Ug?this.backend.createAttribute(e):t===Fg?this.backend.createIndexAttribute(e):t===Pg?this.backend.createStorageAttribute(e):t===Ig&&this.backend.createIndirectStorageAttribute(e),r.version=this._getBufferAttribute(e).version;else{const t=this._getBufferAttribute(e);(r.version=0;--t)if(e[t]>=65535)return!0;return!1}(t)?ae:ue)(t,1);return i.version=Vg(e),i}class Gg extends Bg{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 r=()=>{this.info.memory.geometries--;const s=t.index,i=e.getAttributes();null!==s&&this.attributes.delete(s);for(const e of i)this.attributes.delete(e);const n=this.wireframes.get(t);void 0!==n&&this.attributes.delete(n),t.removeEventListener("dispose",r)};t.addEventListener("dispose",r)}updateAttributes(e){const t=e.getAttributes();for(const e of t)e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute?this.updateAttribute(e,Pg):this.updateAttribute(e,Ug);const r=this.getIndex(e);null!==r&&this.updateAttribute(r,Fg);const s=e.geometry.indirect;null!==s&&this.updateAttribute(s,Ig)}updateAttribute(e,t){const r=this.info.render.calls;e.isInterleavedBufferAttribute?void 0===this.attributeCall.get(e)?(this.attributes.update(e,t),this.attributeCall.set(e,r)):this.attributeCall.get(e.data)!==r&&(this.attributes.update(e,t),this.attributeCall.set(e.data,r),this.attributeCall.set(e,r)):this.attributeCall.get(e)!==r&&(this.attributes.update(e,t),this.attributeCall.set(e,r))}getIndirect(e){return e.geometry.indirect}getIndex(e){const{geometry:t,material:r}=e;let s=t.index;if(!0===r.wireframe){const e=this.wireframes;let r=e.get(t);void 0===r?(r=Og(t),e.set(t,r)):r.version!==Vg(t)&&(this.attributes.delete(r),r=Og(t),e.set(t,r)),s=r}return s}}class kg{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,r){this.render.drawCalls++,e.isMesh||e.isSprite?this.render.triangles+=r*(t/3):e.isPoints?this.render.points+=r*t:e.isLineSegments?this.render.lines+=r*(t/2):e.isLine?this.render.lines+=r*(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 zg{constructor(e){this.cacheKey=e,this.usedTimes=0}}class $g extends zg{constructor(e,t,r){super(e),this.vertexProgram=t,this.fragmentProgram=r}}class Hg extends zg{constructor(e,t){super(e),this.computeProgram=t,this.isComputePipeline=!0}}let Wg=0;class jg{constructor(e,t,r=null,s=null){this.id=Wg++,this.code=e,this.stage=t,this.transforms=r,this.attributes=s,this.usedTimes=0}}class qg extends Bg{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:r}=this,s=this.get(e);if(this._needsComputeUpdate(e)){const i=s.pipeline;i&&(i.usedTimes--,i.computeProgram.usedTimes--);const n=this.nodes.getForCompute(e);let o=this.programs.compute.get(n.computeShader);void 0===o&&(i&&0===i.computeProgram.usedTimes&&this._releaseProgram(i.computeProgram),o=new jg(n.computeShader,"compute",n.transforms,n.nodeAttributes),this.programs.compute.set(n.computeShader,o),r.createProgram(o));const a=this._getComputeCacheKey(e,o);let u=this.caches.get(a);void 0===u&&(i&&0===i.usedTimes&&this._releasePipeline(i),u=this._getComputePipeline(e,o,a,t)),u.usedTimes++,o.usedTimes++,s.version=e.version,s.pipeline=u}return s.pipeline}getForRender(e,t=null){const{backend:r}=this,s=this.get(e);if(this._needsRenderUpdate(e)){const i=s.pipeline;i&&(i.usedTimes--,i.vertexProgram.usedTimes--,i.fragmentProgram.usedTimes--);const n=e.getNodeBuilderState();let o=this.programs.vertex.get(n.vertexShader);void 0===o&&(i&&0===i.vertexProgram.usedTimes&&this._releaseProgram(i.vertexProgram),o=new jg(n.vertexShader,"vertex"),this.programs.vertex.set(n.vertexShader,o),r.createProgram(o));let a=this.programs.fragment.get(n.fragmentShader);void 0===a&&(i&&0===i.fragmentProgram.usedTimes&&this._releaseProgram(i.fragmentProgram),a=new jg(n.fragmentShader,"fragment"),this.programs.fragment.set(n.fragmentShader,a),r.createProgram(a));const u=this._getRenderCacheKey(e,o,a);let l=this.caches.get(u);void 0===l?(i&&0===i.usedTimes&&this._releasePipeline(i),l=this._getRenderPipeline(e,o,a,u,t)):e.pipeline=l,l.usedTimes++,o.usedTimes++,a.usedTimes++,s.pipeline=l}return s.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,r,s){r=r||this._getComputeCacheKey(e,t);let i=this.caches.get(r);return void 0===i&&(i=new Hg(r,t),this.caches.set(r,i),this.backend.createComputePipeline(i,s)),i}_getRenderPipeline(e,t,r,s,i){s=s||this._getRenderCacheKey(e,t,r);let n=this.caches.get(s);return void 0===n&&(n=new $g(s,t,r),this.caches.set(s,n),e.pipeline=n,this.backend.createRenderPipeline(e,i)),n}_getComputeCacheKey(e,t){return e.id+","+t.id}_getRenderCacheKey(e,t,r){return t.id+","+r.id+","+this.backend.getRenderCacheKey(e)}_releasePipeline(e){this.caches.delete(e.cacheKey)}_releaseProgram(e){const t=e.code,r=e.stage;this.programs[r].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 Kg extends Bg{constructor(e,t,r,s,i,n){super(),this.backend=e,this.textures=r,this.pipelines=i,this.attributes=s,this.nodes=t,this.info=n,this.pipelines.bindings=this}getForRender(e){const t=e.getBindings();for(const e of t){const r=this.get(e);void 0===r.bindGroup&&(this._init(e),this.backend.createBindings(e,t,0),r.bindGroup=e)}return t}getForCompute(e){const t=this.nodes.getForCompute(e).bindings;for(const e of t){const r=this.get(e);void 0===r.bindGroup&&(this._init(e),this.backend.createBindings(e,t,0),r.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,r=e.isIndirectStorageBufferAttribute?Ig:Pg;this.attributes.update(e,r)}}_update(e,t){const{backend:r}=this;let s=!1,i=!0,n=0,o=0;for(const t of e.bindings){if(t.isNodeUniformsGroup){if(!this.nodes.updateGroup(t))continue}if(t.isUniformBuffer){t.update()&&r.updateBinding(t)}else if(t.isSampler)t.update();else if(t.isSampledTexture){const e=this.textures.get(t.texture);t.needsBindingsUpdate(e.generation)&&(s=!0);const a=t.update(),u=t.texture;a&&this.textures.updateTexture(u);const l=r.get(u);if(void 0!==l.externalTexture||e.isDefaultTexture?i=!1:(n=10*n+u.id,o+=u.version),!0===r.isWebGPUBackend&&void 0===l.texture&&void 0===l.externalTexture&&(console.error("Bindings._update: binding should be available:",t,a,u,t.textureNode.value,s),this.textures.updateTexture(u),s=!0),!0===u.isStorageTexture){const e=this.get(u);!0===t.store?e.needsMipmap=!0:this.textures.needsMipmaps(u)&&!0===e.needsMipmap&&(this.backend.generateMipmaps(u),e.needsMipmap=!1)}}}!0===s&&this.backend.updateBindings(e,t,i?n:0,o)}}function Xg(e,t){return e.groupOrder!==t.groupOrder?e.groupOrder-t.groupOrder:e.renderOrder!==t.renderOrder?e.renderOrder-t.renderOrder:e.material.id!==t.material.id?e.material.id-t.material.id:e.z!==t.z?e.z-t.z:e.id-t.id}function Yg(e,t){return e.groupOrder!==t.groupOrder?e.groupOrder-t.groupOrder:e.renderOrder!==t.renderOrder?e.renderOrder-t.renderOrder:e.z!==t.z?t.z-e.z:e.id-t.id}function Qg(e){return(e.transmission>0||e.transmissionNode)&&e.side===le&&!1===e.forceSinglePass}class Zg{constructor(e,t,r){this.renderItems=[],this.renderItemsIndex=0,this.opaque=[],this.transparentDoublePass=[],this.transparent=[],this.bundles=[],this.lightsNode=e.getNode(t,r),this.lightsArray=[],this.scene=t,this.camera=r,this.occlusionQueryCount=0}begin(){return this.renderItemsIndex=0,this.opaque.length=0,this.transparentDoublePass.length=0,this.transparent.length=0,this.bundles.length=0,this.lightsArray.length=0,this.occlusionQueryCount=0,this}getNextRenderItem(e,t,r,s,i,n,o){let a=this.renderItems[this.renderItemsIndex];return void 0===a?(a={id:e.id,object:e,geometry:t,material:r,groupOrder:s,renderOrder:e.renderOrder,z:i,group:n,clippingContext:o},this.renderItems[this.renderItemsIndex]=a):(a.id=e.id,a.object=e,a.geometry=t,a.material=r,a.groupOrder=s,a.renderOrder=e.renderOrder,a.z=i,a.group=n,a.clippingContext=o),this.renderItemsIndex++,a}push(e,t,r,s,i,n,o){const a=this.getNextRenderItem(e,t,r,s,i,n,o);!0===e.occlusionTest&&this.occlusionQueryCount++,!0===r.transparent||r.transmission>0?(Qg(r)&&this.transparentDoublePass.push(a),this.transparent.push(a)):this.opaque.push(a)}unshift(e,t,r,s,i,n,o){const a=this.getNextRenderItem(e,t,r,s,i,n,o);!0===r.transparent||r.transmission>0?(Qg(r)&&this.transparentDoublePass.unshift(a),this.transparent.unshift(a)):this.opaque.unshift(a)}pushBundle(e){this.bundles.push(e)}pushLight(e){this.lightsArray.push(e)}sort(e,t){this.opaque.length>1&&this.opaque.sort(e||Xg),this.transparentDoublePass.length>1&&this.transparentDoublePass.sort(t||Yg),this.transparent.length>1&&this.transparent.sort(t||Yg)}finish(){this.lightsNode.setLights(this.lightsArray);for(let e=this.renderItemsIndex,t=this.renderItems.length;e>t,u=o.height>>t;let l=e.depthTexture||i[t];const d=!0===e.depthBuffer||!0===e.stencilBuffer;let c=!1;void 0===l&&d&&(l=new B,l.format=e.stencilBuffer?de:ce,l.type=e.stencilBuffer?he:f,l.image.width=a,l.image.height=u,i[t]=l),r.width===o.width&&o.height===r.height||(c=!0,l&&(l.needsUpdate=!0,l.image.width=a,l.image.height=u)),r.width=o.width,r.height=o.height,r.textures=n,r.depthTexture=l||null,r.depth=e.depthBuffer,r.stencil=e.stencilBuffer,r.renderTarget=e,r.sampleCount!==s&&(c=!0,l&&(l.needsUpdate=!0),r.sampleCount=s);const h={sampleCount:s};for(let e=0;e{e.removeEventListener("dispose",t);for(let e=0;e0){const s=e.image;if(void 0===s)console.warn("THREE.Renderer: Texture marked for update but image is undefined.");else if(!1===s.complete)console.warn("THREE.Renderer: Texture marked for update but image is incomplete.");else{if(e.images){const r=[];for(const t of e.images)r.push(t);t.images=r}else t.image=s;void 0!==r.isDefaultTexture&&!0!==r.isDefaultTexture||(i.createTexture(e,t),r.isDefaultTexture=!1,r.generation=e.version),!0===e.source.dataReady&&i.updateTexture(e,t),t.needsMipmaps&&0===e.mipmaps.length&&i.generateMipmaps(e)}}else i.createDefaultTexture(e),r.isDefaultTexture=!0,r.generation=e.version}if(!0!==r.initialized){r.initialized=!0,r.generation=e.version,this.info.memory.textures++;const t=()=>{e.removeEventListener("dispose",t),this._destroyTexture(e),this.info.memory.textures--};e.addEventListener("dispose",t)}r.version=e.version}getSize(e,t=im){let r=e.images?e.images[0]:e.image;return r?(void 0!==r.image&&(r=r.image),t.width=r.width||1,t.height=r.height||1,t.depth=e.isCubeTexture?6:r.depth||1):t.width=t.height=t.depth=1,t}getMipLevels(e,t,r){let s;return s=e.isCompressedTexture?e.mipmaps?e.mipmaps.length:1:Math.floor(Math.log2(Math.max(t,r)))+1,s}needsMipmaps(e){return this.isEnvironmentTexture(e)||!0===e.isCompressedTexture||e.generateMipmaps}isEnvironmentTexture(e){const t=e.mapping;return t===j||t===q||t===T||t===_}_destroyTexture(e){this.backend.destroySampler(e),this.backend.destroyTexture(e),this.delete(e)}}class om extends e{constructor(e,t,r,s=1){super(e,t,r),this.a=s}set(e,t,r,s=1){return this.a=s,super.set(e,t,r)}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)}}class am extends rn{static get type(){return"ParameterNode"}constructor(e,t=null){super(e,t),this.isParameterNode=!0}getHash(){return this.uuid}generate(){return this.name}}class um extends Ms{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 r=new mi(t);return this._currentCond=Ta(e,r),this.add(this._currentCond)}ElseIf(e,t){const r=new mi(t),s=Ta(e,r);return this._currentCond.elseNode=s,this._currentCond=s,this}Else(e){return this._currentCond.elseNode=new mi(e),this}build(e,...t){const r=Ni();vi(this);for(const t of this.nodes)t.build(e,"void");return vi(r),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 lm=xi(um);class dm extends Ms{static get type(){return"OutputStructNode"}constructor(...e){super(),this.members=e,this.isOutputStructNode=!0}setup(e){super.setup(e);const t=this.members,r=[];for(let s=0;s{const t=e.toUint().mul(747796405).add(2891336453),r=t.shiftRight(t.shiftRight(28).add(4)).bitXor(t).mul(277803737);return r.shiftRight(22).bitXor(r).toFloat().mul(1/2**32)})),fm=(e,t)=>sa(kn(4,e.mul(Gn(1,e))),t),ym=_i((([e])=>e.fract().sub(.5).abs())).setLayout({name:"tri",type:"float",inputs:[{name:"x",type:"float"}]}),bm=_i((([e])=>Ii(ym(e.z.add(ym(e.y.mul(1)))),ym(e.z.add(ym(e.x.mul(1)))),ym(e.y.add(ym(e.x.mul(1))))))).setLayout({name:"tri3",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),xm=_i((([e,t,r])=>{const s=Ii(e).toVar(),i=Ci(1.4).toVar(),n=Ci(0).toVar(),o=Ii(s).toVar();return ic({start:Ci(0),end:Ci(3),type:"float",condition:"<="},(()=>{const e=Ii(bm(o.mul(2))).toVar();s.addAssign(e.add(r.mul(Ci(.1).mul(t)))),o.mulAssign(1.8),i.mulAssign(1.5),s.mulAssign(1.2);const a=Ci(ym(s.z.add(ym(s.x.add(ym(s.y)))))).toVar();n.addAssign(a.div(i)),o.addAssign(.14)})),n})).setLayout({name:"triNoise3D",type:"float",inputs:[{name:"position",type:"vec3"},{name:"speed",type:"float"},{name:"time",type:"float"}]});class Tm extends Ms{static get type(){return"FunctionOverloadingNode"}constructor(e=[],...t){super(),this.functionNodes=e,this.parametersNodes=t,this._candidateFnCall=null,this.global=!0}getNodeType(){return this.functionNodes[0].shaderNode.layout.type}setup(e){const t=this.parametersNodes;let r=this._candidateFnCall;if(null===r){let s=null,i=-1;for(const r of this.functionNodes){const n=r.shaderNode.layout;if(null===n)throw new Error("FunctionOverloadingNode: FunctionNode must be a layout.");const o=n.inputs;if(t.length===o.length){let n=0;for(let r=0;ri&&(s=r,i=n)}}this._candidateFnCall=r=s(...t)}return r}}const _m=xi(Tm),vm=e=>(...t)=>_m(e,...t),Nm=tn(0).setGroup(Zi).onRenderUpdate((e=>e.time)),Sm=tn(0).setGroup(Zi).onRenderUpdate((e=>e.deltaTime)),Am=tn(0,"uint").setGroup(Zi).onRenderUpdate((e=>e.frameId)),Rm=_i((([e,t,r=Bi(.5)])=>mg(e.sub(r),t).add(r))),Cm=_i((([e,t,r=Bi(.5)])=>{const s=e.sub(r),i=s.dot(s),n=i.mul(i).mul(t);return e.add(s.mul(n))})),Em=_i((({position:e=null,horizontal:t=!0,vertical:r=!1})=>{let s;null!==e?(s=Du.toVar(),s[3][0]=e.x,s[3][1]=e.y,s[3][2]=e.z):s=Du;const i=Au.mul(s);return pi(t)&&(i[0][0]=Du[0].length(),i[0][1]=0,i[0][2]=0),pi(r)&&(i[1][0]=0,i[1][1]=Du[1].length(),i[1][2]=0),i[2][0]=0,i[2][1]=0,i[2][2]=1,Nu.mul(i).mul(qu)})),wm=_i((([e=null])=>{const t=$c();return $c(Ic(e)).sub(t).lessThan(0).select(xc,e)}));class Mm extends Ms{static get type(){return"SpriteSheetUVNode"}constructor(e,t=pu(),r=Ci(0)){super("vec2"),this.countNode=e,this.uvNode=t,this.frameNode=r}setup(){const{frameNode:e,uvNode:t,countNode:r}=this,{width:s,height:i}=r,n=e.mod(s.mul(i)).floor(),o=n.mod(s),a=i.sub(n.add(1).div(s).ceil()),u=r.reciprocal(),l=Bi(o,a);return t.add(l).mul(u)}}const Bm=xi(Mm);class Um extends Ms{static get type(){return"TriplanarTexturesNode"}constructor(e,t=null,r=null,s=Ci(1),i=qu,n=sl){super("vec4"),this.textureXNode=e,this.textureYNode=t,this.textureZNode=r,this.scaleNode=s,this.positionNode=i,this.normalNode=n}setup(){const{textureXNode:e,textureYNode:t,textureZNode:r,scaleNode:s,positionNode:i,normalNode:n}=this;let o=n.abs().normalize();o=o.div(o.dot(Ii(1)));const a=i.yz.mul(s),u=i.zx.mul(s),l=i.xy.mul(s),d=e.value,c=null!==t?t.value:d,h=null!==r?r.value:d,p=xu(d,a).mul(o.x),g=xu(c,u).mul(o.y),m=xu(h,l).mul(o.z);return On(p,g,m)}}const Fm=xi(Um),Pm=new me,Im=new r,Lm=new r,Dm=new r,Vm=new n,Om=new r(0,0,-1),Gm=new s,km=new r,zm=new r,$m=new s,Hm=new t,Wm=new ge,jm=xc.flipX();Wm.depthTexture=new B(1,1);let qm=!1;class Km extends bu{static get type(){return"ReflectorNode"}constructor(e={}){super(e.defaultTexture||Wm.texture,jm),this._reflectorBaseNode=e.reflector||new Xm(this,e),this._depthNode=null,this.setUpdateMatrix(!1)}get reflector(){return this._reflectorBaseNode}get target(){return this._reflectorBaseNode.target}getDepthNode(){if(null===this._depthNode){if(!0!==this._reflectorBaseNode.depth)throw new Error("THREE.ReflectorNode: Depth node can only be requested when the reflector is created with { depth: true }. ");this._depthNode=fi(new Km({defaultTexture:Wm.depthTexture,reflector:this._reflectorBaseNode}))}return this._depthNode}setup(e){return e.object.isQuadMesh||this._reflectorBaseNode.build(e),super.setup(e)}clone(){const e=new this.constructor(this.reflectorNode);return e._reflectorBaseNode=this._reflectorBaseNode,e}}class Xm extends Ms{static get type(){return"ReflectorBaseNode"}constructor(e,t={}){super();const{target:r=new fe,resolution:s=1,generateMipmaps:i=!1,bounces:n=!0,depth:o=!1}=t;this.textureNode=e,this.target=r,this.resolution=s,this.generateMipmaps=i,this.bounces=n,this.depth=o,this.updateBeforeType=n?vs.RENDER:vs.FRAME,this.virtualCameras=new WeakMap,this.renderTargets=new WeakMap}_updateResolution(e,t){const r=this.resolution;t.getDrawingBufferSize(Hm),e.setSize(Math.round(Hm.width*r),Math.round(Hm.height*r))}setup(e){return this._updateResolution(Wm,e.renderer),super.setup(e)}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 ge(0,0,{type:ye}),!0===this.generateMipmaps&&(t.texture.minFilter=be,t.texture.generateMipmaps=!0),!0===this.depth&&(t.depthTexture=new B),this.renderTargets.set(e,t)),t}updateBefore(e){if(!1===this.bounces&&qm)return;qm=!0;const{scene:t,camera:r,renderer:s,material:i}=e,{target:n}=this,o=this.getVirtualCamera(r),a=this.getRenderTarget(o);if(s.getDrawingBufferSize(Hm),this._updateResolution(a,s),Lm.setFromMatrixPosition(n.matrixWorld),Dm.setFromMatrixPosition(r.matrixWorld),Vm.extractRotation(n.matrixWorld),Im.set(0,0,1),Im.applyMatrix4(Vm),km.subVectors(Lm,Dm),km.dot(Im)>0)return;km.reflect(Im).negate(),km.add(Lm),Vm.extractRotation(r.matrixWorld),Om.set(0,0,-1),Om.applyMatrix4(Vm),Om.add(Dm),zm.subVectors(Lm,Om),zm.reflect(Im).negate(),zm.add(Lm),o.coordinateSystem=r.coordinateSystem,o.position.copy(km),o.up.set(0,1,0),o.up.applyMatrix4(Vm),o.up.reflect(Im),o.lookAt(zm),o.near=r.near,o.far=r.far,o.updateMatrixWorld(),o.projectionMatrix.copy(r.projectionMatrix),Pm.setFromNormalAndCoplanarPoint(Im,Lm),Pm.applyMatrix4(o.matrixWorldInverse),Gm.set(Pm.normal.x,Pm.normal.y,Pm.normal.z,Pm.constant);const u=o.projectionMatrix;$m.x=(Math.sign(Gm.x)+u.elements[8])/u.elements[0],$m.y=(Math.sign(Gm.y)+u.elements[9])/u.elements[5],$m.z=-1,$m.w=(1+u.elements[10])/u.elements[14],Gm.multiplyScalar(1/Gm.dot($m));u.elements[2]=Gm.x,u.elements[6]=Gm.y,u.elements[10]=s.coordinateSystem===v?Gm.z-0:Gm.z+1-0,u.elements[14]=Gm.w,this.textureNode.value=a.texture,!0===this.depth&&(this.textureNode.getDepthNode().value=a.depthTexture),i.visible=!1;const l=s.getRenderTarget(),d=s.getMRT();s.setMRT(null),s.setRenderTarget(a),s.render(t,o),s.setMRT(d),s.setRenderTarget(l),i.visible=!0,qm=!1}}const Ym=new xe(-1,1,1,-1,0,1);class Qm extends Te{constructor(e=!1){super();const t=!1===e?[0,-1,0,1,2,1]:[0,2,0,0,2,0];this.setAttribute("position",new _e([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new _e(t,2))}}const Zm=new Qm;class Jm extends k{constructor(e=null){super(Zm,e),this.camera=Ym,this.isQuadMesh=!0}renderAsync(e){return e.renderAsync(this,Ym)}render(e){e.render(this,Ym)}}const ef=new t;class tf extends bu{static get type(){return"RTTNode"}constructor(e,t=null,r=null,s={type:ye}){const i=new ge(t,r,s);super(i.texture,pu()),this.node=e,this.width=t,this.height=r,this.pixelRatio=1,this.renderTarget=i,this.textureNeedsUpdate=!0,this.autoUpdate=!0,this._rttNode=null,this._quadMesh=new Jm(new Yc),this.updateBeforeType=vs.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 r=e*this.pixelRatio,s=t*this.pixelRatio;this.renderTarget.setSize(r,s),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(ef);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 bu(this.value,this.uvNode,this.levelNode);return e.sampler=this.sampler,e.referenceNode=this,e}}const rf=(e,...t)=>fi(new tf(fi(e),...t)),sf=_i((([e,t,r],s)=>{let i;s.renderer.coordinateSystem===v?(e=Bi(e.x,e.y.oneMinus()).mul(2).sub(1),i=Oi(Ii(e,t),1)):i=Oi(Ii(e.x,e.y.oneMinus(),t).mul(2).sub(1),1);const n=Oi(r.mul(i));return n.xyz.div(n.w)})),nf=_i((([e,t])=>{const r=t.mul(Oi(e,1)),s=r.xy.div(r.w).mul(.5).add(.5).toVar();return Bi(s.x,s.y.oneMinus())})),of=_i((([e,t,r])=>{const s=mu(Tu(t)),i=Ui(e.mul(s)).toVar(),n=Tu(t,i).toVar(),o=Tu(t,i.sub(Ui(2,0))).toVar(),a=Tu(t,i.sub(Ui(1,0))).toVar(),u=Tu(t,i.add(Ui(1,0))).toVar(),l=Tu(t,i.add(Ui(2,0))).toVar(),d=Tu(t,i.add(Ui(0,2))).toVar(),c=Tu(t,i.add(Ui(0,1))).toVar(),h=Tu(t,i.sub(Ui(0,1))).toVar(),p=Tu(t,i.sub(Ui(0,2))).toVar(),g=Po(Gn(Ci(2).mul(a).sub(o),n)).toVar(),m=Po(Gn(Ci(2).mul(u).sub(l),n)).toVar(),f=Po(Gn(Ci(2).mul(c).sub(d),n)).toVar(),y=Po(Gn(Ci(2).mul(h).sub(p),n)).toVar(),b=sf(e,n,r).toVar(),x=g.lessThan(m).select(b.sub(sf(e.sub(Bi(Ci(1).div(s.x),0)),a,r)),b.negate().add(sf(e.add(Bi(Ci(1).div(s.x),0)),u,r))),T=f.lessThan(y).select(b.sub(sf(e.add(Bi(0,Ci(1).div(s.y))),c,r)),b.negate().add(sf(e.sub(Bi(0,Ci(1).div(s.y))),h,r)));return Ro(ra(x,T))}));class af extends R{constructor(e,t,r=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new r(e*t)),super(e,t),this.isStorageInstancedBufferAttribute=!0}}class uf extends ve{constructor(e,t,r=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new r(e*t)),super(e,t),this.isStorageBufferAttribute=!0}}class lf extends Bs{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.isPBO&&e.setupPBO(this.node),super.setup(e)}generate(e,t){let r;const s=e.context.assign;if(r=!1===e.isAvailable("storageBuffer")?!0!==this.node.isPBO||!0===s||!this.node.value.isInstancedBufferAttribute&&"compute"===e.shaderStage?this.node.build(e):e.generatePBO(this):super.generate(e),!0!==s){const s=this.getNodeType(e);r=e.format(r,s,t)}return r}}const df=xi(lf);class cf extends xl{static get type(){return"StorageBufferNode"}constructor(e,t=null,r=0){null===t&&(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute)&&(t=gs(e.itemSize),r=e.count),super(e,t,r),this.isStorageBufferNode=!0,this.access=Ss.READ_WRITE,this.isAtomic=!1,this.isPBO=!1,this.bufferCount=r,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 this.value.isIndirectStorageBufferAttribute?"indirectStorageBuffer":"storageBuffer"}element(e){return df(this,e)}setPBO(e){return this.isPBO=e,this}getPBO(){return this.isPBO}setAccess(e){return this.access=e,this}toReadOnly(){return this.setAccess(Ss.READ_ONLY)}setAtomic(e){return this.isAtomic=e,this}toAtomic(){return this.setAtomic(!0)}getAttributeData(){return null===this._attribute&&(this._attribute=qa(this.value),this._varying=wa(this._attribute)),{attribute:this._attribute,varying:this._varying}}getNodeType(e){if(e.isAvailable("storageBuffer")||e.isAvailable("indirectStorageBuffer"))return super.getNodeType(e);const{attribute:t}=this.getAttributeData();return t.getNodeType(e)}generate(e){if(e.isAvailable("storageBuffer")||e.isAvailable("indirectStorageBuffer"))return super.generate(e);const{attribute:t,varying:r}=this.getAttributeData(),s=r.build(e);return e.registerTransform(s,t),s}}const hf=(e,t,r)=>fi(new cf(e,t,r));class pf extends cu{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 r;return r=!0===e.hasGeometryAttribute(t)?super.generate(e):e.generateConst(this.nodeType,new s(1,1,1,1)),r}serialize(e){super.serialize(e),e.index=this.index}deserialize(e){super.deserialize(e),this.index=e.index}}class gf extends Ms{static get type(){return"PointUVNode"}constructor(){super("vec2"),this.isPointUVNode=!0}generate(){return"vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )"}}const mf=Ti(gf),ff=new Se,yf=new n;class bf extends Ms{static get type(){return"SceneNode"}constructor(e=bf.BACKGROUND_BLURRINESS,t=null){super(),this.scope=e,this.scene=t}setup(e){const t=this.scope,r=null!==this.scene?this.scene:e.scene;let s;return t===bf.BACKGROUND_BLURRINESS?s=Rl("backgroundBlurriness","float",r):t===bf.BACKGROUND_INTENSITY?s=Rl("backgroundIntensity","float",r):t===bf.BACKGROUND_ROTATION?s=tn("mat4").label("backgroundRotation").setGroup(Zi).onRenderUpdate((()=>{const e=r.background;return null!==e&&e.isTexture&&e.mapping!==Ne?(ff.copy(r.backgroundRotation),ff.x*=-1,ff.y*=-1,ff.z*=-1,yf.makeRotationFromEuler(ff)):yf.identity(),yf})):console.error("THREE.SceneNode: Unknown scope:",t),s}}bf.BACKGROUND_BLURRINESS="backgroundBlurriness",bf.BACKGROUND_INTENSITY="backgroundIntensity",bf.BACKGROUND_ROTATION="backgroundRotation";const xf=Ti(bf,bf.BACKGROUND_BLURRINESS),Tf=Ti(bf,bf.BACKGROUND_INTENSITY),_f=Ti(bf,bf.BACKGROUND_ROTATION);class vf extends bu{static get type(){return"StorageTextureNode"}constructor(e,t,r=null){super(e,t),this.storeNode=r,this.isStorageTextureNode=!0,this.access=Ss.WRITE_ONLY}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 r;return r=null!==this.storeNode?this.generateStore(e):super.generate(e,t),r}toReadWrite(){return this.setAccess(Ss.READ_WRITE)}toReadOnly(){return this.setAccess(Ss.READ_ONLY)}toWriteOnly(){return this.setAccess(Ss.WRITE_ONLY)}generateStore(e){const t=e.getNodeProperties(this),{uvNode:r,storeNode:s}=t,i=super.generate(e,"property"),n=r.build(e,"uvec2"),o=s.build(e,"vec4"),a=e.generateTextureStore(e,i,n,o);e.addLineFlowCode(a,this)}}const Nf=xi(vf);class Sf extends Al{static get type(){return"UserDataNode"}constructor(e,t,r=null){super(e,t,r),this.userData=r}updateReference(e){return this.reference=null!==this.userData?this.userData:e.object.userData,this.reference}}const Af=new WeakMap;class Rf extends Fs{static get type(){return"VelocityNode"}constructor(){super("vec2"),this.projectionMatrix=null,this.updateType=vs.OBJECT,this.updateAfterType=vs.OBJECT,this.previousModelWorldMatrix=tn(new n),this.previousProjectionMatrix=tn(new n).setGroup(Zi),this.previousCameraViewMatrix=tn(new n)}setProjectionMatrix(e){this.projectionMatrix=e}update({frameId:e,camera:t,object:r}){const s=Ef(r);this.previousModelWorldMatrix.value.copy(s);const i=Cf(t);i.frameId!==e&&(i.frameId=e,void 0===i.previousProjectionMatrix?(i.previousProjectionMatrix=new n,i.previousCameraViewMatrix=new n,i.currentProjectionMatrix=new n,i.currentCameraViewMatrix=new n,i.previousProjectionMatrix.copy(this.projectionMatrix||t.projectionMatrix),i.previousCameraViewMatrix.copy(t.matrixWorldInverse)):(i.previousProjectionMatrix.copy(i.currentProjectionMatrix),i.previousCameraViewMatrix.copy(i.currentCameraViewMatrix)),i.currentProjectionMatrix.copy(this.projectionMatrix||t.projectionMatrix),i.currentCameraViewMatrix.copy(t.matrixWorldInverse),this.previousProjectionMatrix.value.copy(i.previousProjectionMatrix),this.previousCameraViewMatrix.value.copy(i.previousCameraViewMatrix))}updateAfter({object:e}){Ef(e).copy(e.matrixWorld)}setup(){const e=null===this.projectionMatrix?Nu:tn(this.projectionMatrix),t=this.previousCameraViewMatrix.mul(this.previousModelWorldMatrix),r=e.mul($u).mul(qu),s=this.previousProjectionMatrix.mul(t).mul(Ku),i=r.xy.div(r.w),n=s.xy.div(s.w);return Gn(i,n)}}function Cf(e){let t=Af.get(e);return void 0===t&&(t={},Af.set(e,t)),t}function Ef(e,t=0){const r=Cf(e);let s=r[t];return void 0===s&&(r[t]=s=new n),s}const wf=Ti(Rf),Mf=_i((([e,t])=>Ko(1,e.oneMinus().div(t)).oneMinus())).setLayout({name:"blendBurn",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Bf=_i((([e,t])=>Ko(e.div(t.oneMinus()),1))).setLayout({name:"blendDodge",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Uf=_i((([e,t])=>e.oneMinus().mul(t.oneMinus()).oneMinus())).setLayout({name:"blendScreen",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Ff=_i((([e,t])=>da(e.mul(2).mul(t),e.oneMinus().mul(2).mul(t.oneMinus()).oneMinus(),Qo(.5,e)))).setLayout({name:"blendOverlay",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Pf=_i((([e,t])=>{const r=t.a.add(e.a.mul(t.a.oneMinus()));return Oi(t.rgb.mul(t.a).add(e.rgb.mul(e.a).mul(t.a.oneMinus())).div(r),r)})).setLayout({name:"blendColor",type:"vec4",inputs:[{name:"base",type:"vec4"},{name:"blend",type:"vec4"}]}),If=_i((([e])=>Of(e.rgb))),Lf=_i((([e,t=Ci(1)])=>t.mix(Of(e.rgb),e.rgb))),Df=_i((([e,t=Ci(1)])=>{const r=On(e.r,e.g,e.b).div(3),s=e.r.max(e.g.max(e.b)),i=s.sub(r).mul(t).mul(-3);return da(e.rgb,s,i)})),Vf=_i((([e,t=Ci(1)])=>{const r=Ii(.57735,.57735,.57735),s=t.cos();return Ii(e.rgb.mul(s).add(r.cross(e.rgb).mul(t.sin()).add(r.mul(ta(r,e.rgb).mul(s.oneMinus())))))})),Of=(e,t=Ii(u.getLuminanceCoefficients(new r)))=>ta(e,t),Gf=_i((([e,t=Ii(1),s=Ii(0),i=Ii(1),n=Ci(1),o=Ii(u.getLuminanceCoefficients(new r,Ae))])=>{const a=e.rgb.dot(Ii(o)),l=Xo(e.rgb.mul(t).add(s),0).toVar(),d=l.pow(i).toVar();return Si(l.r.greaterThan(0),(()=>{l.r.assign(d.r)})),Si(l.g.greaterThan(0),(()=>{l.g.assign(d.g)})),Si(l.b.greaterThan(0),(()=>{l.b.assign(d.b)})),l.assign(a.add(l.sub(a).mul(n))),Oi(l.rgb,e.a)}));class kf extends Fs{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 zf=xi(kf),$f=new t;class Hf extends bu{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 Wf extends Hf{static get type(){return"PassMultipleTextureNode"}constructor(e,t,r=!1){super(e,null),this.textureName=t,this.previousTexture=r}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 jf extends Fs{static get type(){return"PassNode"}constructor(e,t,r,s={}){super("vec4"),this.scope=e,this.scene=t,this.camera=r,this.options=s,this._pixelRatio=1,this._width=1,this._height=1;const i=new B;i.isRenderTargetTexture=!0,i.name="depth";const n=new ge(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:ye,...s});n.texture.name="output",n.depthTexture=i,this.renderTarget=n,this._textures={output:n.texture,depth:i},this._textureNodes={},this._linearDepthNodes={},this._viewZNodes={},this._previousTextures={},this._previousTextureNodes={},this._cameraNear=tn(0),this._cameraFar=tn(0),this._mrt=null,this.isPassNode=!0,this.updateBeforeType=vs.FRAME}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.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(),this._previousTextures[e]=t),t}toggleTexture(e){const t=this._previousTextures[e];if(void 0!==t){const r=this._textures[e],s=this.renderTarget.textures.indexOf(r);this.renderTarget.textures[s]=t,this._textures[e]=t,this._previousTextures[e]=r,this._textureNodes[e].updateTexture(),this._previousTextureNodes[e].updateTexture()}}getTextureNode(e="output"){let t=this._textureNodes[e];return void 0===t&&(t=fi(new Wf(this,e)),t.updateTexture(),this._textureNodes[e]=t),t}getPreviousTextureNode(e="output"){let t=this._previousTextureNodes[e];return void 0===t&&(void 0===this._textureNodes[e]&&this.getTextureNode(e),t=fi(new Wf(this,e,!0)),t.updateTexture(),this._previousTextureNodes[e]=t),t}getViewZNode(e="depth"){let t=this._viewZNodes[e];if(void 0===t){const r=this._cameraNear,s=this._cameraFar;this._viewZNodes[e]=t=Oc(this.getTextureNode(e),r,s)}return t}getLinearDepthNode(e="depth"){let t=this._linearDepthNodes[e];if(void 0===t){const r=this._cameraNear,s=this._cameraFar,i=this.getViewZNode(e);this._linearDepthNodes[e]=t=Dc(i,r,s)}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.scope===jf.COLOR?this.getTextureNode():this.getLinearDepthNode()}updateBefore(e){const{renderer:t}=e,{scene:r,camera:s}=this;this._pixelRatio=t.getPixelRatio();const i=t.getSize($f);this.setSize(i.width,i.height);const n=t.getRenderTarget(),o=t.getMRT();this._cameraNear.value=s.near,this._cameraFar.value=s.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(this.renderTarget),t.setMRT(this._mrt),t.render(r,s),t.setRenderTarget(n),t.setMRT(o)}setSize(e,t){this._width=e,this._height=t;const r=this._width*this._pixelRatio,s=this._height*this._pixelRatio;this.renderTarget.setSize(r,s)}setPixelRatio(e){this._pixelRatio=e,this.setSize(this._width,this._height)}dispose(){this.renderTarget.dispose()}}jf.COLOR="color",jf.DEPTH="depth";class qf extends jf{static get type(){return"ToonOutlinePassNode"}constructor(e,t,r,s,i){super(jf.COLOR,e,t),this.colorNode=r,this.thicknessNode=s,this.alphaNode=i,this._materialCache=new WeakMap}updateBefore(e){const{renderer:t}=e,r=t.getRenderObjectFunction();t.setRenderObjectFunction(((e,r,s,i,n,o,a,u)=>{if((n.isMeshToonMaterial||n.isMeshToonNodeMaterial)&&!1===n.wireframe){const l=this._getOutlineMaterial(n);t.renderObject(e,r,s,i,l,o,a,u)}t.renderObject(e,r,s,i,n,o,a,u)})),super.updateBefore(e),t.setRenderObjectFunction(r)}_createMaterial(){const e=new Yc;e.isMeshToonOutlineMaterial=!0,e.name="Toon_Outline",e.side=x;const t=sl.negate(),r=Nu.mul($u),s=Ci(1),i=r.mul(Oi(qu,1)),n=r.mul(Oi(qu.add(t),1)),o=Ro(i.sub(n));return e.vertexNode=i.add(o.mul(this.thicknessNode).mul(i.w).mul(s)),e.colorNode=Oi(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 Kf=_i((([e,t])=>e.mul(t).clamp())).setLayout({name:"linearToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),Xf=_i((([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"}]}),Yf=_i((([e,t])=>{const r=(e=(e=e.mul(t)).sub(.004).max(0)).mul(e.mul(6.2).add(.5)),s=e.mul(e.mul(6.2).add(1.7)).add(.06);return r.div(s).pow(2.2)})).setLayout({name:"cineonToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),Qf=_i((([e])=>{const t=e.mul(e.add(.0245786)).sub(90537e-9),r=e.mul(e.add(.432951).mul(.983729)).add(.238081);return t.div(r)})),Zf=_i((([e,t])=>{const r=Hi(.59719,.35458,.04823,.076,.90834,.01566,.0284,.13383,.83777),s=Hi(1.60475,-.53108,-.07367,-.10208,1.10813,-.00605,-.00327,-.07276,1.07602);return e=e.mul(t).div(.6),e=r.mul(e),e=Qf(e),(e=s.mul(e)).clamp()})).setLayout({name:"acesFilmicToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),Jf=Hi(Ii(1.6605,-.1246,-.0182),Ii(-.5876,1.1329,-.1006),Ii(-.0728,-.0083,1.1187)),ey=Hi(Ii(.6274,.0691,.0164),Ii(.3293,.9195,.088),Ii(.0433,.0113,.8956)),ty=_i((([e])=>{const t=Ii(e).toVar(),r=Ii(t.mul(t)).toVar(),s=Ii(r.mul(r)).toVar();return Ci(15.5).mul(s.mul(r)).sub(kn(40.14,s.mul(t))).add(kn(31.96,s).sub(kn(6.868,r.mul(t))).add(kn(.4298,r).add(kn(.1191,t).sub(.00232))))})),ry=_i((([e,t])=>{const r=Ii(e).toVar(),s=Hi(Ii(.856627153315983,.137318972929847,.11189821299995),Ii(.0951212405381588,.761241990602591,.0767994186031903),Ii(.0482516061458583,.101439036467562,.811302368396859)),i=Hi(Ii(1.1271005818144368,-.1413297634984383,-.14132976349843826),Ii(-.11060664309660323,1.157823702216272,-.11060664309660294),Ii(-.016493938717834573,-.016493938717834257,1.2519364065950405)),n=Ci(-12.47393),o=Ci(4.026069);return r.mulAssign(t),r.assign(ey.mul(r)),r.assign(s.mul(r)),r.assign(Xo(r,1e-10)),r.assign(_o(r)),r.assign(r.sub(n).div(o.sub(n))),r.assign(ca(r,0,1)),r.assign(ty(r)),r.assign(i.mul(r)),r.assign(sa(Xo(Ii(0),r),Ii(2.2))),r.assign(Jf.mul(r)),r.assign(ca(r,0,1)),r})).setLayout({name:"agxToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),sy=_i((([e,t])=>{const r=Ci(.76),s=Ci(.15);e=e.mul(t);const i=Ko(e.r,Ko(e.g,e.b)),n=Ta(i.lessThan(.08),i.sub(kn(6.25,i.mul(i))),.04);e.subAssign(n);const o=Xo(e.r,Xo(e.g,e.b));Si(o.lessThan(r),(()=>e));const a=Gn(1,r),u=Gn(1,a.mul(a).div(o.add(a.sub(r))));e.mulAssign(u.div(o));const l=Gn(1,zn(1,s.mul(o.sub(u)).add(1)));return da(e,Ii(u),l)})).setLayout({name:"neutralToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]});class iy extends Ms{static get type(){return"CodeNode"}constructor(e="",t=[],r=""){super("code"),this.isCodeNode=!0,this.code=e,this.includes=t,this.language=r}isGlobal(){return!0}setIncludes(e){return this.includes=e,this}getIncludes(){return this.includes}generate(e){const t=this.getIncludes(e);for(const r of t)r.build(e);const r=e.getCodeFromNode(this,this.getNodeType(e));return r.code=this.code,r.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 ny=xi(iy);class oy extends iy{static get type(){return"FunctionNode"}constructor(e="",t=[],r=""){super(e,t,r)}getNodeType(e){return this.getNodeFunction(e).type}getInputs(e){return this.getNodeFunction(e).inputs}getNodeFunction(e){const t=e.getDataFromNode(this);let r=t.nodeFunction;return void 0===r&&(r=e.parser.parseFunction(this.code),t.nodeFunction=r),r}generate(e,t){super.generate(e);const r=this.getNodeFunction(e),s=r.name,i=r.type,n=e.getCodeFromNode(this,i);""!==s&&(n.name=s);const o=e.getPropertyName(n),a=this.getNodeFunction(e).getCode(o);return n.code=a+"\n","property"===t?o:e.format(`${o}()`,i,t)}}const ay=(e,t=[],r="")=>{for(let e=0;es.call(...e);return i.functionNode=s,i};class uy extends Ms{static get type(){return"ScriptableValueNode"}constructor(e=null){super(),this._value=e,this._cache=null,this.inputType=null,this.outputType=null,this.events=new o,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:Ci()}serialize(e){super.serialize(e),null!==this.value?"ArrayBuffer"===this.inputType?e.value=bs(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?xs(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 ly=xi(uy);class dy extends Map{get(e,t=null,...r){if(this.has(e))return super.get(e);if(null!==t){const s=t(...r);return this.set(e,s),s}}}class cy{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 hy=new dy;class py extends Ms{static get type(){return"ScriptableNode"}constructor(e=null,t={}){super(),this.codeNode=e,this.parameters=t,this._local=new dy,this._output=ly(),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 r=this._outputs;return void 0===r[e]?r[e]=ly(t):r[e].value=t,this}getOutput(e){return this._outputs[e]}getParameter(e){return this.parameters[e]}setParameter(e,t){const r=this.parameters;return t&&t.isScriptableNode?(this.deleteParameter(e),r[e]=t,r[e].getDefaultOutput().events.addEventListener("refresh",this.onRefresh)):t&&t.isScriptableValueNode?(this.deleteParameter(e),r[e]=t,r[e].events.addEventListener("refresh",this.onRefresh)):void 0===r[e]?(r[e]=ly(t),r[e].events.addEventListener("refresh",this.onRefresh)):r[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 r=this.getObject()[e];if("function"==typeof r)return r(...t)}async callAsync(e,...t){const r=this.getObject()[e];if("function"==typeof r)return"AsyncFunction"===r.constructor.name?await r(...t):r(...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 cy(this),t=hy.get("THREE"),r=hy.get("TSL"),s=this.getMethod(this.codeNode),i=[e,this._local,hy,()=>this.refresh(),(e,t)=>this.setOutput(e,t),t,r];this._object=s(...i);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:Ci()}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+" };",r="var "+e+"; var output = {};\n"+this.codeNode.code+t;return this._method=new Function(...["parameters","local","global","refresh","setOutput","THREE","TSL"],r),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=[us(this.source),this.getDefaultOutputNode().getCacheKey(e)];for(const r in this.parameters)t.push(this.parameters[r].getCacheKey(e));return ls(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 gy=xi(py);class my extends Ms{static get type(){return"FogNode"}constructor(e,t){super("float"),this.isFogNode=!0,this.colorNode=e,this.factorNode=t}getViewZNode(e){let t;const r=e.context.getViewZ;return void 0!==r&&(t=r(this)),(t||Qu.z).negate()}setup(){return this.factorNode}}const fy=xi(my);class yy extends my{static get type(){return"FogRangeNode"}constructor(e,t,r){super(e,null),this.isFogRangeNode=!0,this.nearNode=t,this.farNode=r}setup(e){const t=this.getViewZNode(e);return ga(this.nearNode,this.farNode,t)}}const by=xi(yy);class xy extends my{static get type(){return"FogExp2Node"}constructor(e,t){super(e,null),this.isFogExp2Node=!0,this.densityNode=t}setup(e){const t=this.getViewZNode(e),r=this.densityNode;return r.mul(r,t,t).negate().exp().oneMinus()}}const Ty=xi(xy);let _y=null,vy=null;class Ny extends Ms{static get type(){return"RangeNode"}constructor(e=Ci(),t=Ci()){super(),this.minNode=e,this.maxNode=t}getVectorLength(e){const t=e.getTypeLength(fs(this.minNode.value)),r=e.getTypeLength(fs(this.maxNode.value));return t>r?t:r}getNodeType(e){return e.object.count>1?e.getTypeFromLength(this.getVectorLength(e)):"float"}setup(e){const t=e.object;let r=null;if(t.count>1){const i=this.minNode.value,n=this.maxNode.value,o=e.getTypeLength(fs(i)),u=e.getTypeLength(fs(n));_y=_y||new s,vy=vy||new s,_y.setScalar(0),vy.setScalar(0),1===o?_y.setScalar(i):i.isColor?_y.set(i.r,i.g,i.b,1):_y.set(i.x,i.y,i.z||0,i.w||0),1===u?vy.setScalar(n):n.isColor?vy.set(n.r,n.g,n.b,1):vy.set(n.x,n.y,n.z||0,n.w||0);const l=4,d=l*t.count,c=new Float32Array(d);for(let e=0;efi(new Ay(e,t)),Cy=Ry("numWorkgroups","uvec3"),Ey=Ry("workgroupId","uvec3"),wy=Ry("localId","uvec3"),My=Ry("subgroupSize","uint");const By=xi(class extends Ms{constructor(e){super(),this.scope=e}generate(e){const{scope:t}=this,{renderer:r}=e;!0===r.backend.isWebGLBackend?e.addFlowCode(`\t// ${t}Barrier \n`):e.addLineFlowCode(`${t}Barrier()`,this)}});class Uy extends Bs{constructor(e,t){super(e,t),this.isWorkgroupInfoElementNode=!0}generate(e,t){let r;const s=e.context.assign;if(r=super.generate(e),!0!==s){const s=this.getNodeType(e);r=e.format(r,s,t)}return r}}class Fy extends Ms{constructor(e,t,r=0){super(t),this.bufferType=t,this.bufferCount=r,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 fi(new Uy(this,e))}generate(e){return e.getScopedArray(this.name||`${this.scope}Array_${this.id}`,this.scope.toLowerCase(),this.bufferType,this.bufferCount)}}class Py extends Fs{static get type(){return"AtomicFunctionNode"}constructor(e,t,r,s=null){super("uint"),this.method=e,this.pointerNode=t,this.valueNode=r,this.storeNode=s}getInputType(e){return this.pointerNode.getNodeType(e)}getNodeType(e){return this.getInputType(e)}generate(e){const t=this.method,r=this.getNodeType(e),s=this.getInputType(e),i=this.pointerNode,n=this.valueNode,o=[];o.push(`&${i.build(e,s)}`),o.push(n.build(e,s));const a=`${e.getMethod(t,r)}( ${o.join(", ")} )`;if(null!==this.storeNode){const t=this.storeNode.build(e,s);e.addLineFlowCode(`${t} = ${a}`,this)}else e.addLineFlowCode(a,this)}}Py.ATOMIC_LOAD="atomicLoad",Py.ATOMIC_STORE="atomicStore",Py.ATOMIC_ADD="atomicAdd",Py.ATOMIC_SUB="atomicSub",Py.ATOMIC_MAX="atomicMax",Py.ATOMIC_MIN="atomicMin",Py.ATOMIC_AND="atomicAnd",Py.ATOMIC_OR="atomicOr",Py.ATOMIC_XOR="atomicXor";const Iy=xi(Py),Ly=(e,t,r,s)=>{const i=Iy(e,t,r,s);return i.append(),i};let Dy;function Vy(e){Dy=Dy||new WeakMap;let t=Dy.get(e);return void 0===t&&Dy.set(e,t={}),t}function Oy(e){const t=Vy(e);return t.shadowMatrix||(t.shadowMatrix=tn("mat4").setGroup(Zi).onRenderUpdate((()=>(!0!==e.castShadow&&e.shadow.updateMatrices(e),e.shadow.matrix))))}function Gy(e){const t=Vy(e);if(void 0===t.projectionUV){const r=Oy(e).mul(Xu);t.projectionUV=r.xyz.div(r.w)}return t.projectionUV}function ky(e){const t=Vy(e);return t.position||(t.position=tn(new r).setGroup(Zi).onRenderUpdate(((t,r)=>r.value.setFromMatrixPosition(e.matrixWorld))))}function zy(e){const t=Vy(e);return t.targetPosition||(t.targetPosition=tn(new r).setGroup(Zi).onRenderUpdate(((t,r)=>r.value.setFromMatrixPosition(e.target.matrixWorld))))}function $y(e){const t=Vy(e);return t.viewPosition||(t.viewPosition=tn(new r).setGroup(Zi).onRenderUpdate((({camera:t},s)=>{s.value=s.value||new r,s.value.setFromMatrixPosition(e.matrixWorld),s.value.applyMatrix4(t.matrixWorldInverse)})))}const Hy=e=>Au.transformDirection(ky(e).sub(zy(e))),Wy=(e,t)=>{for(const r of t)if(r.isAnalyticLightNode&&r.light.id===e)return r;return null},jy=new WeakMap;class qy extends Ms{static get type(){return"LightsNode"}constructor(){super("vec3"),this.totalDiffuseNode=Ii().toVar("totalDiffuse"),this.totalSpecularNode=Ii().toVar("totalSpecular"),this.outgoingLightNode=Ii().toVar("outgoingLight"),this._lights=[],this._lightNodes=null,this._lightNodesHash=null,this.global=!0}customCacheKey(){const e=[];for(let t=0;te.sort(((e,t)=>e.id-t.id)))(this._lights),i=e.renderer.library;for(const e of s)if(e.isNode)t.push(fi(e));else{let s=null;if(null!==r&&(s=Wy(e.id,r)),null===s){const r=i.getLightNodeClass(e.constructor);if(null===r){console.warn(`LightsNode.setupNodeLights: Light node not found for ${e.constructor.name}`);continue}let s=null;jy.has(e)?s=jy.get(e):(s=fi(new r(e)),jy.set(e,s)),t.push(s)}}this._lightNodes=t}setupLights(e,t){for(const r of t)r.build(e)}setup(e){null===this._lightNodes&&this.setupLightsNode(e);const t=e.context,r=t.lightingModel;let s=this.outgoingLightNode;if(r){const{_lightNodes:i,totalDiffuseNode:n,totalSpecularNode:o}=this;t.outgoingLight=s;const a=e.addStack();e.getDataFromNode(this).nodes=a.nodes,r.start(t,a,e),this.setupLights(e,i),r.indirect(t,a,e);const{backdrop:u,backdropAlpha:l}=t,{directDiffuse:d,directSpecular:c,indirectDiffuse:h,indirectSpecular:p}=t.reflectedLight;let g=d.add(h);null!==u&&(g=Ii(null!==l?l.mix(g,u):u),t.material.transparent=!0),n.assign(g),o.assign(c.add(p)),s.assign(n.add(o)),r.finish(t,a,e),s=s.bypass(e.removeStack())}return s}setLights(e){return this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this}getLights(){return this._lights}get hasLights(){return this._lights.length>0}}const Ky=(e=[])=>fi(new qy).setLights(e);class Xy extends Ms{static get type(){return"ShadowBaseNode"}constructor(e){super(),this.light=e,this.updateBeforeType=vs.RENDER,this.isShadowBaseNode=!0}setupShadowPosition({material:e}){Yy.assign(e.shadowPositionNode||Xu)}dispose(){this.updateBeforeType=vs.NONE}}const Yy=Ii().toVar("shadowWorldPosition"),Qy=new WeakMap,Zy=_i((([e,t,r])=>{let s=Xu.sub(e).length();return s=s.sub(t).div(r.sub(t)),s=s.saturate(),s})),Jy=e=>{let t=Qy.get(e);if(void 0===t){const r=e.isPointLight?(e=>{const t=e.shadow.camera,r=Rl("near","float",t).setGroup(Zi),s=Rl("far","float",t).setGroup(Zi),i=Uu(e);return Zy(i,r,s)})(e):null;t=new Yc,t.colorNode=Oi(0,0,0,1),t.depthNode=r,t.isShadowNodeMaterial=!0,t.name="ShadowMaterial",Qy.set(e,t)}return t},eb=_i((({depthTexture:e,shadowCoord:t})=>xu(e,t.xy).compare(t.z))),tb=_i((({depthTexture:e,shadowCoord:t,shadow:r})=>{const s=(t,r)=>xu(e,t).compare(r),i=Rl("mapSize","vec2",r).setGroup(Zi),n=Rl("radius","float",r).setGroup(Zi),o=Bi(1).div(i),a=o.x.negate().mul(n),u=o.y.negate().mul(n),l=o.x.mul(n),d=o.y.mul(n),c=a.div(2),h=u.div(2),p=l.div(2),g=d.div(2);return On(s(t.xy.add(Bi(a,u)),t.z),s(t.xy.add(Bi(0,u)),t.z),s(t.xy.add(Bi(l,u)),t.z),s(t.xy.add(Bi(c,h)),t.z),s(t.xy.add(Bi(0,h)),t.z),s(t.xy.add(Bi(p,h)),t.z),s(t.xy.add(Bi(a,0)),t.z),s(t.xy.add(Bi(c,0)),t.z),s(t.xy,t.z),s(t.xy.add(Bi(p,0)),t.z),s(t.xy.add(Bi(l,0)),t.z),s(t.xy.add(Bi(c,g)),t.z),s(t.xy.add(Bi(0,g)),t.z),s(t.xy.add(Bi(p,g)),t.z),s(t.xy.add(Bi(a,d)),t.z),s(t.xy.add(Bi(0,d)),t.z),s(t.xy.add(Bi(l,d)),t.z)).mul(1/17)})),rb=_i((({depthTexture:e,shadowCoord:t,shadow:r})=>{const s=(t,r)=>xu(e,t).compare(r),i=Rl("mapSize","vec2",r).setGroup(Zi),n=Bi(1).div(i),o=n.x,a=n.y,u=t.xy,l=Co(u.mul(i).add(.5));return u.subAssign(l.mul(n)),On(s(u,t.z),s(u.add(Bi(o,0)),t.z),s(u.add(Bi(0,a)),t.z),s(u.add(n),t.z),da(s(u.add(Bi(o.negate(),0)),t.z),s(u.add(Bi(o.mul(2),0)),t.z),l.x),da(s(u.add(Bi(o.negate(),a)),t.z),s(u.add(Bi(o.mul(2),a)),t.z),l.x),da(s(u.add(Bi(0,a.negate())),t.z),s(u.add(Bi(0,a.mul(2))),t.z),l.y),da(s(u.add(Bi(o,a.negate())),t.z),s(u.add(Bi(o,a.mul(2))),t.z),l.y),da(da(s(u.add(Bi(o.negate(),a.negate())),t.z),s(u.add(Bi(o.mul(2),a.negate())),t.z),l.x),da(s(u.add(Bi(o.negate(),a.mul(2))),t.z),s(u.add(Bi(o.mul(2),a.mul(2))),t.z),l.x),l.y)).mul(1/9)})),sb=_i((({depthTexture:e,shadowCoord:t})=>{const r=Ci(1).toVar(),s=xu(e).sample(t.xy).rg,i=Qo(t.z,s.x);return Si(i.notEqual(Ci(1)),(()=>{const e=t.z.sub(s.x),n=Xo(0,s.y.mul(s.y));let o=n.div(n.add(e.mul(e)));o=ca(Gn(o,.3).div(.95-.3)),r.assign(ca(Xo(i,o)))})),r})),ib=_i((({samples:e,radius:t,size:r,shadowPass:s})=>{const i=Ci(0).toVar(),n=Ci(0).toVar(),o=e.lessThanEqual(Ci(1)).select(Ci(0),Ci(2).div(e.sub(1))),a=e.lessThanEqual(Ci(1)).select(Ci(0),Ci(-1));ic({start:Ei(0),end:Ei(e),type:"int",condition:"<"},(({i:e})=>{const u=a.add(Ci(e).mul(o)),l=s.sample(On(_c.xy,Bi(0,u).mul(t)).div(r)).x;i.addAssign(l),n.addAssign(l.mul(l))})),i.divAssign(e),n.divAssign(e);const u=vo(n.sub(i.mul(i)));return Bi(i,u)})),nb=_i((({samples:e,radius:t,size:r,shadowPass:s})=>{const i=Ci(0).toVar(),n=Ci(0).toVar(),o=e.lessThanEqual(Ci(1)).select(Ci(0),Ci(2).div(e.sub(1))),a=e.lessThanEqual(Ci(1)).select(Ci(0),Ci(-1));ic({start:Ei(0),end:Ei(e),type:"int",condition:"<"},(({i:e})=>{const u=a.add(Ci(e).mul(o)),l=s.sample(On(_c.xy,Bi(u,0).mul(t)).div(r));i.addAssign(l.x),n.addAssign(On(l.y.mul(l.y),l.x.mul(l.x)))})),i.divAssign(e),n.divAssign(e);const u=vo(n.sub(i.mul(i)));return Bi(i,u)})),ob=[eb,tb,rb,sb],ab=new Jm;class ub extends Xy{static get type(){return"ShadowNode"}constructor(e,t=null){super(e),this.shadow=t||e.shadow,this.shadowMap=null,this.vsmShadowMapVertical=null,this.vsmShadowMapHorizontal=null,this.vsmMaterialVertical=null,this.vsmMaterialHorizontal=null,this._node=null,this.isShadowNode=!0}setupShadowFilter(e,{filterFn:t,depthTexture:r,shadowCoord:s,shadow:i}){const n=s.x.greaterThanEqual(0).and(s.x.lessThanEqual(1)).and(s.y.greaterThanEqual(0)).and(s.y.lessThanEqual(1)).and(s.z.lessThanEqual(1)),o=t({depthTexture:r,shadowCoord:s,shadow:i});return n.select(o,Ci(1))}setupShadowCoord(e,t){const{shadow:r}=this,{renderer:s}=e,i=Rl("bias","float",r).setGroup(Zi);let n,o=t;if(r.camera.isOrthographicCamera||!0!==s.logarithmicDepthBuffer)o=o.xyz.div(o.w),n=o.z,s.coordinateSystem===v&&(n=n.mul(2).sub(1));else{const e=o.w;o=o.xy.div(e);const t=Rl("near","float",r.camera).setGroup(Zi),s=Rl("far","float",r.camera).setGroup(Zi);n=Gc(e.negate(),t,s)}return o=Ii(o.x,o.y.oneMinus(),n.add(i)),o}getShadowFilterFn(e){return ob[e]}setupShadow(e){const{renderer:t}=e,{light:r,shadow:s}=this,i=t.shadowMap.type,n=new B(s.mapSize.width,s.mapSize.height);n.compareFunction=Re;const o=e.createRenderTarget(s.mapSize.width,s.mapSize.height);if(o.depthTexture=n,s.camera.updateProjectionMatrix(),i===Ce){n.compareFunction=null,this.vsmShadowMapVertical=e.createRenderTarget(s.mapSize.width,s.mapSize.height,{format:Ee,type:ye}),this.vsmShadowMapHorizontal=e.createRenderTarget(s.mapSize.width,s.mapSize.height,{format:Ee,type:ye});const t=xu(n),r=xu(this.vsmShadowMapVertical.texture),i=Rl("blurSamples","float",s).setGroup(Zi),o=Rl("radius","float",s).setGroup(Zi),a=Rl("mapSize","vec2",s).setGroup(Zi);let u=this.vsmMaterialVertical||(this.vsmMaterialVertical=new Yc);u.fragmentNode=ib({samples:i,radius:o,size:a,shadowPass:t}).context(e.getSharedContext()),u.name="VSMVertical",u=this.vsmMaterialHorizontal||(this.vsmMaterialHorizontal=new Yc),u.fragmentNode=nb({samples:i,radius:o,size:a,shadowPass:r}).context(e.getSharedContext()),u.name="VSMHorizontal"}const a=Rl("intensity","float",s).setGroup(Zi),u=Rl("normalBias","float",s).setGroup(Zi),l=Oy(r).mul(Yy.add(ul.mul(u))),d=this.setupShadowCoord(e,l),c=s.filterNode||this.getShadowFilterFn(t.shadowMap.type)||null;if(null===c)throw new Error("THREE.WebGPURenderer: Shadow map type not supported yet.");const h=i===Ce?this.vsmShadowMapHorizontal.texture:n,p=this.setupShadowFilter(e,{filterFn:c,shadowTexture:o.texture,depthTexture:h,shadowCoord:d,shadow:s}),g=xu(o.texture,d),m=da(1,p.rgb.mix(g,1),a.mul(g.a)).toVar();return this.shadowMap=o,this.shadow.map=o,m}setup(e){if(!1!==e.renderer.shadowMap.enabled)return _i((()=>{let t=this._node;return this.setupShadowPosition(e),null===t&&(this._node=t=this.setupShadow(e)),e.material.shadowNode&&console.warn('THREE.NodeMaterial: ".shadowNode" is deprecated. Use ".castShadowNode" instead.'),e.material.receivedShadowNode&&(t=e.material.receivedShadowNode(t)),t}))()}renderShadow(e){const{shadow:t,shadowMap:r,light:s}=this,{renderer:i,scene:n}=e;t.updateMatrices(s),r.setSize(t.mapSize.width,t.mapSize.height),i.render(n,t.camera)}updateShadow(e){const{shadowMap:t,light:r,shadow:s}=this,{renderer:i,scene:n,camera:o}=e,a=i.shadowMap.type,u=t.depthTexture.version;this._depthVersionCached=u;const l=n.overrideMaterial;n.overrideMaterial=Jy(r),s.camera.layers.mask=o.layers.mask;const d=i.getRenderTarget(),c=i.getRenderObjectFunction(),h=i.getMRT();i.setMRT(null),i.setRenderObjectFunction(((e,t,r,n,u,l,...d)=>{(!0===e.castShadow||e.receiveShadow&&a===Ce)&&(e.onBeforeShadow(i,e,o,s.camera,n,t.overrideMaterial,l),i.renderObject(e,t,r,n,u,l,...d),e.onAfterShadow(i,e,o,s.camera,n,t.overrideMaterial,l))})),i.setRenderTarget(t),this.renderShadow(e),i.setRenderObjectFunction(c),!0!==r.isPointLight&&a===Ce&&this.vsmPass(i),i.setRenderTarget(d),i.setMRT(h),n.overrideMaterial=l}vsmPass(e){const{shadow:t}=this;this.vsmShadowMapVertical.setSize(t.mapSize.width,t.mapSize.height),this.vsmShadowMapHorizontal.setSize(t.mapSize.width,t.mapSize.height),e.setRenderTarget(this.vsmShadowMapVertical),ab.material=this.vsmMaterialVertical,ab.render(e),e.setRenderTarget(this.vsmShadowMapHorizontal),ab.material=this.vsmMaterialHorizontal,ab.render(e)}dispose(){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),super.dispose()}updateBefore(e){const{shadow:t}=this;(t.needsUpdate||t.autoUpdate)&&(this.updateShadow(e),this.shadowMap.depthTexture.version===this._depthVersionCached&&(t.needsUpdate=!1))}}const lb=(e,t)=>fi(new ub(e,t));class db extends cc{static get type(){return"AnalyticLightNode"}constructor(t=null){super(),this.light=t,this.color=new e,this.colorNode=t&&t.colorNode||tn(this.color).setGroup(Zi),this.baseColorNode=null,this.shadowNode=null,this.shadowColorNode=null,this.isAnalyticLightNode=!0,this.updateType=vs.FRAME}customCacheKey(){return ds(this.light.id,this.light.castShadow?1:0)}getHash(){return this.light.uuid}setupShadowNode(){return lb(this.light)}setupShadow(e){const{renderer:t}=e;if(!1===t.shadowMap.enabled)return;let r=this.shadowColorNode;if(null===r){const t=this.light.shadow.shadowNode;let s;s=void 0!==t?fi(t):this.setupShadowNode(e),this.shadowNode=s,this.shadowColorNode=r=this.colorNode.mul(s),this.baseColorNode=this.colorNode}this.colorNode=r}setup(e){this.colorNode=this.baseColorNode||this.colorNode,this.light.castShadow?e.object.receiveShadow&&this.setupShadow(e):null!==this.shadowNode&&(this.shadowNode.dispose(),this.shadowNode=null,this.shadowColorNode=null)}update(){const{light:e}=this;this.color.copy(e.color).multiplyScalar(e.intensity)}}const cb=_i((e=>{const{lightDistance:t,cutoffDistance:r,decayExponent:s}=e,i=t.pow(s).max(.01).reciprocal();return r.greaterThan(0).select(i.mul(t.div(r).pow4().oneMinus().clamp().pow2()),i)})),hb=new e,pb=_i((([e,t])=>{const r=e.toVar(),s=Po(r),i=zn(1,Xo(s.x,Xo(s.y,s.z)));s.mulAssign(i),r.mulAssign(i.mul(t.mul(2).oneMinus()));const n=Bi(r.xy).toVar(),o=t.mul(1.5).oneMinus();return Si(s.z.greaterThanEqual(o),(()=>{Si(r.z.greaterThan(0),(()=>{n.x.assign(Gn(4,r.x))}))})).ElseIf(s.x.greaterThanEqual(o),(()=>{const e=Io(r.x);n.x.assign(r.z.mul(e).add(e.mul(2)))})).ElseIf(s.y.greaterThanEqual(o),(()=>{const e=Io(r.y);n.x.assign(r.x.add(e.mul(2)).add(2)),n.y.assign(r.z.mul(e).sub(2))})),Bi(.125,.25).mul(n).add(Bi(.375,.75)).flipY()})).setLayout({name:"cubeToUV",type:"vec2",inputs:[{name:"pos",type:"vec3"},{name:"texelSizeY",type:"float"}]}),gb=_i((({depthTexture:e,bd3D:t,dp:r,texelSize:s})=>xu(e,pb(t,s.y)).compare(r))),mb=_i((({depthTexture:e,bd3D:t,dp:r,texelSize:s,shadow:i})=>{const n=Rl("radius","float",i).setGroup(Zi),o=Bi(-1,1).mul(n).mul(s.y);return xu(e,pb(t.add(o.xyy),s.y)).compare(r).add(xu(e,pb(t.add(o.yyy),s.y)).compare(r)).add(xu(e,pb(t.add(o.xyx),s.y)).compare(r)).add(xu(e,pb(t.add(o.yyx),s.y)).compare(r)).add(xu(e,pb(t,s.y)).compare(r)).add(xu(e,pb(t.add(o.xxy),s.y)).compare(r)).add(xu(e,pb(t.add(o.yxy),s.y)).compare(r)).add(xu(e,pb(t.add(o.xxx),s.y)).compare(r)).add(xu(e,pb(t.add(o.yxx),s.y)).compare(r)).mul(1/9)})),fb=_i((({filterFn:e,depthTexture:t,shadowCoord:r,shadow:s})=>{const i=r.xyz.toVar(),n=i.length(),o=tn("float").setGroup(Zi).onRenderUpdate((()=>s.camera.near)),a=tn("float").setGroup(Zi).onRenderUpdate((()=>s.camera.far)),u=Rl("bias","float",s).setGroup(Zi),l=tn(s.mapSize).setGroup(Zi),d=Ci(1).toVar();return Si(n.sub(a).lessThanEqual(0).and(n.sub(o).greaterThanEqual(0)),(()=>{const r=n.sub(o).div(a.sub(o)).toVar();r.addAssign(u);const c=i.normalize(),h=Bi(1).div(l.mul(Bi(4,2)));d.assign(e({depthTexture:t,bd3D:c,dp:r,texelSize:h,shadow:s}))})),d})),yb=new s,bb=new t,xb=new t;class Tb extends ub{static get type(){return"PointShadowNode"}constructor(e,t=null){super(e,t)}getShadowFilterFn(e){return e===we?gb:mb}setupShadowCoord(e,t){return t}setupShadowFilter(e,{filterFn:t,shadowTexture:r,depthTexture:s,shadowCoord:i,shadow:n}){return fb({filterFn:t,shadowTexture:r,depthTexture:s,shadowCoord:i,shadow:n})}renderShadow(e){const{shadow:t,shadowMap:r,light:s}=this,{renderer:i,scene:n}=e,o=t.getFrameExtents();xb.copy(t.mapSize),xb.multiply(o),r.setSize(xb.width,xb.height),bb.copy(t.mapSize);const a=i.autoClear,u=i.getClearColor(hb),l=i.getClearAlpha();i.autoClear=!1,i.setClearColor(t.clearColor,t.clearAlpha),i.clear();const d=t.getViewportCount();for(let e=0;e{const n=i.context.lightingModel,o=t.sub(Qu),a=o.normalize(),u=o.length(),l=cb({lightDistance:u,cutoffDistance:r,decayExponent:s}),d=e.mul(l),c=i.context.reflectedLight;n.direct({lightDirection:a,lightColor:d,reflectedLight:c},i.stack,i)}));class vb extends db{static get type(){return"PointLightNode"}constructor(e=null){super(e),this.cutoffDistanceNode=tn(0).setGroup(Zi),this.decayExponentNode=tn(2).setGroup(Zi)}update(e){const{light:t}=this;super.update(e),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}setupShadowNode(){return((e,t)=>fi(new Tb(e,t)))(this.light)}setup(e){super.setup(e),_b({color:this.colorNode,lightViewPosition:$y(this.light),cutoffDistance:this.cutoffDistanceNode,decayExponent:this.decayExponentNode}).append()}}const Nb=_i((([e=t()])=>{const t=e.mul(2),r=t.x.floor(),s=t.y.floor();return r.add(s).mod(2).sign()})),Sb=_i((([e,t,r])=>{const s=Ci(r).toVar(),i=Ci(t).toVar(),n=Mi(e).toVar();return Ta(n,i,s)})).setLayout({name:"mx_select",type:"float",inputs:[{name:"b",type:"bool"},{name:"t",type:"float"},{name:"f",type:"float"}]}),Ab=_i((([e,t])=>{const r=Mi(t).toVar(),s=Ci(e).toVar();return Ta(r,s.negate(),s)})).setLayout({name:"mx_negate_if",type:"float",inputs:[{name:"val",type:"float"},{name:"b",type:"bool"}]}),Rb=_i((([e])=>{const t=Ci(e).toVar();return Ei(So(t))})).setLayout({name:"mx_floor",type:"int",inputs:[{name:"x",type:"float"}]}),Cb=_i((([e,t])=>{const r=Ci(e).toVar();return t.assign(Rb(r)),r.sub(Ci(t))})),Eb=vm([_i((([e,t,r,s,i,n])=>{const o=Ci(n).toVar(),a=Ci(i).toVar(),u=Ci(s).toVar(),l=Ci(r).toVar(),d=Ci(t).toVar(),c=Ci(e).toVar(),h=Ci(Gn(1,a)).toVar();return Gn(1,o).mul(c.mul(h).add(d.mul(a))).add(o.mul(l.mul(h).add(u.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"}]}),_i((([e,t,r,s,i,n])=>{const o=Ci(n).toVar(),a=Ci(i).toVar(),u=Ii(s).toVar(),l=Ii(r).toVar(),d=Ii(t).toVar(),c=Ii(e).toVar(),h=Ci(Gn(1,a)).toVar();return Gn(1,o).mul(c.mul(h).add(d.mul(a))).add(o.mul(l.mul(h).add(u.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"}]})]),wb=vm([_i((([e,t,r,s,i,n,o,a,u,l,d])=>{const c=Ci(d).toVar(),h=Ci(l).toVar(),p=Ci(u).toVar(),g=Ci(a).toVar(),m=Ci(o).toVar(),f=Ci(n).toVar(),y=Ci(i).toVar(),b=Ci(s).toVar(),x=Ci(r).toVar(),T=Ci(t).toVar(),_=Ci(e).toVar(),v=Ci(Gn(1,p)).toVar(),N=Ci(Gn(1,h)).toVar();return Ci(Gn(1,c)).toVar().mul(N.mul(_.mul(v).add(T.mul(p))).add(h.mul(x.mul(v).add(b.mul(p))))).add(c.mul(N.mul(y.mul(v).add(f.mul(p))).add(h.mul(m.mul(v).add(g.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"}]}),_i((([e,t,r,s,i,n,o,a,u,l,d])=>{const c=Ci(d).toVar(),h=Ci(l).toVar(),p=Ci(u).toVar(),g=Ii(a).toVar(),m=Ii(o).toVar(),f=Ii(n).toVar(),y=Ii(i).toVar(),b=Ii(s).toVar(),x=Ii(r).toVar(),T=Ii(t).toVar(),_=Ii(e).toVar(),v=Ci(Gn(1,p)).toVar(),N=Ci(Gn(1,h)).toVar();return Ci(Gn(1,c)).toVar().mul(N.mul(_.mul(v).add(T.mul(p))).add(h.mul(x.mul(v).add(b.mul(p))))).add(c.mul(N.mul(y.mul(v).add(f.mul(p))).add(h.mul(m.mul(v).add(g.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"}]})]),Mb=_i((([e,t,r])=>{const s=Ci(r).toVar(),i=Ci(t).toVar(),n=wi(e).toVar(),o=wi(n.bitAnd(wi(7))).toVar(),a=Ci(Sb(o.lessThan(wi(4)),i,s)).toVar(),u=Ci(kn(2,Sb(o.lessThan(wi(4)),s,i))).toVar();return Ab(a,Mi(o.bitAnd(wi(1)))).add(Ab(u,Mi(o.bitAnd(wi(2)))))})).setLayout({name:"mx_gradient_float_0",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"}]}),Bb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ci(t).toVar(),a=wi(e).toVar(),u=wi(a.bitAnd(wi(15))).toVar(),l=Ci(Sb(u.lessThan(wi(8)),o,n)).toVar(),d=Ci(Sb(u.lessThan(wi(4)),n,Sb(u.equal(wi(12)).or(u.equal(wi(14))),o,i))).toVar();return Ab(l,Mi(u.bitAnd(wi(1)))).add(Ab(d,Mi(u.bitAnd(wi(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"}]}),Ub=vm([Mb,Bb]),Fb=_i((([e,t,r])=>{const s=Ci(r).toVar(),i=Ci(t).toVar(),n=Di(e).toVar();return Ii(Ub(n.x,i,s),Ub(n.y,i,s),Ub(n.z,i,s))})).setLayout({name:"mx_gradient_vec3_0",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"}]}),Pb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ci(t).toVar(),a=Di(e).toVar();return Ii(Ub(a.x,o,n,i),Ub(a.y,o,n,i),Ub(a.z,o,n,i))})).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"}]}),Ib=vm([Fb,Pb]),Lb=_i((([e])=>{const t=Ci(e).toVar();return kn(.6616,t)})).setLayout({name:"mx_gradient_scale2d_0",type:"float",inputs:[{name:"v",type:"float"}]}),Db=_i((([e])=>{const t=Ci(e).toVar();return kn(.982,t)})).setLayout({name:"mx_gradient_scale3d_0",type:"float",inputs:[{name:"v",type:"float"}]}),Vb=vm([Lb,_i((([e])=>{const t=Ii(e).toVar();return kn(.6616,t)})).setLayout({name:"mx_gradient_scale2d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),Ob=vm([Db,_i((([e])=>{const t=Ii(e).toVar();return kn(.982,t)})).setLayout({name:"mx_gradient_scale3d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),Gb=_i((([e,t])=>{const r=Ei(t).toVar(),s=wi(e).toVar();return s.shiftLeft(r).bitOr(s.shiftRight(Ei(32).sub(r)))})).setLayout({name:"mx_rotl32",type:"uint",inputs:[{name:"x",type:"uint"},{name:"k",type:"int"}]}),kb=_i((([e,t,r])=>{e.subAssign(r),e.bitXorAssign(Gb(r,Ei(4))),r.addAssign(t),t.subAssign(e),t.bitXorAssign(Gb(e,Ei(6))),e.addAssign(r),r.subAssign(t),r.bitXorAssign(Gb(t,Ei(8))),t.addAssign(e),e.subAssign(r),e.bitXorAssign(Gb(r,Ei(16))),r.addAssign(t),t.subAssign(e),t.bitXorAssign(Gb(e,Ei(19))),e.addAssign(r),r.subAssign(t),r.bitXorAssign(Gb(t,Ei(4))),t.addAssign(e)})),zb=_i((([e,t,r])=>{const s=wi(r).toVar(),i=wi(t).toVar(),n=wi(e).toVar();return s.bitXorAssign(i),s.subAssign(Gb(i,Ei(14))),n.bitXorAssign(s),n.subAssign(Gb(s,Ei(11))),i.bitXorAssign(n),i.subAssign(Gb(n,Ei(25))),s.bitXorAssign(i),s.subAssign(Gb(i,Ei(16))),n.bitXorAssign(s),n.subAssign(Gb(s,Ei(4))),i.bitXorAssign(n),i.subAssign(Gb(n,Ei(14))),s.bitXorAssign(i),s.subAssign(Gb(i,Ei(24))),s})).setLayout({name:"mx_bjfinal",type:"uint",inputs:[{name:"a",type:"uint"},{name:"b",type:"uint"},{name:"c",type:"uint"}]}),$b=_i((([e])=>{const t=wi(e).toVar();return Ci(t).div(Ci(wi(Ei(4294967295))))})).setLayout({name:"mx_bits_to_01",type:"float",inputs:[{name:"bits",type:"uint"}]}),Hb=_i((([e])=>{const t=Ci(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"}]}),Wb=vm([_i((([e])=>{const t=Ei(e).toVar(),r=wi(wi(1)).toVar(),s=wi(wi(Ei(3735928559)).add(r.shiftLeft(wi(2))).add(wi(13))).toVar();return zb(s.add(wi(t)),s,s)})).setLayout({name:"mx_hash_int_0",type:"uint",inputs:[{name:"x",type:"int"}]}),_i((([e,t])=>{const r=Ei(t).toVar(),s=Ei(e).toVar(),i=wi(wi(2)).toVar(),n=wi().toVar(),o=wi().toVar(),a=wi().toVar();return n.assign(o.assign(a.assign(wi(Ei(3735928559)).add(i.shiftLeft(wi(2))).add(wi(13))))),n.addAssign(wi(s)),o.addAssign(wi(r)),zb(n,o,a)})).setLayout({name:"mx_hash_int_1",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ei(t).toVar(),n=Ei(e).toVar(),o=wi(wi(3)).toVar(),a=wi().toVar(),u=wi().toVar(),l=wi().toVar();return a.assign(u.assign(l.assign(wi(Ei(3735928559)).add(o.shiftLeft(wi(2))).add(wi(13))))),a.addAssign(wi(n)),u.addAssign(wi(i)),l.addAssign(wi(s)),zb(a,u,l)})).setLayout({name:"mx_hash_int_2",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]}),_i((([e,t,r,s])=>{const i=Ei(s).toVar(),n=Ei(r).toVar(),o=Ei(t).toVar(),a=Ei(e).toVar(),u=wi(wi(4)).toVar(),l=wi().toVar(),d=wi().toVar(),c=wi().toVar();return l.assign(d.assign(c.assign(wi(Ei(3735928559)).add(u.shiftLeft(wi(2))).add(wi(13))))),l.addAssign(wi(a)),d.addAssign(wi(o)),c.addAssign(wi(n)),kb(l,d,c),l.addAssign(wi(i)),zb(l,d,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"}]}),_i((([e,t,r,s,i])=>{const n=Ei(i).toVar(),o=Ei(s).toVar(),a=Ei(r).toVar(),u=Ei(t).toVar(),l=Ei(e).toVar(),d=wi(wi(5)).toVar(),c=wi().toVar(),h=wi().toVar(),p=wi().toVar();return c.assign(h.assign(p.assign(wi(Ei(3735928559)).add(d.shiftLeft(wi(2))).add(wi(13))))),c.addAssign(wi(l)),h.addAssign(wi(u)),p.addAssign(wi(a)),kb(c,h,p),c.addAssign(wi(o)),h.addAssign(wi(n)),zb(c,h,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"}]})]),jb=vm([_i((([e,t])=>{const r=Ei(t).toVar(),s=Ei(e).toVar(),i=wi(Wb(s,r)).toVar(),n=Di().toVar();return n.x.assign(i.bitAnd(Ei(255))),n.y.assign(i.shiftRight(Ei(8)).bitAnd(Ei(255))),n.z.assign(i.shiftRight(Ei(16)).bitAnd(Ei(255))),n})).setLayout({name:"mx_hash_vec3_0",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ei(t).toVar(),n=Ei(e).toVar(),o=wi(Wb(n,i,s)).toVar(),a=Di().toVar();return a.x.assign(o.bitAnd(Ei(255))),a.y.assign(o.shiftRight(Ei(8)).bitAnd(Ei(255))),a.z.assign(o.shiftRight(Ei(16)).bitAnd(Ei(255))),a})).setLayout({name:"mx_hash_vec3_1",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]})]),qb=vm([_i((([e])=>{const t=Bi(e).toVar(),r=Ei().toVar(),s=Ei().toVar(),i=Ci(Cb(t.x,r)).toVar(),n=Ci(Cb(t.y,s)).toVar(),o=Ci(Hb(i)).toVar(),a=Ci(Hb(n)).toVar(),u=Ci(Eb(Ub(Wb(r,s),i,n),Ub(Wb(r.add(Ei(1)),s),i.sub(1),n),Ub(Wb(r,s.add(Ei(1))),i,n.sub(1)),Ub(Wb(r.add(Ei(1)),s.add(Ei(1))),i.sub(1),n.sub(1)),o,a)).toVar();return Vb(u)})).setLayout({name:"mx_perlin_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"}]}),_i((([e])=>{const t=Ii(e).toVar(),r=Ei().toVar(),s=Ei().toVar(),i=Ei().toVar(),n=Ci(Cb(t.x,r)).toVar(),o=Ci(Cb(t.y,s)).toVar(),a=Ci(Cb(t.z,i)).toVar(),u=Ci(Hb(n)).toVar(),l=Ci(Hb(o)).toVar(),d=Ci(Hb(a)).toVar(),c=Ci(wb(Ub(Wb(r,s,i),n,o,a),Ub(Wb(r.add(Ei(1)),s,i),n.sub(1),o,a),Ub(Wb(r,s.add(Ei(1)),i),n,o.sub(1),a),Ub(Wb(r.add(Ei(1)),s.add(Ei(1)),i),n.sub(1),o.sub(1),a),Ub(Wb(r,s,i.add(Ei(1))),n,o,a.sub(1)),Ub(Wb(r.add(Ei(1)),s,i.add(Ei(1))),n.sub(1),o,a.sub(1)),Ub(Wb(r,s.add(Ei(1)),i.add(Ei(1))),n,o.sub(1),a.sub(1)),Ub(Wb(r.add(Ei(1)),s.add(Ei(1)),i.add(Ei(1))),n.sub(1),o.sub(1),a.sub(1)),u,l,d)).toVar();return Ob(c)})).setLayout({name:"mx_perlin_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"}]})]),Kb=vm([_i((([e])=>{const t=Bi(e).toVar(),r=Ei().toVar(),s=Ei().toVar(),i=Ci(Cb(t.x,r)).toVar(),n=Ci(Cb(t.y,s)).toVar(),o=Ci(Hb(i)).toVar(),a=Ci(Hb(n)).toVar(),u=Ii(Eb(Ib(jb(r,s),i,n),Ib(jb(r.add(Ei(1)),s),i.sub(1),n),Ib(jb(r,s.add(Ei(1))),i,n.sub(1)),Ib(jb(r.add(Ei(1)),s.add(Ei(1))),i.sub(1),n.sub(1)),o,a)).toVar();return Vb(u)})).setLayout({name:"mx_perlin_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),_i((([e])=>{const t=Ii(e).toVar(),r=Ei().toVar(),s=Ei().toVar(),i=Ei().toVar(),n=Ci(Cb(t.x,r)).toVar(),o=Ci(Cb(t.y,s)).toVar(),a=Ci(Cb(t.z,i)).toVar(),u=Ci(Hb(n)).toVar(),l=Ci(Hb(o)).toVar(),d=Ci(Hb(a)).toVar(),c=Ii(wb(Ib(jb(r,s,i),n,o,a),Ib(jb(r.add(Ei(1)),s,i),n.sub(1),o,a),Ib(jb(r,s.add(Ei(1)),i),n,o.sub(1),a),Ib(jb(r.add(Ei(1)),s.add(Ei(1)),i),n.sub(1),o.sub(1),a),Ib(jb(r,s,i.add(Ei(1))),n,o,a.sub(1)),Ib(jb(r.add(Ei(1)),s,i.add(Ei(1))),n.sub(1),o,a.sub(1)),Ib(jb(r,s.add(Ei(1)),i.add(Ei(1))),n,o.sub(1),a.sub(1)),Ib(jb(r.add(Ei(1)),s.add(Ei(1)),i.add(Ei(1))),n.sub(1),o.sub(1),a.sub(1)),u,l,d)).toVar();return Ob(c)})).setLayout({name:"mx_perlin_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"}]})]),Xb=vm([_i((([e])=>{const t=Ci(e).toVar(),r=Ei(Rb(t)).toVar();return $b(Wb(r))})).setLayout({name:"mx_cell_noise_float_0",type:"float",inputs:[{name:"p",type:"float"}]}),_i((([e])=>{const t=Bi(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar();return $b(Wb(r,s))})).setLayout({name:"mx_cell_noise_float_1",type:"float",inputs:[{name:"p",type:"vec2"}]}),_i((([e])=>{const t=Ii(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar(),i=Ei(Rb(t.z)).toVar();return $b(Wb(r,s,i))})).setLayout({name:"mx_cell_noise_float_2",type:"float",inputs:[{name:"p",type:"vec3"}]}),_i((([e])=>{const t=Oi(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar(),i=Ei(Rb(t.z)).toVar(),n=Ei(Rb(t.w)).toVar();return $b(Wb(r,s,i,n))})).setLayout({name:"mx_cell_noise_float_3",type:"float",inputs:[{name:"p",type:"vec4"}]})]),Yb=vm([_i((([e])=>{const t=Ci(e).toVar(),r=Ei(Rb(t)).toVar();return Ii($b(Wb(r,Ei(0))),$b(Wb(r,Ei(1))),$b(Wb(r,Ei(2))))})).setLayout({name:"mx_cell_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"float"}]}),_i((([e])=>{const t=Bi(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar();return Ii($b(Wb(r,s,Ei(0))),$b(Wb(r,s,Ei(1))),$b(Wb(r,s,Ei(2))))})).setLayout({name:"mx_cell_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),_i((([e])=>{const t=Ii(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar(),i=Ei(Rb(t.z)).toVar();return Ii($b(Wb(r,s,i,Ei(0))),$b(Wb(r,s,i,Ei(1))),$b(Wb(r,s,i,Ei(2))))})).setLayout({name:"mx_cell_noise_vec3_2",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),_i((([e])=>{const t=Oi(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar(),i=Ei(Rb(t.z)).toVar(),n=Ei(Rb(t.w)).toVar();return Ii($b(Wb(r,s,i,n,Ei(0))),$b(Wb(r,s,i,n,Ei(1))),$b(Wb(r,s,i,n,Ei(2))))})).setLayout({name:"mx_cell_noise_vec3_3",type:"vec3",inputs:[{name:"p",type:"vec4"}]})]),Qb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ei(t).toVar(),a=Ii(e).toVar(),u=Ci(0).toVar(),l=Ci(1).toVar();return ic(o,(()=>{u.addAssign(l.mul(qb(a))),l.mulAssign(i),a.mulAssign(n)})),u})).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"}]}),Zb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ei(t).toVar(),a=Ii(e).toVar(),u=Ii(0).toVar(),l=Ci(1).toVar();return ic(o,(()=>{u.addAssign(l.mul(Kb(a))),l.mulAssign(i),a.mulAssign(n)})),u})).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"}]}),Jb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ei(t).toVar(),a=Ii(e).toVar();return Bi(Qb(a,o,n,i),Qb(a.add(Ii(Ei(19),Ei(193),Ei(17))),o,n,i))})).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"}]}),ex=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ei(t).toVar(),a=Ii(e).toVar(),u=Ii(Zb(a,o,n,i)).toVar(),l=Ci(Qb(a.add(Ii(Ei(19),Ei(193),Ei(17))),o,n,i)).toVar();return Oi(u,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"}]}),tx=vm([_i((([e,t,r,s,i,n,o])=>{const a=Ei(o).toVar(),u=Ci(n).toVar(),l=Ei(i).toVar(),d=Ei(s).toVar(),c=Ei(r).toVar(),h=Ei(t).toVar(),p=Bi(e).toVar(),g=Ii(Yb(Bi(h.add(d),c.add(l)))).toVar(),m=Bi(g.x,g.y).toVar();m.subAssign(.5),m.mulAssign(u),m.addAssign(.5);const f=Bi(Bi(Ci(h),Ci(c)).add(m)).toVar(),y=Bi(f.sub(p)).toVar();return Si(a.equal(Ei(2)),(()=>Po(y.x).add(Po(y.y)))),Si(a.equal(Ei(3)),(()=>Xo(Po(y.x),Po(y.y)))),ta(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"}]}),_i((([e,t,r,s,i,n,o,a,u])=>{const l=Ei(u).toVar(),d=Ci(a).toVar(),c=Ei(o).toVar(),h=Ei(n).toVar(),p=Ei(i).toVar(),g=Ei(s).toVar(),m=Ei(r).toVar(),f=Ei(t).toVar(),y=Ii(e).toVar(),b=Ii(Yb(Ii(f.add(p),m.add(h),g.add(c)))).toVar();b.subAssign(.5),b.mulAssign(d),b.addAssign(.5);const x=Ii(Ii(Ci(f),Ci(m),Ci(g)).add(b)).toVar(),T=Ii(x.sub(y)).toVar();return Si(l.equal(Ei(2)),(()=>Po(T.x).add(Po(T.y)).add(Po(T.z)))),Si(l.equal(Ei(3)),(()=>Xo(Xo(Po(T.x),Po(T.y)),Po(T.z)))),ta(T,T)})).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"}]})]),rx=_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Bi(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Bi(Cb(n.x,o),Cb(n.y,a)).toVar(),l=Ci(1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{const r=Ci(tx(u,e,t,o,a,i,s)).toVar();l.assign(Ko(l,r))}))})),Si(s.equal(Ei(0)),(()=>{l.assign(vo(l))})),l})).setLayout({name:"mx_worley_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),sx=_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Bi(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Bi(Cb(n.x,o),Cb(n.y,a)).toVar(),l=Bi(1e6,1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{const r=Ci(tx(u,e,t,o,a,i,s)).toVar();Si(r.lessThan(l.x),(()=>{l.y.assign(l.x),l.x.assign(r)})).ElseIf(r.lessThan(l.y),(()=>{l.y.assign(r)}))}))})),Si(s.equal(Ei(0)),(()=>{l.assign(vo(l))})),l})).setLayout({name:"mx_worley_noise_vec2_0",type:"vec2",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),ix=_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Bi(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Bi(Cb(n.x,o),Cb(n.y,a)).toVar(),l=Ii(1e6,1e6,1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{const r=Ci(tx(u,e,t,o,a,i,s)).toVar();Si(r.lessThan(l.x),(()=>{l.z.assign(l.y),l.y.assign(l.x),l.x.assign(r)})).ElseIf(r.lessThan(l.y),(()=>{l.z.assign(l.y),l.y.assign(r)})).ElseIf(r.lessThan(l.z),(()=>{l.z.assign(r)}))}))})),Si(s.equal(Ei(0)),(()=>{l.assign(vo(l))})),l})).setLayout({name:"mx_worley_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),nx=vm([rx,_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Ii(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Ei().toVar(),l=Ii(Cb(n.x,o),Cb(n.y,a),Cb(n.z,u)).toVar(),d=Ci(1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{ic({start:-1,end:Ei(1),name:"z",condition:"<="},(({z:r})=>{const n=Ci(tx(l,e,t,r,o,a,u,i,s)).toVar();d.assign(Ko(d,n))}))}))})),Si(s.equal(Ei(0)),(()=>{d.assign(vo(d))})),d})).setLayout({name:"mx_worley_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),ox=vm([sx,_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Ii(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Ei().toVar(),l=Ii(Cb(n.x,o),Cb(n.y,a),Cb(n.z,u)).toVar(),d=Bi(1e6,1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{ic({start:-1,end:Ei(1),name:"z",condition:"<="},(({z:r})=>{const n=Ci(tx(l,e,t,r,o,a,u,i,s)).toVar();Si(n.lessThan(d.x),(()=>{d.y.assign(d.x),d.x.assign(n)})).ElseIf(n.lessThan(d.y),(()=>{d.y.assign(n)}))}))}))})),Si(s.equal(Ei(0)),(()=>{d.assign(vo(d))})),d})).setLayout({name:"mx_worley_noise_vec2_1",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),ax=vm([ix,_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Ii(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Ei().toVar(),l=Ii(Cb(n.x,o),Cb(n.y,a),Cb(n.z,u)).toVar(),d=Ii(1e6,1e6,1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{ic({start:-1,end:Ei(1),name:"z",condition:"<="},(({z:r})=>{const n=Ci(tx(l,e,t,r,o,a,u,i,s)).toVar();Si(n.lessThan(d.x),(()=>{d.z.assign(d.y),d.y.assign(d.x),d.x.assign(n)})).ElseIf(n.lessThan(d.y),(()=>{d.z.assign(d.y),d.y.assign(n)})).ElseIf(n.lessThan(d.z),(()=>{d.z.assign(n)}))}))}))})),Si(s.equal(Ei(0)),(()=>{d.assign(vo(d))})),d})).setLayout({name:"mx_worley_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),ux=_i((([e])=>{const t=e.y,r=e.z,s=Ii().toVar();return Si(t.lessThan(1e-4),(()=>{s.assign(Ii(r,r,r))})).Else((()=>{let i=e.x;i=i.sub(So(i)).mul(6).toVar();const n=Ei($o(i)),o=i.sub(Ci(n)),a=r.mul(t.oneMinus()),u=r.mul(t.mul(o).oneMinus()),l=r.mul(t.mul(o.oneMinus()).oneMinus());Si(n.equal(Ei(0)),(()=>{s.assign(Ii(r,l,a))})).ElseIf(n.equal(Ei(1)),(()=>{s.assign(Ii(u,r,a))})).ElseIf(n.equal(Ei(2)),(()=>{s.assign(Ii(a,r,l))})).ElseIf(n.equal(Ei(3)),(()=>{s.assign(Ii(a,u,r))})).ElseIf(n.equal(Ei(4)),(()=>{s.assign(Ii(l,a,r))})).Else((()=>{s.assign(Ii(r,a,u))}))})),s})).setLayout({name:"mx_hsvtorgb",type:"vec3",inputs:[{name:"hsv",type:"vec3"}]}),lx=_i((([e])=>{const t=Ii(e).toVar(),r=Ci(t.x).toVar(),s=Ci(t.y).toVar(),i=Ci(t.z).toVar(),n=Ci(Ko(r,Ko(s,i))).toVar(),o=Ci(Xo(r,Xo(s,i))).toVar(),a=Ci(o.sub(n)).toVar(),u=Ci().toVar(),l=Ci().toVar(),d=Ci().toVar();return d.assign(o),Si(o.greaterThan(0),(()=>{l.assign(a.div(o))})).Else((()=>{l.assign(0)})),Si(l.lessThanEqual(0),(()=>{u.assign(0)})).Else((()=>{Si(r.greaterThanEqual(o),(()=>{u.assign(s.sub(i).div(a))})).ElseIf(s.greaterThanEqual(o),(()=>{u.assign(On(2,i.sub(r).div(a)))})).Else((()=>{u.assign(On(4,r.sub(s).div(a)))})),u.mulAssign(1/6),Si(u.lessThan(0),(()=>{u.addAssign(1)}))})),Ii(u,l,d)})).setLayout({name:"mx_rgbtohsv",type:"vec3",inputs:[{name:"c",type:"vec3"}]}),dx=_i((([e])=>{const t=Ii(e).toVar(),r=Vi(qn(t,Ii(.04045))).toVar(),s=Ii(t.div(12.92)).toVar(),i=Ii(sa(Xo(t.add(Ii(.055)),Ii(0)).div(1.055),Ii(2.4))).toVar();return da(s,i,r)})).setLayout({name:"mx_srgb_texture_to_lin_rec709",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),cx=(e,t)=>{e=Ci(e),t=Ci(t);const r=Bi(t.dFdx(),t.dFdy()).length().mul(.7071067811865476);return ga(e.sub(r),e.add(r),t)},hx=(e,t,r,s)=>da(e,t,r[s].clamp()),px=(e,t,r,s,i)=>da(e,t,cx(r,s[i])),gx=_i((([e,t,r])=>{const s=Ro(e).toVar("nDir"),i=Gn(Ci(.5).mul(t.sub(r)),Xu).div(s).toVar("rbmax"),n=Gn(Ci(-.5).mul(t.sub(r)),Xu).div(s).toVar("rbmin"),o=Ii().toVar("rbminmax");o.x=s.x.greaterThan(Ci(0)).select(i.x,n.x),o.y=s.y.greaterThan(Ci(0)).select(i.y,n.y),o.z=s.z.greaterThan(Ci(0)).select(i.z,n.z);const a=Ko(Ko(o.x,o.y),o.z).toVar("correction");return Xu.add(s.mul(a)).toVar("boxIntersection").sub(r)})),mx=_i((([e,t])=>{const r=e.x,s=e.y,i=e.z;let n=t.element(0).mul(.886227);return n=n.add(t.element(1).mul(1.023328).mul(s)),n=n.add(t.element(2).mul(1.023328).mul(i)),n=n.add(t.element(3).mul(1.023328).mul(r)),n=n.add(t.element(4).mul(.858086).mul(r).mul(s)),n=n.add(t.element(5).mul(.858086).mul(s).mul(i)),n=n.add(t.element(6).mul(i.mul(i).mul(.743125).sub(.247708))),n=n.add(t.element(7).mul(.858086).mul(r).mul(i)),n=n.add(t.element(8).mul(.429043).mul(kn(r,r).sub(kn(s,s)))),n}));var fx=Object.freeze({__proto__:null,BRDF_GGX:kh,BRDF_Lambert:Rh,BasicShadowFilter:eb,Break:nc,Continue:()=>au("continue").append(),DFGApprox:zh,D_GGX:Vh,Discard:uu,EPSILON:uo,F_Schlick:Ah,Fn:_i,INFINITY:lo,If:Si,Loop:ic,NodeAccess:Ss,NodeShaderStage:_s,NodeType:Ns,NodeUpdateType:vs,PCFShadowFilter:tb,PCFSoftShadowFilter:rb,PI:co,PI2:ho,Return:()=>au("return").append(),Schlick_to_F0:Hh,ScriptableNodeResources:hy,ShaderNode:mi,TBNViewMatrix:$l,VSMShadowFilter:sb,V_GGX_SmithCorrelated:Lh,abs:Po,acesFilmicToneMapping:Zf,acos:Uo,add:On,addMethodChaining:$s,addNodeElement:function(e){console.warn("THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add",e)},agxToneMapping:ry,all:po,alphaT:yn,and:Yn,anisotropy:bn,anisotropyB:Tn,anisotropyT:xn,any:go,append:Ai,arrayBuffer:e=>fi(new Gs(e,"ArrayBuffer")),asin:Bo,assign:In,atan:Fo,atan2:qo,atomicAdd:(e,t,r=null)=>Ly(Py.ATOMIC_ADD,e,t,r),atomicAnd:(e,t,r=null)=>Ly(Py.ATOMIC_AND,e,t,r),atomicFunc:Ly,atomicMax:(e,t,r=null)=>Ly(Py.ATOMIC_MAX,e,t,r),atomicMin:(e,t,r=null)=>Ly(Py.ATOMIC_MIN,e,t,r),atomicOr:(e,t,r=null)=>Ly(Py.ATOMIC_OR,e,t,r),atomicStore:(e,t,r=null)=>Ly(Py.ATOMIC_STORE,e,t,r),atomicSub:(e,t,r=null)=>Ly(Py.ATOMIC_SUB,e,t,r),atomicXor:(e,t,r=null)=>Ly(Py.ATOMIC_XOR,e,t,r),attenuationColor:Un,attenuationDistance:Bn,attribute:hu,attributeArray:(e,t="float")=>{const r=ms(t),s=new uf(e,r);return hf(s,t,e)},backgroundBlurriness:xf,backgroundIntensity:Tf,backgroundRotation:_f,batch:Jd,billboarding:Em,bitAnd:eo,bitNot:to,bitOr:ro,bitXor:so,bitangentGeometry:Dl,bitangentLocal:Vl,bitangentView:Ol,bitangentWorld:Gl,bitcast:Wo,blendBurn:Mf,blendColor:Pf,blendDodge:Bf,blendOverlay:Ff,blendScreen:Uf,blur:zp,bool:Mi,buffer:Tl,bufferAttribute:qa,bumpMap:Zl,burn:(...e)=>(console.warn('THREE.TSL: "burn" has been renamed. Use "blendBurn" instead.'),Mf(e)),bvec2:Pi,bvec3:Vi,bvec4:zi,bypass:ru,cache:eu,call:Dn,cameraFar:vu,cameraNear:_u,cameraNormalMatrix:Cu,cameraPosition:Eu,cameraProjectionMatrix:Nu,cameraProjectionMatrixInverse:Su,cameraViewMatrix:Au,cameraWorldMatrix:Ru,cbrt:ua,cdl:Gf,ceil:Ao,checker:Nb,cineonToneMapping:Yf,clamp:ca,clearcoat:dn,clearcoatRoughness:cn,code:ny,color:Ri,colorSpaceToWorking:Va,colorToDirection:e=>fi(e).mul(2).sub(1),compute:Za,cond:_a,context:Na,convert:qi,convertColorSpace:(e,t,r)=>fi(new Pa(fi(e),t,r)),convertToTexture:(e,...t)=>e.isTextureNode?e:e.isPassNode?e.getTextureNode():rf(e,...t),cos:wo,cross:ra,cubeTexture:bl,dFdx:Oo,dFdy:Go,dashSize:An,defaultBuildStages:Rs,defaultShaderStages:As,defined:pi,degrees:yo,deltaTime:Sm,densityFog:Ty,depth:zc,depthPass:(e,t)=>fi(new jf(jf.DEPTH,e,t)),difference:ea,diffuseColor:on,directPointLight:_b,directionToColor:uh,dispersion:Fn,distance:Jo,div:zn,dodge:(...e)=>(console.warn('THREE.TSL: "dodge" has been renamed. Use "blendDodge" instead.'),Bf(e)),dot:ta,drawIndex:qd,dynamicBufferAttribute:Ka,element:ji,emissive:an,equal:Hn,equals:mo,equirectUV:hh,exp:bo,exp2:xo,expression:au,faceDirection:tl,faceForward:ma,float:Ci,floor:So,fog:fy,fract:Co,frameGroup:Qi,frameId:Am,frontFacing:el,fwidth:Ho,gain:(e,t)=>e.lessThan(.5)?fm(e.mul(2),t).div(2):Gn(1,fm(kn(Gn(1,e),2),t).div(2)),gapSize:Rn,getConstNodeType:gi,getCurrentStack:Ni,getDirection:Vp,getDistanceAttenuation:cb,getGeometryRoughness:Ph,getNormalFromDepth:of,getParallaxCorrectNormal:gx,getRoughness:Ih,getScreenPosition:nf,getShIrradianceAt:mx,getTextureIndex:hm,getViewPosition:sf,glsl:(e,t)=>ny(e,t,"glsl"),glslFn:(e,t)=>ay(e,t,"glsl"),grayscale:If,greaterThan:qn,greaterThanEqual:Xn,hash:mm,highPrecisionModelNormalViewMatrix:Wu,highPrecisionModelViewMatrix:Hu,hue:Vf,instance:Xd,instanceIndex:$d,instancedArray:(e,t="float")=>{const r=ms(t),s=new af(e,r);return hf(s,t,e)},instancedBufferAttribute:Xa,instancedDynamicBufferAttribute:Ya,instancedMesh:Qd,int:Ei,inverseSqrt:No,invocationLocalIndex:jd,invocationSubgroupIndex:Wd,ior:En,iridescence:gn,iridescenceIOR:mn,iridescenceThickness:fn,ivec2:Ui,ivec3:Li,ivec4:Gi,js:(e,t)=>ny(e,t,"js"),label:Sa,length:Lo,lengthSq:la,lessThan:jn,lessThanEqual:Kn,lightPosition:ky,lightProjectionUV:Gy,lightShadowMatrix:Oy,lightTargetDirection:Hy,lightTargetPosition:zy,lightViewPosition:$y,lightingContext:gc,lights:Ky,linearDepth:$c,linearToneMapping:Kf,localId:wy,log:To,log2:_o,logarithmicDepthToViewZ:(e,t,r)=>{const s=e.mul(To(r.div(t)));return Ci(Math.E).pow(s).mul(t).negate()},loop:(...e)=>(console.warn("TSL.LoopNode: loop() has been renamed to Loop()."),ic(...e)),luminance:Of,mat2:$i,mat3:Hi,mat4:Wi,matcapUV:lg,materialAOMap:Dd,materialAlphaTest:td,materialAnisotropy:Td,materialAnisotropyVector:Vd,materialAttenuationColor:Ed,materialAttenuationDistance:Cd,materialClearcoat:gd,materialClearcoatNormal:fd,materialClearcoatRoughness:md,materialColor:rd,materialDispersion:Id,materialEmissive:id,materialIOR:Rd,materialIridescence:_d,materialIridescenceIOR:vd,materialIridescenceThickness:Nd,materialLightMap:Ld,materialLineDashOffset:Fd,materialLineDashSize:Md,materialLineGapSize:Bd,materialLineScale:wd,materialLineWidth:Ud,materialMetalness:hd,materialNormal:pd,materialOpacity:nd,materialPointWidth:Pd,materialReference:wl,materialReflectivity:dd,materialRefractionRatio:hl,materialRotation:yd,materialRoughness:cd,materialSheen:bd,materialSheenRoughness:xd,materialShininess:sd,materialSpecular:od,materialSpecularColor:ud,materialSpecularIntensity:ad,materialSpecularStrength:ld,materialThickness:Ad,materialTransmission:Sd,max:Xo,maxMipLevel:yu,metalness:ln,min:Ko,mix:da,mixElement:ya,mod:Yo,modInt:$n,modelDirection:Lu,modelNormalMatrix:ku,modelPosition:Vu,modelScale:Ou,modelViewMatrix:$u,modelViewPosition:Gu,modelViewProjection:Gd,modelWorldMatrix:Du,modelWorldMatrixInverse:zu,morphReference:dc,mrt:gm,mul:kn,mx_aastep:cx,mx_cell_noise_float:(e=pu())=>Xb(e.convert("vec2|vec3")),mx_contrast:(e,t=1,r=.5)=>Ci(e).sub(r).mul(t).add(r),mx_fractal_noise_float:(e=pu(),t=3,r=2,s=.5,i=1)=>Qb(e,Ei(t),r,s).mul(i),mx_fractal_noise_vec2:(e=pu(),t=3,r=2,s=.5,i=1)=>Jb(e,Ei(t),r,s).mul(i),mx_fractal_noise_vec3:(e=pu(),t=3,r=2,s=.5,i=1)=>Zb(e,Ei(t),r,s).mul(i),mx_fractal_noise_vec4:(e=pu(),t=3,r=2,s=.5,i=1)=>ex(e,Ei(t),r,s).mul(i),mx_hsvtorgb:ux,mx_noise_float:(e=pu(),t=1,r=0)=>qb(e.convert("vec2|vec3")).mul(t).add(r),mx_noise_vec3:(e=pu(),t=1,r=0)=>Kb(e.convert("vec2|vec3")).mul(t).add(r),mx_noise_vec4:(e=pu(),t=1,r=0)=>{e=e.convert("vec2|vec3");return Oi(Kb(e),qb(e.add(Bi(19,73)))).mul(t).add(r)},mx_ramplr:(e,t,r=pu())=>hx(e,t,r,"x"),mx_ramptb:(e,t,r=pu())=>hx(e,t,r,"y"),mx_rgbtohsv:lx,mx_safepower:(e,t=1)=>(e=Ci(e)).abs().pow(t).mul(e.sign()),mx_splitlr:(e,t,r,s=pu())=>px(e,t,r,s,"x"),mx_splittb:(e,t,r,s=pu())=>px(e,t,r,s,"y"),mx_srgb_texture_to_lin_rec709:dx,mx_transform_uv:(e=1,t=0,r=pu())=>r.mul(e).add(t),mx_worley_noise_float:(e=pu(),t=1)=>nx(e.convert("vec2|vec3"),t,Ei(1)),mx_worley_noise_vec2:(e=pu(),t=1)=>ox(e.convert("vec2|vec3"),t,Ei(1)),mx_worley_noise_vec3:(e=pu(),t=1)=>ax(e.convert("vec2|vec3"),t,Ei(1)),negate:Do,neutralToneMapping:sy,nodeArray:bi,nodeImmutable:Ti,nodeObject:fi,nodeObjects:yi,nodeProxy:xi,normalFlat:il,normalGeometry:rl,normalLocal:sl,normalMap:Kl,normalView:nl,normalWorld:ol,normalize:Ro,not:Zn,notEqual:Wn,numWorkgroups:Cy,objectDirection:Mu,objectGroup:Ji,objectPosition:Uu,objectScale:Fu,objectViewPosition:Pu,objectWorldMatrix:Bu,oneMinus:Vo,or:Qn,orthographicDepthToViewZ:(e,t,r)=>t.sub(r).mul(e).sub(t),oscSawtooth:(e=Nm)=>e.fract(),oscSine:(e=Nm)=>e.add(.75).mul(2*Math.PI).sin().mul(.5).add(.5),oscSquare:(e=Nm)=>e.fract().round(),oscTriangle:(e=Nm)=>e.add(.5).fract().mul(2).sub(1).abs(),output:Sn,outputStruct:cm,overlay:(...e)=>(console.warn('THREE.TSL: "overlay" has been renamed. Use "blendOverlay" instead.'),Ff(e)),overloadingFn:vm,parabola:fm,parallaxDirection:Hl,parallaxUV:(e,t)=>e.sub(Hl.mul(t)),parameter:(e,t)=>fi(new am(e,t)),pass:(e,t,r)=>fi(new jf(jf.COLOR,e,t,r)),passTexture:(e,t)=>fi(new Hf(e,t)),pcurve:(e,t,r)=>sa(zn(sa(e,t),On(sa(e,t),sa(Gn(1,e),r))),1/t),perspectiveDepthToViewZ:Oc,pmremTexture:qp,pointUV:mf,pointWidth:Cn,positionGeometry:ju,positionLocal:qu,positionPrevious:Ku,positionView:Qu,positionViewDirection:Zu,positionWorld:Xu,positionWorldDirection:Yu,posterize:zf,pow:sa,pow2:ia,pow3:na,pow4:oa,property:sn,radians:fo,rand:fa,range:Sy,rangeFog:by,reciprocal:zo,reference:Rl,referenceBuffer:Cl,reflect:Zo,reflectVector:ml,reflectView:pl,reflector:e=>fi(new Km(e)),refract:pa,refractVector:fl,refractView:gl,reinhardToneMapping:Xf,remainder:oo,remap:iu,remapClamp:nu,renderGroup:Zi,renderOutput:du,rendererReference:za,rotate:mg,rotateUV:Rm,roughness:un,round:ko,rtt:rf,sRGBTransferEOTF:Ma,sRGBTransferOETF:Ba,sampler:e=>(!0===e.isNode?e:xu(e)).convert("sampler"),saturate:ha,saturation:Lf,screen:(...e)=>(console.warn('THREE.TSL: "screen" has been renamed. Use "blendScreen" instead.'),Uf(e)),screenCoordinate:_c,screenSize:Tc,screenUV:xc,scriptable:gy,scriptableValue:ly,select:Ta,setCurrentStack:vi,shaderStages:Cs,shadow:lb,sharedUniformGroup:Yi,sheen:hn,sheenRoughness:pn,shiftLeft:io,shiftRight:no,shininess:Nn,sign:Io,sin:Eo,sinc:(e,t)=>Eo(co.mul(t.mul(e).sub(1))).div(co.mul(t.mul(e).sub(1))),skinning:e=>fi(new tc(e)),skinningReference:rc,smoothstep:ga,smoothstepElement:ba,specularColor:_n,specularF90:vn,spherizeUV:Cm,split:(e,t)=>fi(new Ls(fi(e),t)),spritesheetUV:Bm,sqrt:vo,stack:lm,step:Qo,storage:hf,storageBarrier:()=>By("storage").append(),storageObject:(e,t,r)=>(console.warn('THREE.TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.'),hf(e,t,r).setPBO(!0)),storageTexture:Nf,string:(e="")=>fi(new Gs(e,"string")),sub:Gn,subgroupIndex:Hd,subgroupSize:My,tan:Mo,tangentGeometry:Ml,tangentLocal:Bl,tangentView:Ul,tangentWorld:Fl,temp:Ca,texture:xu,texture3D:Ng,textureBarrier:()=>By("texture").append(),textureBicubic:up,textureCubeUV:Op,textureLoad:Tu,textureSize:mu,textureStore:(e,t,r)=>{const s=Nf(e,t,r);return null!==r&&s.append(),s},thickness:Mn,time:Nm,timerDelta:(e=1)=>(console.warn('TSL: timerDelta() is deprecated. Use "deltaTime" instead.'),Sm.mul(e)),timerGlobal:(e=1)=>(console.warn('TSL: timerGlobal() is deprecated. Use "time" instead.'),Nm.mul(e)),timerLocal:(e=1)=>(console.warn('TSL: timerLocal() is deprecated. Use "time" instead.'),Nm.mul(e)),toOutputColorSpace:Ia,toWorkingColorSpace:La,toneMapping:Ha,toneMappingExposure:Wa,toonOutlinePass:(t,r,s=new e(0,0,0),i=.003,n=1)=>fi(new qf(t,r,fi(s),fi(i),fi(n))),transformDirection:aa,transformNormal:dl,transformNormalToView:cl,transformedBentNormalView:Wl,transformedBitangentView:kl,transformedBitangentWorld:zl,transformedClearcoatNormalView:ll,transformedNormalView:al,transformedNormalWorld:ul,transformedTangentView:Pl,transformedTangentWorld:Il,transmission:wn,transpose:jo,triNoise3D:xm,triplanarTexture:(...e)=>Fm(...e),triplanarTextures:Fm,trunc:$o,tslFn:(...e)=>(console.warn("TSL.ShaderNode: tslFn() has been renamed to Fn()."),_i(...e)),uint:wi,uniform:tn,uniformArray:Nl,uniformGroup:Xi,uniforms:(e,t)=>(console.warn("TSL.UniformArrayNode: uniforms() has been renamed to uniformArray()."),fi(new vl(e,t))),userData:(e,t,r)=>fi(new Sf(e,t,r)),uv:pu,uvec2:Fi,uvec3:Di,uvec4:ki,varying:wa,varyingProperty:nn,vec2:Bi,vec3:Ii,vec4:Oi,vectorComponents:Es,velocity:wf,vertexColor:(...e)=>fi(new pf(...e)),vertexIndex:zd,vibrance:Df,viewZToLogarithmicDepth:Gc,viewZToOrthographicDepth:Dc,viewZToPerspectiveDepth:Vc,viewport:vc,viewportBottomLeft:Ec,viewportCoordinate:Sc,viewportDepthTexture:Ic,viewportLinearDepth:Hc,viewportMipTexture:Uc,viewportResolution:Rc,viewportSafeUV:wm,viewportSharedTexture:nh,viewportSize:Nc,viewportTexture:Bc,viewportTopLeft:Cc,viewportUV:Ac,wgsl:(e,t)=>ny(e,t,"wgsl"),wgslFn:(e,t)=>ay(e,t,"wgsl"),workgroupArray:(e,t)=>fi(new Fy("Workgroup",e,t)),workgroupBarrier:()=>By("workgroup").append(),workgroupId:Ey,workingToColorSpace:Da,xor:Jn});const yx=new om;class bx extends Bg{constructor(e,t){super(),this.renderer=e,this.nodes=t}update(e,t,r){const s=this.renderer,i=this.nodes.getBackgroundNode(e)||e.background;let n=!1;if(null===i)s._clearColor.getRGB(yx,Ae),yx.a=s._clearColor.a;else if(!0===i.isColor)i.getRGB(yx,Ae),yx.a=1,n=!0;else if(!0===i.isNode){const r=this.get(e),n=i;yx.copy(s._clearColor);let o=r.backgroundMesh;if(void 0===o){const e=Na(Oi(n).mul(Tf),{getUV:()=>_f.mul(ol),getTextureLevel:()=>xf});let t=Gd();t=t.setZ(t.w);const s=new Yc;s.name="Background.material",s.side=x,s.depthTest=!1,s.depthWrite=!1,s.fog=!1,s.lights=!1,s.vertexNode=t,s.colorNode=e,r.backgroundMeshNode=e,r.backgroundMesh=o=new k(new Me(1,32,32),s),o.frustumCulled=!1,o.name="Background.mesh",o.onBeforeRender=function(e,t,r){this.matrixWorld.copyPosition(r.matrixWorld)}}const a=n.getCacheKey();r.backgroundCacheKey!==a&&(r.backgroundMeshNode.node=Oi(n).mul(Tf),r.backgroundMeshNode.needsUpdate=!0,o.material.needsUpdate=!0,r.backgroundCacheKey=a),t.unshift(o,o.geometry,o.material,0,0,null,null)}else console.error("THREE.Renderer: Unsupported background configuration.",i);if(!0===s.autoClear||!0===n){const e=r.clearColorValue;e.r=yx.r,e.g=yx.g,e.b=yx.b,e.a=yx.a,!0!==s.backend.isWebGLBackend&&!0!==s.alpha||(e.r*=e.a,e.g*=e.a,e.b*=e.a),r.depthClearValue=s._clearDepth,r.stencilClearValue=s._clearStencil,r.clearColor=!0===s.autoClearColor,r.clearDepth=!0===s.autoClearDepth,r.clearStencil=!0===s.autoClearStencil}else r.clearColor=!1,r.clearDepth=!1,r.clearStencil=!1}}let xx=0;class Tx{constructor(e="",t=[],r=0,s=[]){this.name=e,this.bindings=t,this.index=r,this.bindingsReference=s,this.id=xx++}}class _x{constructor(e,t,r,s,i,n,o,a,u,l=[]){this.vertexShader=e,this.fragmentShader=t,this.computeShader=r,this.transforms=l,this.nodeAttributes=s,this.bindings=i,this.updateNodes=n,this.updateBeforeNodes=o,this.updateAfterNodes=a,this.monitor=u,this.usedTimes=0}createBindings(){const e=[];for(const t of this.bindings){if(!0!==t.bindings[0].groupNode.shared){const r=new Tx(t.name,[],t.index,t);e.push(r);for(const e of t.bindings)r.bindings.push(e.clone())}else e.push(t)}return e}}class vx{constructor(e,t,r=null){this.isNodeAttribute=!0,this.name=e,this.type=t,this.node=r}}class Nx{constructor(e,t,r){this.isNodeUniform=!0,this.name=e,this.type=t,this.node=r.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 Sx{constructor(e,t){this.isNodeVar=!0,this.name=e,this.type=t}}class Ax extends Sx{constructor(e,t){super(e,t),this.needsInterpolation=!1,this.isNodeVarying=!0}}class Rx{constructor(e,t,r=""){this.name=e,this.type=t,this.code=r,Object.defineProperty(this,"isNodeCode",{value:!0})}}let Cx=0;class Ex{constructor(e=null){this.id=Cx++,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 wx extends Ms{static get type(){return"StructTypeNode"}constructor(e,t){super(),this.name=e,this.types=t,this.isStructTypeNode=!0}getMemberTypes(){return this.types}}class Mx{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 Bx extends Mx{constructor(e,t=0){super(e,t),this.isNumberUniform=!0,this.boundary=4,this.itemSize=1}}class Ux extends Mx{constructor(e,r=new t){super(e,r),this.isVector2Uniform=!0,this.boundary=8,this.itemSize=2}}class Fx extends Mx{constructor(e,t=new r){super(e,t),this.isVector3Uniform=!0,this.boundary=16,this.itemSize=3}}class Px extends Mx{constructor(e,t=new s){super(e,t),this.isVector4Uniform=!0,this.boundary=16,this.itemSize=4}}class Ix extends Mx{constructor(t,r=new e){super(t,r),this.isColorUniform=!0,this.boundary=16,this.itemSize=3}}class Lx extends Mx{constructor(e,t=new i){super(e,t),this.isMatrix3Uniform=!0,this.boundary=48,this.itemSize=12}}class Dx extends Mx{constructor(e,t=new n){super(e,t),this.isMatrix4Uniform=!0,this.boundary=64,this.itemSize=16}}class Vx extends Bx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class Ox extends Ux{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class Gx extends Fx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class kx extends Px{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class zx extends Ix{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class $x extends Lx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class Hx extends Dx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}const Wx=[.125,.215,.35,.446,.526,.582],jx=20,qx=new xe(-1,1,1,-1,0,1),Kx=new Ue(90,1),Xx=new e;let Yx=null,Qx=0,Zx=0;const Jx=(1+Math.sqrt(5))/2,eT=1/Jx,tT=[new r(-Jx,eT,0),new r(Jx,eT,0),new r(-eT,0,Jx),new r(eT,0,Jx),new r(0,Jx,-eT),new r(0,Jx,eT),new r(-1,1,-1),new r(1,1,-1),new r(-1,1,1),new r(1,1,1)],rT=[3,1,5,0,4,2],sT=Vp(pu(),hu("faceIndex")).normalize(),iT=Ii(sT.x,sT.y,sT.z);class nT{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}get _hasInitialized(){return this._renderer.hasInitialized()}fromScene(e,t=0,r=.1,s=100,i=null){if(this._setSize(256),!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromScene() called before the backend is initialized. Try using .fromSceneAsync() instead.");const n=i||this._allocateTargets();return this.fromSceneAsync(e,t,r,s,n),n}Yx=this._renderer.getRenderTarget(),Qx=this._renderer.getActiveCubeFace(),Zx=this._renderer.getActiveMipmapLevel();const n=i||this._allocateTargets();return n.depthBuffer=!0,this._sceneToCubeUV(e,r,s,n),t>0&&this._blur(n,0,0,t),this._applyPMREM(n),this._cleanup(n),n}async fromSceneAsync(e,t=0,r=.1,s=100,i=null){return!1===this._hasInitialized&&await this._renderer.init(),this.fromScene(e,t,r,s,i)}fromEquirectangular(e,t=null){if(!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromEquirectangular() called before the backend is initialized. Try using .fromEquirectangularAsync() instead."),this._setSizeFromTexture(e);const r=t||this._allocateTargets();return this.fromEquirectangularAsync(e,r),r}return this._fromTexture(e,t)}async fromEquirectangularAsync(e,t=null){return!1===this._hasInitialized&&await this._renderer.init(),this._fromTexture(e,t)}fromCubemap(e,t=null){if(!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromCubemap() called before the backend is initialized. Try using .fromCubemapAsync() instead."),this._setSizeFromTexture(e);const r=t||this._allocateTargets();return this.fromCubemapAsync(e,t),r}return this._fromTexture(e,t)}async fromCubemapAsync(e,t=null){return!1===this._hasInitialized&&await this._renderer.init(),this._fromTexture(e,t)}async compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=lT(),await this._compileMaterial(this._cubemapMaterial))}async compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=dT(),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())}_setSizeFromTexture(e){e.mapping===T||e.mapping===_?this._setSize(0===e.image.length?16:e.image[0].width||e.image[0].image.width):this._setSize(e.image.width/4)}_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?u=Wx[a-e+4-1]:0===a&&(u=0),s.push(u);const l=1/(o-2),d=-l,c=1+l,h=[d,d,c,d,c,c,d,d,c,c,d,c],p=6,g=6,m=3,f=2,y=1,b=new Float32Array(m*g*p),x=new Float32Array(f*g*p),T=new Float32Array(y*g*p);for(let e=0;e2?0:-1,s=[t,r,0,t+2/3,r,0,t+2/3,r+1,0,t,r,0,t+2/3,r+1,0,t,r+1,0],i=rT[e];b.set(s,m*g*i),x.set(h,f*g*i);const n=[i,i,i,i,i,i];T.set(n,y*g*i)}const _=new Te;_.setAttribute("position",new ve(b,m)),_.setAttribute("uv",new ve(x,f)),_.setAttribute("faceIndex",new ve(T,y)),t.push(_),i.push(new k(_,null)),n>4&&n--}return{lodPlanes:t,sizeLods:r,sigmas:s,lodMeshes:i}}(i)),this._blurMaterial=function(e,t,s){const i=Nl(new Array(jx).fill(0)),n=tn(new r(0,1,0)),o=tn(0),a=Ci(jx),u=tn(0),l=tn(1),d=xu(null),c=tn(0),h=Ci(1/t),p=Ci(1/s),g=Ci(e),m={n:a,latitudinal:u,weights:i,poleAxis:n,outputDirection:iT,dTheta:o,samples:l,envMap:d,mipInt:c,CUBEUV_TEXEL_WIDTH:h,CUBEUV_TEXEL_HEIGHT:p,CUBEUV_MAX_MIP:g},f=uT("blur");return f.uniforms=m,f.fragmentNode=zp({...m,latitudinal:u.equal(1)}),f}(i,e,t)}return i}async _compileMaterial(e){const t=new k(this._lodPlanes[0],e);await this._renderer.compile(t,qx)}_sceneToCubeUV(e,t,r,s){const i=Kx;i.near=t,i.far=r;const n=[1,1,1,1,-1,1],o=[1,-1,1,-1,1,-1],a=this._renderer,u=a.autoClear;a.getClearColor(Xx),a.autoClear=!1;let l=this._backgroundBox;if(null===l){const e=new Q({name:"PMREM.Background",side:x,depthWrite:!1,depthTest:!1});l=new k(new G,e)}let d=!1;const c=e.background;c?c.isColor&&(l.material.color.copy(c),e.background=null,d=!0):(l.material.color.copy(Xx),d=!0),a.setRenderTarget(s),a.clear(),d&&a.render(l,i);for(let t=0;t<6;t++){const r=t%3;0===r?(i.up.set(0,n[t],0),i.lookAt(o[t],0,0)):1===r?(i.up.set(0,0,n[t]),i.lookAt(0,o[t],0)):(i.up.set(0,n[t],0),i.lookAt(0,0,o[t]));const u=this._cubeSize;aT(s,r*u,t>2?u:0,u,u),a.render(e,i)}a.autoClear=u,e.background=c}_textureToCubeUV(e,t){const r=this._renderer,s=e.mapping===T||e.mapping===_;s?null===this._cubemapMaterial&&(this._cubemapMaterial=lT(e)):null===this._equirectMaterial&&(this._equirectMaterial=dT(e));const i=s?this._cubemapMaterial:this._equirectMaterial;i.fragmentNode.value=e;const n=this._lodMeshes[0];n.material=i;const o=this._cubeSize;aT(t,0,0,3*o,2*o),r.setRenderTarget(t),r.render(n,qx)}_applyPMREM(e){const t=this._renderer,r=t.autoClear;t.autoClear=!1;const s=this._lodPlanes.length;for(let t=1;tjx&&console.warn(`sigmaRadians, ${i}, is too large and will clip, as it requested ${g} samples when the maximum is set to 20`);const m=[];let f=0;for(let e=0;ey-4?s-y+4:0),4*(this._cubeSize-b),3*b,2*b),a.setRenderTarget(t),a.render(l,qx)}}function oT(e,t,r){const s=new ge(e,t,r);return s.texture.mapping=Be,s.texture.name="PMREM.cubeUv",s.texture.isPMREMTexture=!0,s.scissorTest=!0,s}function aT(e,t,r,s,i){e.viewport.set(t,r,s,i),e.scissor.set(t,r,s,i)}function uT(e){const t=new Yc;return t.depthTest=!1,t.depthWrite=!1,t.blending=D,t.name=`PMREM_${e}`,t}function lT(e){const t=uT("cubemap");return t.fragmentNode=bl(e,iT),t}function dT(e){const t=uT("equirect");return t.fragmentNode=xu(e,hh(iT),0),t}const cT=new WeakMap,hT=new Map([[Int8Array,"int"],[Int16Array,"int"],[Int32Array,"int"],[Uint8Array,"uint"],[Uint16Array,"uint"],[Uint32Array,"uint"],[Float32Array,"float"]]),pT=e=>/e/g.test(e)?String(e).replace(/\+/g,""):(e=Number(e))+(e%1?"":".0");class gT{constructor(e,t,r){this.object=e,this.material=e&&e.material||null,this.geometry=e&&e.geometry||null,this.renderer=t,this.parser=r,this.scene=null,this.camera=null,this.nodes=[],this.sequentialNodes=[],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=lm(),this.stacks=[],this.tab="\t",this.currentFunctionNode=null,this.context={material:this.material},this.cache=new Ex,this.globalCache=this.cache,this.flowsData=new WeakMap,this.shaderStage=null,this.buildStage=null,this.useComparisonMethod=!1}getBindGroupsCache(){let e=cT.get(this.renderer);return void 0===e&&(e=new Rg,cT.set(this.renderer,e)),e}createRenderTarget(e,t,r){return new ge(e,t,r)}createCubeRenderTarget(e,t){return new ph(e,t)}createPMREMGenerator(){return new nT(this.renderer)}includes(e){return this.nodes.includes(e)}_getBindGroup(e,t){const r=this.getBindGroupsCache(),s=[];let i,n=!0;for(const e of t)s.push(e),n=n&&!0!==e.groupNode.shared;return n?(i=r.get(s),void 0===i&&(i=new Tx(e,s,this.bindingsIndexes[e].group,s),r.set(s,i))):i=new Tx(e,s,this.bindingsIndexes[e].group,s),i}getBindGroupArray(e,t){const r=this.bindings[t];let s=r[e];return void 0===s&&(void 0===this.bindingsIndexes[e]&&(this.bindingsIndexes[e]={binding:0,group:Object.keys(this.bindingsIndexes).length}),r[e]=s=[]),s}getBindings(){let e=this.bindGroups;if(null===e){const t={},r=this.bindings;for(const e of Cs)for(const s in r[e]){const i=r[e][s];(t[s]||(t[s]=[])).push(...i)}e=[];for(const r in t){const s=t[r],i=this._getBindGroup(r,s);e.push(i)}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(n)}u`:"0u";if("bool"===i)return n?"true":"false";if("color"===i)return`${this.getType("vec3")}( ${pT(n.r)}, ${pT(n.g)}, ${pT(n.b)} )`;const o=this.getTypeLength(i),a=this.getComponentType(i),u=e=>this.generateConst(a,e);if(2===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)} )`;if(3===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)}, ${u(n.z)} )`;if(4===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)}, ${u(n.z)}, ${u(n.w)} )`;if(o>4&&n&&(n.isMatrix3||n.isMatrix4))return`${this.getType(i)}( ${n.elements.map(u).join(", ")} )`;if(o>4)return`${this.getType(i)}()`;throw new Error(`NodeBuilder: Type '${i}' 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 r=this.attributes;for(const t of r)if(t.name===e)return t;const s=new vx(e,t);return r.push(s),s}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===y)return"int";if(t===f)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 r=gs(e);return("float"===t?"":t[0])+r}getTypeFromArray(e){return hT.get(e.constructor)}getTypeFromAttribute(e){let t=e;e.isInterleavedBufferAttribute&&(t=e.data);const r=t.array,s=e.itemSize,i=e.normalized;let n;return e instanceof Le||!0===i||(n=this.getTypeFromArray(r)),this.getTypeFromLength(s,n)}getTypeLength(e){const t=this.getVectorType(e),r=/vec([2-4])/.exec(t);return null!==r?Number(r[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=lm(this.stack),this.stacks.push(Ni()||this.stack),vi(this.stack),this.stack}removeStack(){const e=this.stack;return this.stack=e.parent,vi(this.stacks.pop()),e}getDataFromNode(e,t=this.shaderStage,r=null){let s=(r=null===r?e.isGlobal(this)?this.globalCache:this.cache:r).getData(e);return void 0===s&&(s={},r.setData(e,s)),void 0===s[t]&&(s[t]={}),s[t]}getNodeProperties(e,t="any"){const r=this.getDataFromNode(e,t);return r.properties||(r.properties={outputNode:null})}getBufferAttributeFromNode(e,t){const r=this.getDataFromNode(e);let s=r.bufferAttribute;if(void 0===s){const i=this.uniforms.index++;s=new vx("nodeAttribute"+i,t,e),this.bufferAttributes.push(s),r.bufferAttribute=s}return s}getStructTypeFromNode(e,t,r=this.shaderStage){const s=this.getDataFromNode(e,r);let i=s.structType;if(void 0===i){const e=this.structs.index++;i=new wx("StructType"+e,t),this.structs[r].push(i),s.structType=i}return i}getUniformFromNode(e,t,r=this.shaderStage,s=null){const i=this.getDataFromNode(e,r,this.globalCache);let n=i.uniform;if(void 0===n){const o=this.uniforms.index++;n=new Nx(s||"nodeUniform"+o,t,e),this.uniforms[r].push(n),i.uniform=n}return n}getVarFromNode(e,t=null,r=e.getNodeType(this),s=this.shaderStage){const i=this.getDataFromNode(e,s);let n=i.variable;if(void 0===n){const e=this.vars[s]||(this.vars[s]=[]);null===t&&(t="nodeVar"+e.length),n=new Sx(t,r),e.push(n),i.variable=n}return n}getVaryingFromNode(e,t=null,r=e.getNodeType(this)){const s=this.getDataFromNode(e,"any");let i=s.varying;if(void 0===i){const e=this.varyings,n=e.length;null===t&&(t="nodeVarying"+n),i=new Ax(t,r),e.push(i),s.varying=i}return i}getCodeFromNode(e,t,r=this.shaderStage){const s=this.getDataFromNode(e);let i=s.code;if(void 0===i){const e=this.codes[r]||(this.codes[r]=[]),n=e.length;i=new Rx("nodeCode"+n,t),e.push(i),s.code=i}return i}addFlowCodeHierarchy(e,t){const{flowCodes:r,flowCodeBlock:s}=this.getDataFromNode(e);let i=!0,n=t;for(;n;){if(!0===s.get(n)){i=!1;break}n=this.getDataFromNode(n).parentNodeBlock}if(i)for(const e of r)this.addLineFlowCode(e)}addLineFlowCodeBlock(e,t,r){const s=this.getDataFromNode(e),i=s.flowCodes||(s.flowCodes=[]),n=s.flowCodeBlock||(s.flowCodeBlock=new WeakMap);i.push(t),n.set(r,!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),r=this.flowChildNode(e,t);return this.flowsData.set(e,r),r}buildFunctionNode(e){const t=new oy,r=this.currentFunctionNode;return this.currentFunctionNode=t,t.code=this.buildFunctionCode(e),this.currentFunctionNode=r,t}flowShaderNode(e){const t=e.layout,r={[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)r[e.name]=new am(e.type,e.name);e.layout=null;const s=e.call(r),i=this.flowStagesNode(s,t.type);return e.layout=t,i}flowStagesNode(e,t=null){const r=this.flow,s=this.vars,i=this.cache,n=this.buildStage,o=this.stack,a={code:""};this.flow=a,this.vars={},this.cache=new Ex,this.stack=lm();for(const r of Rs)this.setBuildStage(r),a.result=e.build(this,t);return a.vars=this.getVars(this.shaderStage),this.flow=r,this.vars=s,this.cache=i,this.stack=o,this.setBuildStage(n),a}getFunctionOperator(){return null}flowChildNode(e,t=null){const r=this.flow,s={code:""};return this.flow=s,s.result=e.build(this,t),this.flow=r,s}flowNodeFromShaderStage(e,t,r=null,s=null){const i=this.shaderStage;this.setShaderStage(e);const n=this.flowChildNode(t,r);return null!==s&&(n.code+=`${this.tab+s} = ${n.result};\n`),this.flowCode[e]=this.flowCode[e]+n.code,this.setShaderStage(i),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 r=this.vars[e];if(void 0!==r)for(const e of r)t+=`${this.getVar(e.type,e.name)}; `;return t}getUniforms(){console.warn("Abstract function.")}getCodes(e){const t=this.codes[e];let r="";if(void 0!==t)for(const e of t)r+=e.code+"\n";return r}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:r}=this;if(null!==t){let e=r.library.fromMaterial(t);null===e&&(console.error(`NodeMaterial: Material "${t.type}" is not compatible.`),e=new Yc),e.build(this)}else this.addFlow("compute",e);for(const e of Rs){this.setBuildStage(e),this.context.vertex&&this.context.vertex.isNode&&this.flowNodeFromShaderStage("vertex",this.context.vertex);for(const t of Cs){this.setShaderStage(t);const r=this.flowNodes[t];for(const t of r)"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 Vx(e);if("vec2"===t||"ivec2"===t||"uvec2"===t)return new Ox(e);if("vec3"===t||"ivec3"===t||"uvec3"===t)return new Gx(e);if("vec4"===t||"ivec4"===t||"uvec4"===t)return new kx(e);if("color"===t)return new zx(e);if("mat3"===t)return new $x(e);if("mat4"===t)return new Hx(e);throw new Error(`Uniform "${t}" not declared.`)}format(e,t,r){if((t=this.getVectorType(t))===(r=this.getVectorType(r))||null===r||this.isReference(r))return e;const s=this.getTypeLength(t),i=this.getTypeLength(r);return 16===s&&9===i?`${this.getType(r)}(${e}[0].xyz, ${e}[1].xyz, ${e}[2].xyz)`:9===s&&4===i?`${this.getType(r)}(${e}[0].xy, ${e}[1].xy)`:s>4||i>4||0===i?e:s===i?`${this.getType(r)}( ${e} )`:s>i?this.format(`${e}.${"xyz".slice(0,i)}`,this.getTypeFromLength(i,this.getComponentType(t)),r):4===i&&s>1?`${this.getType(r)}( ${this.format(e,t,"vec3")}, 1.0 )`:2===s?`${this.getType(r)}( ${this.format(e,t,"vec2")}, 0.0 )`:(1===s&&i>1&&t!==this.getComponentType(r)&&(e=`${this.getType(this.getComponentType(r))}( ${e} )`),`${this.getType(r)}( ${e} )`)}getSignature(){return`// Three.js r${De} - Node System\n`}createNodeMaterial(e="NodeMaterial"){throw new Error(`THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${e}() instead.`)}}class mT{constructor(){this.time=0,this.deltaTime=0,this.frameId=0,this.renderId=0,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 r=e.get(t);return void 0===r&&(r={renderMap:new WeakMap,frameMap:new WeakMap},e.set(t,r)),r}updateBeforeNode(e){const t=e.getUpdateBeforeType(),r=e.updateReference(this);if(t===vs.FRAME){const{frameMap:t}=this._getMaps(this.updateBeforeMap,r);t.get(r)!==this.frameId&&!1!==e.updateBefore(this)&&t.set(r,this.frameId)}else if(t===vs.RENDER){const{renderMap:t}=this._getMaps(this.updateBeforeMap,r);t.get(r)!==this.renderId&&!1!==e.updateBefore(this)&&t.set(r,this.renderId)}else t===vs.OBJECT&&e.updateBefore(this)}updateAfterNode(e){const t=e.getUpdateAfterType(),r=e.updateReference(this);if(t===vs.FRAME){const{frameMap:t}=this._getMaps(this.updateAfterMap,r);t.get(r)!==this.frameId&&!1!==e.updateAfter(this)&&t.set(r,this.frameId)}else if(t===vs.RENDER){const{renderMap:t}=this._getMaps(this.updateAfterMap,r);t.get(r)!==this.renderId&&!1!==e.updateAfter(this)&&t.set(r,this.renderId)}else t===vs.OBJECT&&e.updateAfter(this)}updateNode(e){const t=e.getUpdateType(),r=e.updateReference(this);if(t===vs.FRAME){const{frameMap:t}=this._getMaps(this.updateMap,r);t.get(r)!==this.frameId&&!1!==e.update(this)&&t.set(r,this.frameId)}else if(t===vs.RENDER){const{renderMap:t}=this._getMaps(this.updateMap,r);t.get(r)!==this.renderId&&!1!==e.update(this)&&t.set(r,this.renderId)}else t===vs.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 fT{constructor(e,t,r=null,s="",i=!1){this.type=e,this.name=t,this.count=r,this.qualifier=s,this.isConst=i}}fT.isNodeFunctionInput=!0;class yT extends db{static get type(){return"DirectionalLightNode"}constructor(e=null){super(e)}setup(e){super.setup(e);const t=e.context.lightingModel,r=this.colorNode,s=Hy(this.light),i=e.context.reflectedLight;t.direct({lightDirection:s,lightColor:r,reflectedLight:i},e.stack,e)}}const bT=new n,xT=new n;let TT=null;class _T extends db{static get type(){return"RectAreaLightNode"}constructor(e=null){super(e),this.halfHeight=tn(new r).setGroup(Zi),this.halfWidth=tn(new r).setGroup(Zi),this.updateType=vs.RENDER}update(e){super.update(e);const{light:t}=this,r=e.camera.matrixWorldInverse;xT.identity(),bT.copy(t.matrixWorld),bT.premultiply(r),xT.extractRotation(bT),this.halfWidth.value.set(.5*t.width,0,0),this.halfHeight.value.set(0,.5*t.height,0),this.halfWidth.value.applyMatrix4(xT),this.halfHeight.value.applyMatrix4(xT)}setup(e){let t,r;super.setup(e),e.isAvailable("float32Filterable")?(t=xu(TT.LTC_FLOAT_1),r=xu(TT.LTC_FLOAT_2)):(t=xu(TT.LTC_HALF_1),r=xu(TT.LTC_HALF_2));const{colorNode:s,light:i}=this,n=e.context.lightingModel,o=$y(i),a=e.context.reflectedLight;n.directRectArea({lightColor:s,lightPosition:o,halfWidth:this.halfWidth,halfHeight:this.halfHeight,reflectedLight:a,ltc_1:t,ltc_2:r},e.stack,e)}static setLTC(e){TT=e}}class vT extends db{static get type(){return"SpotLightNode"}constructor(e=null){super(e),this.coneCosNode=tn(0).setGroup(Zi),this.penumbraCosNode=tn(0).setGroup(Zi),this.cutoffDistanceNode=tn(0).setGroup(Zi),this.decayExponentNode=tn(0).setGroup(Zi)}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:r}=this;return ga(t,r,e)}setup(e){super.setup(e);const t=e.context.lightingModel,{colorNode:r,cutoffDistanceNode:s,decayExponentNode:i,light:n}=this,o=$y(n).sub(Qu),a=o.normalize(),u=a.dot(Hy(n)),l=this.getSpotAttenuation(u),d=o.length(),c=cb({lightDistance:d,cutoffDistance:s,decayExponent:i});let h=r.mul(l).mul(c);if(n.map){const e=Gy(n),t=xu(n.map,e.xy).onRenderUpdate((()=>n.map));h=e.mul(2).sub(1).abs().lessThan(1).all().select(h.mul(t),h)}const p=e.context.reflectedLight;t.direct({lightDirection:a,lightColor:h,reflectedLight:p},e.stack,e)}}class NT extends vT{static get type(){return"IESSpotLightNode"}getSpotAttenuation(e){const t=this.light.iesMap;let r=null;if(t&&!0===t.isTexture){const s=e.acos().mul(1/Math.PI);r=xu(t,Bi(s,0),0).r}else r=super.getSpotAttenuation(e);return r}}class ST extends db{static get type(){return"AmbientLightNode"}constructor(e=null){super(e)}setup({context:e}){e.irradiance.addAssign(this.colorNode)}}class AT extends db{static get type(){return"HemisphereLightNode"}constructor(t=null){super(t),this.lightPositionNode=ky(t),this.lightDirectionNode=this.lightPositionNode.normalize(),this.groundColorNode=tn(new e).setGroup(Zi)}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:r,lightDirectionNode:s}=this,i=nl.dot(s).mul(.5).add(.5),n=da(r,t,i);e.context.irradiance.addAssign(n)}}class RT extends db{static get type(){return"LightProbeNode"}constructor(e=null){super(e);const t=[];for(let e=0;e<9;e++)t.push(new r);this.lightProbe=Nl(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=mx(ol,this.lightProbe);e.context.irradiance.addAssign(t)}}class CT{parseFunction(){console.warn("Abstract function.")}}class ET{constructor(e,t,r="",s=""){this.type=e,this.inputs=t,this.name=r,this.precision=s}getCode(){console.warn("Abstract function.")}}ET.isNodeFunction=!0;const wT=/^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i,MT=/[a-z_0-9]+/gi,BT="#pragma main";class UT extends ET{constructor(e){const{type:t,inputs:r,name:s,precision:i,inputsCode:n,blockCode:o,headerCode:a}=(e=>{const t=(e=e.trim()).indexOf(BT),r=-1!==t?e.slice(t+12):e,s=r.match(wT);if(null!==s&&5===s.length){const i=s[4],n=[];let o=null;for(;null!==(o=MT.exec(i));)n.push(o);const a=[];let u=0;for(;u0||e.backgroundBlurriness>0&&0===t.backgroundBlurriness;if(t.background!==r||s){let s=null;if(!0===r.isCubeTexture||r.mapping===j||r.mapping===q||r.mapping===Be)if(e.backgroundBlurriness>0||r.mapping===Be)s=qp(r);else{let e;e=!0===r.isCubeTexture?bl(r):xu(r),s=bh(e)}else!0===r.isTexture?s=xu(r,xc.flipY()).setUpdateMatrix(!0):!0!==r.isColor&&console.error("WebGPUNodes: Unsupported background configuration.",r);t.backgroundNode=s,t.background=r,t.backgroundBlurriness=e.backgroundBlurriness}}else t.backgroundNode&&(delete t.backgroundNode,delete t.background)}updateFog(e){const t=this.get(e),r=e.fog;if(r){if(t.fog!==r){let e=null;if(r.isFogExp2){const t=Rl("color","color",r).setGroup(Zi),s=Rl("density","float",r).setGroup(Zi);e=Ty(t,s)}else if(r.isFog){const t=Rl("color","color",r).setGroup(Zi),s=Rl("near","float",r).setGroup(Zi),i=Rl("far","float",r).setGroup(Zi);e=by(t,s,i)}else console.error("WebGPUNodes: Unsupported fog configuration.",r);t.fogNode=e,t.fog=r}}else delete t.fogNode,delete t.fog}updateEnvironment(e){const t=this.get(e),r=e.environment;if(r){if(t.environment!==r){let e=null;!0===r.isCubeTexture?e=bl(r):!0===r.isTexture?e=xu(r):console.error("Nodes: Unsupported environment configuration.",r),t.environmentNode=e,t.environment=r}}else t.environmentNode&&(delete t.environmentNode,delete t.environment)}getNodeFrame(e=this.renderer,t=null,r=null,s=null,i=null){const n=this.nodeFrame;return n.renderer=e,n.scene=t,n.object=r,n.camera=s,n.material=i,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 PT.get(e)!==this.getOutputCacheKey()}getOutputNode(e){const t=this.renderer,r=this.getOutputCacheKey(),s=xu(e,xc).renderOutput(t.toneMapping,t.currentColorSpace);return PT.set(e,r),s}updateBefore(e){const t=e.getNodeBuilderState();for(const r of t.updateBeforeNodes)this.getNodeFrameForRender(e).updateBeforeNode(r)}updateAfter(e){const t=e.getNodeBuilderState();for(const r of t.updateAfterNodes)this.getNodeFrameForRender(e).updateAfterNode(r)}updateForCompute(e){const t=this.getNodeFrame(),r=this.getForCompute(e);for(const e of r.updateNodes)t.updateNode(e)}updateForRender(e){const t=this.getNodeFrameForRender(e),r=e.getNodeBuilderState();for(const e of r.updateNodes)t.updateNode(e)}needsRefresh(e){const t=this.getNodeFrameForRender(e);return e.getMonitor().needsRefresh(e,t)}dispose(){super.dispose(),this.nodeFrame=new mT,this.nodeBuilderCache=new Map}}const LT=new me;class DT{constructor(e=null){this.version=0,this.clipIntersection=null,this.cacheKey="",null===e?(this.intersectionPlanes=[],this.unionPlanes=[],this.viewNormalMatrix=new i,this.clippingGroupContexts=new WeakMap,this.shadowPass=!1):(this.viewNormalMatrix=e.viewNormalMatrix,this.clippingGroupContexts=e.clippingGroupContexts,this.shadowPass=e.shadowPass,this.viewMatrix=e.viewMatrix),this.parentVersion=null}projectPlanes(e,t,r){const s=e.length;for(let i=0;i{await this.compileAsync(e,t);const s=this._renderLists.get(e,t),i=this._renderContexts.get(e,t,this._renderTarget),n=e.overrideMaterial||r.material,o=this._objects.get(r,n,e,t,s.lightsNode,i,i.clippingContext),{fragmentShader:a,vertexShader:u}=o.getNodeBuilderState();return{fragmentShader:a,vertexShader:u}}}}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 r=this.backend;try{await r.init(this)}catch(e){if(null===this._getFallback)return void t(e);try{this.backend=r=this._getFallback(e),await r.init(this)}catch(e){return void t(e)}}this._nodes=new IT(this,r),this._animation=new Ag(this._nodes,this.info),this._attributes=new Dg(r),this._background=new bx(this,this._nodes),this._geometries=new Gg(this._attributes,this.info),this._textures=new nm(this,r,this.info),this._pipelines=new qg(r,this._nodes),this._bindings=new Kg(r,this._nodes,this._textures,this._attributes,this._pipelines,this.info),this._objects=new Mg(this,this._nodes,this._geometries,this._pipelines,this._bindings,this.info),this._renderLists=new Jg(this.lighting),this._bundles=new OT,this._renderContexts=new sm,this._animation.start(),this._initialized=!0,e()}))),this._initPromise}get coordinateSystem(){return this.backend.coordinateSystem}async compileAsync(e,t,r=null){if(!0===this._isDeviceLost)return;!1===this._initialized&&await this.init();const s=this._nodes.nodeFrame,i=s.renderId,n=this._currentRenderContext,o=this._currentRenderObjectFunction,a=this._compilationPromises,u=!0===e.isScene?e:$T;null===r&&(r=e);const l=this._renderTarget,d=this._renderContexts.get(r,t,l),c=this._activeMipmapLevel,h=[];this._currentRenderContext=d,this._currentRenderObjectFunction=this.renderObject,this._handleObjectFunction=this._createObjectPipeline,this._compilationPromises=h,s.renderId++,s.update(),d.depth=this.depth,d.stencil=this.stencil,d.clippingContext||(d.clippingContext=new DT),d.clippingContext.updateGlobal(u,t),u.onBeforeRender(this,e,t,l);const p=this._renderLists.get(e,t);if(p.begin(),this._projectObject(e,t,0,p,d.clippingContext),r!==e&&r.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);d.textures=e.textures,d.depthTexture=e.depthTexture}else d.textures=null,d.depthTexture=null;this._nodes.updateScene(u),this._background.update(u,p,d);const g=p.opaque,m=p.transparent,f=p.transparentDoublePass,y=p.lightsNode;!0===this.opaque&&g.length>0&&this._renderObjects(g,t,u,y),!0===this.transparent&&m.length>0&&this._renderTransparents(m,f,t,u,y),s.renderId=i,this._currentRenderContext=n,this._currentRenderObjectFunction=o,this._compilationPromises=a,this._handleObjectFunction=this._renderObjectDirect,await Promise.all(h)}async renderAsync(e,t){!1===this._initialized&&await this.init();const r=this._renderScene(e,t);await this.backend.resolveTimestampAsync(r,"render")}async waitForGPU(){await this.backend.waitForGPU()}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}_onDeviceLost(e){let t=`THREE.WebGPURenderer: ${e.api} Device Lost:\n\nMessage: ${e.message}`;e.reason&&(t+=`\nReason: ${e.reason}`),console.error(t),this._isDeviceLost=!0}_renderBundle(e,t,r){const{bundleGroup:s,camera:i,renderList:n}=e,o=this._currentRenderContext,a=this._bundles.get(s,i),u=this.backend.get(a);void 0===u.renderContexts&&(u.renderContexts=new Set);const l=s.version!==u.version,d=!1===u.renderContexts.has(o)||l;if(u.renderContexts.add(o),d){this.backend.beginBundle(o),(void 0===u.renderObjects||l)&&(u.renderObjects=[]),this._currentRenderBundle=a;const e=n.opaque;!0===this.opaque&&e.length>0&&this._renderObjects(e,i,t,r),this._currentRenderBundle=null,this.backend.finishBundle(o,a),u.version=s.version}else{const{renderObjects:e}=u;for(let t=0,r=e.length;t>=c,p.viewportValue.height>>=c,p.viewportValue.minDepth=b,p.viewportValue.maxDepth=x,p.viewport=!1===p.viewportValue.equals(WT),p.scissorValue.copy(f).multiplyScalar(y).floor(),p.scissor=this._scissorTest&&!1===p.scissorValue.equals(WT),p.scissorValue.width>>=c,p.scissorValue.height>>=c,p.clippingContext||(p.clippingContext=new DT),p.clippingContext.updateGlobal(u,t),u.onBeforeRender(this,e,t,h),qT.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),jT.setFromProjectionMatrix(qT,g);const T=this._renderLists.get(e,t);if(T.begin(),this._projectObject(e,t,0,T,p.clippingContext),T.finish(),!0===this.sortObjects&&T.sort(this._opaqueSort,this._transparentSort),null!==h){this._textures.updateRenderTarget(h,c);const e=this._textures.get(h);p.textures=e.textures,p.depthTexture=e.depthTexture,p.width=e.width,p.height=e.height,p.renderTarget=h,p.depth=h.depthBuffer,p.stencil=h.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=d,p.activeMipmapLevel=c,p.occlusionQueryCount=T.occlusionQueryCount,this._nodes.updateScene(u),this._background.update(u,T,p),this.backend.beginRender(p);const{bundles:_,lightsNode:v,transparentDoublePass:N,transparent:S,opaque:A}=T;if(_.length>0&&this._renderBundles(_,u,v),!0===this.opaque&&A.length>0&&this._renderObjects(A,t,u,v),!0===this.transparent&&S.length>0&&this._renderTransparents(S,N,t,u,v),this.backend.finishRender(p),i.renderId=n,this._currentRenderContext=o,this._currentRenderObjectFunction=a,null!==s){this.setRenderTarget(l,d,c);const e=this._quad;this._nodes.hasOutputChange(h.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(h.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}return u.onAfterRender(this,e,t,h),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._pixelRatio=e,this.setSize(this._width,this._height,!1))}setDrawingBufferSize(e,t,r){this._width=e,this._height=t,this._pixelRatio=r,this.domElement.width=Math.floor(e*r),this.domElement.height=Math.floor(t*r),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setSize(e,t,r=!0){this._width=e,this._height=t,this.domElement.width=Math.floor(e*this._pixelRatio),this.domElement.height=Math.floor(t*this._pixelRatio),!0===r&&(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,r,s){const i=this._scissor;e.isVector4?i.copy(e):i.set(e,t,r,s)}getScissorTest(){return this._scissorTest}setScissorTest(e){this._scissorTest=e,this.backend.setScissorTest(e)}getViewport(e){return e.copy(this._viewport)}setViewport(e,t,r,s,i=0,n=1){const o=this._viewport;e.isVector4?o.copy(e):o.set(e,t,r,s),o.minDepth=i,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,r=!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,r);const s=this._renderTarget||this._getFrameBufferTarget();let i=null;if(null!==s&&(this._textures.updateRenderTarget(s),i=this._textures.get(s)),this.backend.clear(e,t,r,i),null!==s&&null===this._renderTarget){const e=this._quad;this._nodes.hasOutputChange(s.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(s.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,r=!0){!1===this._initialized&&await this.init(),this.clear(e,t,r)}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?d:this.toneMapping}get currentColorSpace(){return null!==this._renderTarget?Ae:this.outputColorSpace}dispose(){this.info.dispose(),this.backend.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,r=0){this._renderTarget=e,this._activeCubeFace=t,this._activeMipmapLevel=r}getRenderTarget(){return this._renderTarget}setRenderObjectFunction(e){this._renderObjectFunction=e}getRenderObjectFunction(){return this._renderObjectFunction}compute(e){if(!0===this.isDeviceLost)return;if(!1===this._initialized)return console.warn("THREE.Renderer: .compute() called before the backend is initialized. Try using .computeAsync() instead."),this.computeAsync(e);const t=this._nodes.nodeFrame,r=t.renderId;this.info.calls++,this.info.compute.calls++,this.info.compute.frameCalls++,t.renderId=this.info.calls;const s=this.backend,i=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.");s.beginCompute(e);for(const t of a){if(!1===i.has(t)){const e=()=>{t.removeEventListener("dispose",e),i.delete(t),n.delete(t),o.delete(t)};t.addEventListener("dispose",e);const r=t.onInitFunction;null!==r&&r.call(t,{renderer:this})}o.updateForCompute(t),n.updateForCompute(t);const r=n.getForCompute(t),a=i.getForCompute(t,r);s.compute(e,t,r,a)}s.finishCompute(e),t.renderId=r}async computeAsync(e){!1===this._initialized&&await this.init(),this.compute(e),await this.backend.resolveTimestampAsync(e,"compute")}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)}hasInitialized(){return this._initialized}async initTextureAsync(e){!1===this._initialized&&await this.init(),this._textures.updateTexture(e)}initTexture(e){if(!1===this._initialized)return console.warn("THREE.Renderer: .initTexture() called before the backend is initialized. Try using .initTextureAsync() instead."),!1;this._textures.updateTexture(e)}copyFramebufferToTexture(e,t=null){if(null!==t)if(t.isVector2)t=KT.set(t.x,t.y,e.image.width,e.image.height).floor();else{if(!t.isVector4)return void console.error("THREE.Renderer.copyFramebufferToTexture: Invalid rectangle.");t=KT.copy(t).floor()}else t=KT.set(0,0,e.image.width,e.image.height);let r,s=this._currentRenderContext;null!==s?r=s.renderTarget:(r=this._renderTarget||this._getFrameBufferTarget(),null!==r&&(this._textures.updateRenderTarget(r),s=this._textures.get(r))),this._textures.updateTexture(e,{renderTarget:r}),this.backend.copyFramebufferToTexture(e,s,t)}copyTextureToTexture(e,t,r=null,s=null,i=0){this._textures.updateTexture(e),this._textures.updateTexture(t),this.backend.copyTextureToTexture(e,t,r,s,i)}readRenderTargetPixelsAsync(e,t,r,s,i,n=0,o=0){return this.backend.copyTextureToBuffer(e.textures[n],t,r,s,i,o)}_projectObject(e,t,r,s,i){if(!1===e.visible)return;if(e.layers.test(t.layers))if(e.isGroup)r=e.renderOrder,e.isClippingGroup&&e.enabled&&(i=i.getGroupContext(e));else if(e.isLOD)!0===e.autoUpdate&&e.update(t);else if(e.isLight)s.pushLight(e);else if(e.isSprite){if(!e.frustumCulled||jT.intersectsSprite(e)){!0===this.sortObjects&&KT.setFromMatrixPosition(e.matrixWorld).applyMatrix4(qT);const{geometry:t,material:n}=e;n.visible&&s.push(e,t,n,r,KT.z,null,i)}}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||jT.intersectsObject(e))){const{geometry:t,material:n}=e;if(!0===this.sortObjects&&(null===t.boundingSphere&&t.computeBoundingSphere(),KT.copy(t.boundingSphere.center).applyMatrix4(e.matrixWorld).applyMatrix4(qT)),Array.isArray(n)){const o=t.groups;for(let a=0,u=o.length;a0){for(const{material:e}of t)e.side=x;this._renderObjects(t,r,s,i,"backSide");for(const{material:e}of t)e.side=Ge;this._renderObjects(e,r,s,i);for(const{material:e}of t)e.side=le}else this._renderObjects(e,r,s,i)}_renderObjects(e,t,r,s,i=null){for(let n=0,o=e.length;n0,e.isShadowNodeMaterial&&(e.side=null===i.shadowSide?i.side:i.shadowSide,i.depthNode&&i.depthNode.isNode&&(c=e.depthNode,e.depthNode=i.depthNode),i.castShadowNode&&i.castShadowNode.isNode&&(d=e.colorNode,e.colorNode=i.castShadowNode)),i=e}!0===i.transparent&&i.side===le&&!1===i.forceSinglePass?(i.side=x,this._handleObjectFunction(e,i,t,r,o,n,a,"backSide"),i.side=Ge,this._handleObjectFunction(e,i,t,r,o,n,a,u),i.side=le):this._handleObjectFunction(e,i,t,r,o,n,a,u),void 0!==l&&(t.overrideMaterial.positionNode=l),void 0!==c&&(t.overrideMaterial.depthNode=c),void 0!==d&&(t.overrideMaterial.colorNode=d),e.onAfterRender(this,t,r,s,i,n)}_renderObjectDirect(e,t,r,s,i,n,o,a){const u=this._objects.get(e,t,r,s,i,this._currentRenderContext,o,a);u.drawRange=e.geometry.drawRange,u.group=n;const l=this._nodes.needsRefresh(u);if(l&&(this._nodes.updateBefore(u),this._geometries.updateForRender(u),this._nodes.updateForRender(u),this._bindings.updateForRender(u)),this._pipelines.updateForRender(u),null!==this._currentRenderBundle){this.backend.get(this._currentRenderBundle).renderObjects.push(u),u.bundle=this._currentRenderBundle.scene}this.backend.draw(u,this.info),l&&this._nodes.updateAfter(u)}_createObjectPipeline(e,t,r,s,i,n,o){const a=this._objects.get(e,t,r,s,i,this._currentRenderContext,n,o);this._nodes.updateBefore(a),this._geometries.updateForRender(a),this._nodes.updateForRender(a),this._bindings.updateForRender(a),this._pipelines.getForRender(a,this._compilationPromises),this._nodes.updateAfter(a)}get compile(){return this.compileAsync}}class YT{constructor(e=""){this.name=e,this.visibility=0}setVisibility(e){this.visibility|=e}clone(){return Object.assign(new this.constructor,this)}}class QT extends YT{constructor(e,t=null){super(e),this.isBuffer=!0,this.bytesPerElement=Float32Array.BYTES_PER_ELEMENT,this._buffer=t}get byteLength(){return(e=this._buffer.byteLength)+(Lg-e%Lg)%Lg;var e}get buffer(){return this._buffer}update(){return!0}}class ZT extends QT{constructor(e,t=null){super(e,t),this.isUniformBuffer=!0}}let JT=0;class e_ extends ZT{constructor(e,t){super("UniformBuffer_"+JT++,e?e.value:null),this.nodeUniform=e,this.groupNode=t}get buffer(){return this.nodeUniform.value}}class t_ extends ZT{constructor(e){super(e),this.isUniformsGroup=!0,this._values=null,this.uniforms=[]}addUniform(e){return this.uniforms.push(e),this}removeUniform(e){const t=this.uniforms.indexOf(e);return-1!==t&&this.uniforms.splice(t,1),this}get values(){return null===this._values&&(this._values=Array.from(this.buffer)),this._values}get buffer(){let e=this._buffer;if(null===e){const t=this.byteLength;e=new Float32Array(new ArrayBuffer(t)),this._buffer=e}return e}get byteLength(){let e=0;for(let t=0,r=this.uniforms.length;t0?s:"";t=`${e.name} {\n\t${r} ${i.name}[${n}];\n};\n`}else{t=`${this.getVectorType(i.type)} ${this.getPropertyName(i,e)};`,n=!0}const o=i.node.precision;if(null!==o&&(t=d_[o]+" "+t),n){t="\t"+t;const e=i.groupNode.name;(s[e]||(s[e]=[])).push(t)}else t="uniform "+t,r.push(t)}let i="";for(const t in s){const r=s[t];i+=this._getGLSLUniformStruct(e+"_"+t,r.join("\n"))+"\n"}return i+=r.join("\n"),i}getTypeFromAttribute(e){let t=super.getTypeFromAttribute(e);if(/^[iu]/.test(t)&&e.gpuType!==y){let r=e;e.isInterleavedBufferAttribute&&(r=e.data);const s=r.array;!1==(s instanceof Uint32Array||s instanceof Int32Array)&&(t=t.slice(1))}return t}getAttributes(e){let t="";if("vertex"===e||"compute"===e){const e=this.getAttributesArray();let r=0;for(const s of e)t+=`layout( location = ${r++} ) in ${s.type} ${s.name};\n`}return t}getStructMembers(e){const t=[],r=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,r=this.shaderStage){const s=this.extensions[r]||(this.extensions[r]=new Map);!1===s.has(e)&&s.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 r=this.extensions[e];if(void 0!==r)for(const{name:e,behavior:s}of r.values())t.push(`#extension ${e} : ${s}`);return t.join("\n")}getClipDistance(){return"gl_ClipDistance"}isAvailable(e){let t=c_[e];if(void 0===t){let r;switch(t=!1,e){case"float32Filterable":r="OES_texture_float_linear";break;case"clipDistance":r="WEBGL_clip_cull_distance"}if(void 0!==r){const e=this.renderer.backend.extensions;e.has(r)&&(e.get(r),t=!0)}c_[e]=t}return t}isFlipY(){return!0}enableHardwareClipping(e){this.enableExtension("GL_ANGLE_clip_cull_distance","require"),this.builtins.vertex.push(`out float gl_ClipDistance[ ${e} ]`)}registerTransform(e,t){this.transforms.push({varyingName:e,attributeNode:t})}getTransforms(){const e=this.transforms;let t="";for(let r=0;r0&&(r+="\n"),r+=`\t// flow -> ${n}\n\t`),r+=`${s.code}\n\t`,e===i&&"compute"!==t&&(r+="// result\n\t","vertex"===t?(r+="gl_Position = ",r+=`${s.result};`):"fragment"===t&&(e.outputNode.isOutputStructNode||(r+="fragColor = ",r+=`${s.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=r}null!==this.material?(this.vertexShader=this._getGLSLVertexCode(e.vertex),this.fragmentShader=this._getGLSLFragmentCode(e.fragment)):this.computeShader=this._getGLSLVertexCode(e.compute)}getUniformFromNode(e,t,r,s=null){const i=super.getUniformFromNode(e,t,r,s),n=this.getDataFromNode(e,r,this.globalCache);let o=n.uniformGPU;if(void 0===o){const s=e.groupNode,a=s.name,u=this.getBindGroupArray(a,r);if("texture"===t)o=new o_(i.name,i.node,s),u.push(o);else if("cubeTexture"===t)o=new a_(i.name,i.node,s),u.push(o);else if("texture3D"===t)o=new u_(i.name,i.node,s),u.push(o);else if("buffer"===t){e.name=`NodeBuffer_${e.id}`,i.name=`buffer${e.id}`;const t=new e_(e,s);t.name=e.name,u.push(t),o=t}else{const e=this.uniformGroups[r]||(this.uniformGroups[r]={});let n=e[a];void 0===n&&(n=new s_(r+"_"+a,s),e[a]=n,u.push(n)),o=this.getNodeUniform(i,t),n.addUniform(o)}n.uniformGPU=o}return i}}let g_=null,m_=null,f_=null;class y_{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:r}=e;return r.isInstancedBufferGeometry?r.instanceCount:t.count>1?t.count:1}getDrawingBufferSize(){return g_=g_||new t,this.renderer.getDrawingBufferSize(g_)}getScissor(){return m_=m_||new s,this.renderer.getScissor(m_)}setScissorTest(){}getClearColor(){const e=this.renderer;return f_=f_||new om,e.getClearColor(f_),f_.getRGB(f_,this.renderer.currentColorSpace),f_}getDomElement(){let e=this.domElement;return null===e&&(e=void 0!==this.parameters.canvas?this.parameters.canvas:Ze(),"setAttribute"in e&&e.setAttribute("data-engine",`three.js r${De} webgpu`),this.domElement=e),e}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)}dispose(){}}let b_=0;class x_{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 T_{constructor(e){this.backend=e}createAttribute(e,t){const r=this.backend,{gl:s}=r,i=e.array,n=e.usage||s.STATIC_DRAW,o=e.isInterleavedBufferAttribute?e.data:e,a=r.get(o);let u,l=a.bufferGPU;if(void 0===l&&(l=this._createBuffer(s,t,i,n),a.bufferGPU=l,a.bufferType=t,a.version=o.version),i instanceof Float32Array)u=s.FLOAT;else if(i instanceof Uint16Array)u=e.isFloat16BufferAttribute?s.HALF_FLOAT:s.UNSIGNED_SHORT;else if(i instanceof Int16Array)u=s.SHORT;else if(i instanceof Uint32Array)u=s.UNSIGNED_INT;else if(i instanceof Int32Array)u=s.INT;else if(i instanceof Int8Array)u=s.BYTE;else if(i instanceof Uint8Array)u=s.UNSIGNED_BYTE;else{if(!(i instanceof Uint8ClampedArray))throw new Error("THREE.WebGLBackend: Unsupported buffer data format: "+i);u=s.UNSIGNED_BYTE}let d={bufferGPU:l,bufferType:t,type:u,byteLength:i.byteLength,bytesPerElement:i.BYTES_PER_ELEMENT,version:e.version,pbo:e.pbo,isInteger:u===s.INT||u===s.UNSIGNED_INT||e.gpuType===y,id:b_++};if(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute){const e=this._createBuffer(s,t,i,n);d=new x_(d,e)}r.set(e,d)}updateAttribute(e){const t=this.backend,{gl:r}=t,s=e.array,i=e.isInterleavedBufferAttribute?e.data:e,n=t.get(i),o=n.bufferType,a=e.isInterleavedBufferAttribute?e.data.updateRanges:e.updateRanges;if(r.bindBuffer(o,n.bufferGPU),0===a.length)r.bufferSubData(o,0,s);else{for(let e=0,t=a.length;e1?this.enable(s.SAMPLE_ALPHA_TO_COVERAGE):this.disable(s.SAMPLE_ALPHA_TO_COVERAGE),r>0&&this.currentClippingPlanes!==r){const e=12288;for(let t=0;t<8;t++)t{!function i(){const n=e.clientWaitSync(t,e.SYNC_FLUSH_COMMANDS_BIT,0);if(n===e.WAIT_FAILED)return e.deleteSync(t),void s();n!==e.TIMEOUT_EXPIRED?(e.deleteSync(t),r()):requestAnimationFrame(i)}()}))}}let R_,C_,E_,w_=!1;class M_{constructor(e){this.backend=e,this.gl=e.gl,this.extensions=e.extensions,this.defaultTextures={},!1===w_&&(this._init(this.gl),w_=!0)}_init(e){R_={[dr]:e.REPEAT,[cr]:e.CLAMP_TO_EDGE,[hr]:e.MIRRORED_REPEAT},C_={[pr]:e.NEAREST,[gr]:e.NEAREST_MIPMAP_NEAREST,[Ie]:e.NEAREST_MIPMAP_LINEAR,[$]:e.LINEAR,[Pe]:e.LINEAR_MIPMAP_NEAREST,[M]:e.LINEAR_MIPMAP_LINEAR},E_={[mr]:e.NEVER,[fr]:e.ALWAYS,[Re]:e.LESS,[yr]:e.LEQUAL,[br]:e.EQUAL,[xr]:e.GEQUAL,[Tr]:e.GREATER,[_r]:e.NOTEQUAL}}filterFallback(e){const{gl:t}=this;return e===pr||e===gr||e===Ie?t.NEAREST:t.LINEAR}getGLTextureType(e){const{gl:t}=this;let r;return r=!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,r}getInternalFormat(e,t,r,s,i=!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&&(r===n.FLOAT&&(a=n.R32F),r===n.HALF_FLOAT&&(a=n.R16F),r===n.UNSIGNED_BYTE&&(a=n.R8),r===n.UNSIGNED_SHORT&&(a=n.R16),r===n.UNSIGNED_INT&&(a=n.R32UI),r===n.BYTE&&(a=n.R8I),r===n.SHORT&&(a=n.R16I),r===n.INT&&(a=n.R32I)),t===n.RED_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.R8UI),r===n.UNSIGNED_SHORT&&(a=n.R16UI),r===n.UNSIGNED_INT&&(a=n.R32UI),r===n.BYTE&&(a=n.R8I),r===n.SHORT&&(a=n.R16I),r===n.INT&&(a=n.R32I)),t===n.RG&&(r===n.FLOAT&&(a=n.RG32F),r===n.HALF_FLOAT&&(a=n.RG16F),r===n.UNSIGNED_BYTE&&(a=n.RG8),r===n.UNSIGNED_SHORT&&(a=n.RG16),r===n.UNSIGNED_INT&&(a=n.RG32UI),r===n.BYTE&&(a=n.RG8I),r===n.SHORT&&(a=n.RG16I),r===n.INT&&(a=n.RG32I)),t===n.RG_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RG8UI),r===n.UNSIGNED_SHORT&&(a=n.RG16UI),r===n.UNSIGNED_INT&&(a=n.RG32UI),r===n.BYTE&&(a=n.RG8I),r===n.SHORT&&(a=n.RG16I),r===n.INT&&(a=n.RG32I)),t===n.RGB&&(r===n.FLOAT&&(a=n.RGB32F),r===n.HALF_FLOAT&&(a=n.RGB16F),r===n.UNSIGNED_BYTE&&(a=n.RGB8),r===n.UNSIGNED_SHORT&&(a=n.RGB16),r===n.UNSIGNED_INT&&(a=n.RGB32UI),r===n.BYTE&&(a=n.RGB8I),r===n.SHORT&&(a=n.RGB16I),r===n.INT&&(a=n.RGB32I),r===n.UNSIGNED_BYTE&&(a=s===Ve&&!1===i?n.SRGB8:n.RGB8),r===n.UNSIGNED_SHORT_5_6_5&&(a=n.RGB565),r===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1),r===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGB4),r===n.UNSIGNED_INT_5_9_9_9_REV&&(a=n.RGB9_E5)),t===n.RGB_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RGB8UI),r===n.UNSIGNED_SHORT&&(a=n.RGB16UI),r===n.UNSIGNED_INT&&(a=n.RGB32UI),r===n.BYTE&&(a=n.RGB8I),r===n.SHORT&&(a=n.RGB16I),r===n.INT&&(a=n.RGB32I)),t===n.RGBA&&(r===n.FLOAT&&(a=n.RGBA32F),r===n.HALF_FLOAT&&(a=n.RGBA16F),r===n.UNSIGNED_BYTE&&(a=n.RGBA8),r===n.UNSIGNED_SHORT&&(a=n.RGBA16),r===n.UNSIGNED_INT&&(a=n.RGBA32UI),r===n.BYTE&&(a=n.RGBA8I),r===n.SHORT&&(a=n.RGBA16I),r===n.INT&&(a=n.RGBA32I),r===n.UNSIGNED_BYTE&&(a=s===Ve&&!1===i?n.SRGB8_ALPHA8:n.RGBA8),r===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGBA4),r===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1)),t===n.RGBA_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RGBA8UI),r===n.UNSIGNED_SHORT&&(a=n.RGBA16UI),r===n.UNSIGNED_INT&&(a=n.RGBA32UI),r===n.BYTE&&(a=n.RGBA8I),r===n.SHORT&&(a=n.RGBA16I),r===n.INT&&(a=n.RGBA32I)),t===n.DEPTH_COMPONENT&&(r===n.UNSIGNED_INT&&(a=n.DEPTH24_STENCIL8),r===n.FLOAT&&(a=n.DEPTH_COMPONENT32F)),t===n.DEPTH_STENCIL&&r===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:r,extensions:s,backend:i}=this;r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,t.flipY),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,t.premultiplyAlpha),r.pixelStorei(r.UNPACK_ALIGNMENT,t.unpackAlignment),r.pixelStorei(r.UNPACK_COLORSPACE_CONVERSION_WEBGL,r.NONE),r.texParameteri(e,r.TEXTURE_WRAP_S,R_[t.wrapS]),r.texParameteri(e,r.TEXTURE_WRAP_T,R_[t.wrapT]),e!==r.TEXTURE_3D&&e!==r.TEXTURE_2D_ARRAY||r.texParameteri(e,r.TEXTURE_WRAP_R,R_[t.wrapR]),r.texParameteri(e,r.TEXTURE_MAG_FILTER,C_[t.magFilter]);const n=void 0!==t.mipmaps&&t.mipmaps.length>0,o=t.minFilter===$&&n?M:t.minFilter;if(r.texParameteri(e,r.TEXTURE_MIN_FILTER,C_[o]),t.compareFunction&&(r.texParameteri(e,r.TEXTURE_COMPARE_MODE,r.COMPARE_REF_TO_TEXTURE),r.texParameteri(e,r.TEXTURE_COMPARE_FUNC,E_[t.compareFunction])),!0===s.has("EXT_texture_filter_anisotropic")){if(t.magFilter===pr)return;if(t.minFilter!==Ie&&t.minFilter!==M)return;if(t.type===E&&!1===s.has("OES_texture_float_linear"))return;if(t.anisotropy>1){const n=s.get("EXT_texture_filter_anisotropic");r.texParameterf(e,n.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(t.anisotropy,i.getMaxAnisotropy()))}}}createDefaultTexture(e){const{gl:t,backend:r,defaultTextures:s}=this,i=this.getGLTextureType(e);let n=s[i];void 0===n&&(n=t.createTexture(),r.state.bindTexture(i,n),t.texParameteri(i,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(i,t.TEXTURE_MAG_FILTER,t.NEAREST),s[i]=n),r.set(e,{textureGPU:n,glTextureType:i,isDefault:!0})}createTexture(e,t){const{gl:r,backend:s}=this,{levels:i,width:n,height:o,depth:a}=t,u=s.utils.convert(e.format,e.colorSpace),l=s.utils.convert(e.type),d=this.getInternalFormat(e.internalFormat,u,l,e.colorSpace,e.isVideoTexture),c=r.createTexture(),h=this.getGLTextureType(e);s.state.bindTexture(h,c),this.setTextureParameters(h,e),e.isDataArrayTexture||e.isCompressedArrayTexture?r.texStorage3D(r.TEXTURE_2D_ARRAY,i,d,n,o,a):e.isData3DTexture?r.texStorage3D(r.TEXTURE_3D,i,d,n,o,a):e.isVideoTexture||r.texStorage2D(h,i,d,n,o),s.set(e,{textureGPU:c,glTextureType:h,glFormat:u,glType:l,glInternalFormat:d})}copyBufferToTexture(e,t){const{gl:r,backend:s}=this,{textureGPU:i,glTextureType:n,glFormat:o,glType:a}=s.get(t),{width:u,height:l}=t.source.data;r.bindBuffer(r.PIXEL_UNPACK_BUFFER,e),s.state.bindTexture(n,i),r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,!1),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),r.texSubImage2D(n,0,0,0,u,l,o,a,0),r.bindBuffer(r.PIXEL_UNPACK_BUFFER,null),s.state.unbindTexture()}updateTexture(e,t){const{gl:r}=this,{width:s,height:i}=t,{textureGPU:n,glTextureType:o,glFormat:a,glType:u,glInternalFormat:l}=this.backend.get(e);if(e.isRenderTargetTexture||void 0===n)return;const d=e=>e.isDataTexture?e.image.data:"undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap||e instanceof OffscreenCanvas?e:e.data;if(this.backend.state.bindTexture(o,n),this.setTextureParameters(o,e),e.isCompressedTexture){const s=e.mipmaps,i=t.image;for(let t=0;t0,c=t.renderTarget?t.renderTarget.height:this.backend.gerDrawingBufferSize().y;if(d){const r=0!==o||0!==a;let d,h;if(!0===e.isDepthTexture?(d=s.DEPTH_BUFFER_BIT,h=s.DEPTH_ATTACHMENT,t.stencil&&(d|=s.STENCIL_BUFFER_BIT)):(d=s.COLOR_BUFFER_BIT,h=s.COLOR_ATTACHMENT0),r){const e=this.backend.get(t.renderTarget),r=e.framebuffers[t.getCacheKey()],h=e.msaaFrameBuffer;i.bindFramebuffer(s.DRAW_FRAMEBUFFER,r),i.bindFramebuffer(s.READ_FRAMEBUFFER,h);const p=c-a-l;s.blitFramebuffer(o,p,o+u,p+l,o,p,o+u,p+l,d,s.NEAREST),i.bindFramebuffer(s.READ_FRAMEBUFFER,r),i.bindTexture(s.TEXTURE_2D,n),s.copyTexSubImage2D(s.TEXTURE_2D,0,0,0,o,p,u,l),i.unbindTexture()}else{const e=s.createFramebuffer();i.bindFramebuffer(s.DRAW_FRAMEBUFFER,e),s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,h,s.TEXTURE_2D,n,0),s.blitFramebuffer(0,0,u,l,0,0,u,l,d,s.NEAREST),s.deleteFramebuffer(e)}}else i.bindTexture(s.TEXTURE_2D,n),s.copyTexSubImage2D(s.TEXTURE_2D,0,0,0,o,c-l-a,u,l),i.unbindTexture();e.generateMipmaps&&this.generateMipmaps(e),this.backend._setFramebuffer(t)}setupRenderBufferStorage(e,t){const{gl:r}=this,s=t.renderTarget,{samples:i,depthTexture:n,depthBuffer:o,stencilBuffer:a,width:u,height:l}=s;if(r.bindRenderbuffer(r.RENDERBUFFER,e),o&&!a){let t=r.DEPTH_COMPONENT24;i>0?(n&&n.isDepthTexture&&n.type===r.FLOAT&&(t=r.DEPTH_COMPONENT32F),r.renderbufferStorageMultisample(r.RENDERBUFFER,i,t,u,l)):r.renderbufferStorage(r.RENDERBUFFER,t,u,l),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,e)}else o&&a&&(i>0?r.renderbufferStorageMultisample(r.RENDERBUFFER,i,r.DEPTH24_STENCIL8,u,l):r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_STENCIL,u,l),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,e))}async copyTextureToBuffer(e,t,r,s,i,n){const{backend:o,gl:a}=this,{textureGPU:u,glFormat:l,glType:d}=this.backend.get(e),c=a.createFramebuffer();a.bindFramebuffer(a.READ_FRAMEBUFFER,c);const h=e.isCubeTexture?a.TEXTURE_CUBE_MAP_POSITIVE_X+n:a.TEXTURE_2D;a.framebufferTexture2D(a.READ_FRAMEBUFFER,a.COLOR_ATTACHMENT0,h,u,0);const p=this._getTypedArrayType(d),g=s*i*this._getBytesPerTexel(d,l),m=a.createBuffer();a.bindBuffer(a.PIXEL_PACK_BUFFER,m),a.bufferData(a.PIXEL_PACK_BUFFER,g,a.STREAM_READ),a.readPixels(t,r,s,i,l,d,0),a.bindBuffer(a.PIXEL_PACK_BUFFER,null),await o.utils._clientWaitAsync();const f=new p(g/p.BYTES_PER_ELEMENT);return a.bindBuffer(a.PIXEL_PACK_BUFFER,m),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:r}=this;let s=0;return e===r.UNSIGNED_BYTE&&(s=1),e!==r.UNSIGNED_SHORT_4_4_4_4&&e!==r.UNSIGNED_SHORT_5_5_5_1&&e!==r.UNSIGNED_SHORT_5_6_5&&e!==r.UNSIGNED_SHORT&&e!==r.HALF_FLOAT||(s=2),e!==r.UNSIGNED_INT&&e!==r.FLOAT||(s=4),t===r.RGBA?4*s:t===r.RGB?3*s:t===r.ALPHA?s:void 0}}class B_{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 U_{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 r=t.get("EXT_texture_filter_anisotropic");this.maxAnisotropy=e.getParameter(r.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else this.maxAnisotropy=0;return this.maxAnisotropy}}const F_={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 P_{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:r,mode:s,object:i,type:n,info:o,index:a}=this;0!==a?r.drawElements(s,t,n,e):r.drawArrays(s,e,t),o.update(i,t,s,1)}renderInstances(e,t,r){const{gl:s,mode:i,type:n,index:o,object:a,info:u}=this;0!==r&&(0!==o?s.drawElementsInstanced(i,t,n,e,r):s.drawArraysInstanced(i,e,t,r),u.update(a,t,i,r))}renderMultiDraw(e,t,r){const{extensions:s,mode:i,object:n,info:o}=this;if(0===r)return;const a=s.get("WEBGL_multi_draw");if(null===a)for(let s=0;s0)){const e=t.queryQueue.shift();this.initTimestampQuery(e)}}async resolveTimestampAsync(e,t="render"){if(!this.disjoint||!this.trackTimestamp)return;const r=this.get(e);r.gpuQueries||(r.gpuQueries=[]);for(let e=0;e0&&(r.currentOcclusionQueries=r.occlusionQueries,r.currentOcclusionQueryObjects=r.occlusionQueryObjects,r.lastOcclusionObject=null,r.occlusionQueries=new Array(s),r.occlusionQueryObjects=new Array(s),r.occlusionQueryIndex=0)}finishRender(e){const{gl:t,state:r}=this,s=this.get(e),i=s.previousContext,n=e.occlusionQueryCount;n>0&&(n>s.occlusionQueryIndex&&t.endQuery(t.ANY_SAMPLES_PASSED),this.resolveOccludedAsync(e));const o=e.textures;if(null!==o)for(let e=0;e0){const i=s.framebuffers[e.getCacheKey()],n=t.COLOR_BUFFER_BIT,o=s.msaaFrameBuffer,a=e.textures;r.bindFramebuffer(t.READ_FRAMEBUFFER,o),r.bindFramebuffer(t.DRAW_FRAMEBUFFER,i);for(let r=0;r{let o=0;for(let t=0;t0&&e.add(s[t]),r[t]=null,i.deleteQuery(n),o++))}o1?f.renderInstances(x,y,b):f.render(x,y),a.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,r,s,i,n){return this.textureUtils.copyTextureToBuffer(e,t,r,s,i,n)}createSampler(){}destroySampler(){}createNodeBuilder(e,t){return new p_(e,t)}createProgram(e){const t=this.gl,{stage:r,code:s}=e,i="fragment"===r?t.createShader(t.FRAGMENT_SHADER):t.createShader(t.VERTEX_SHADER);t.shaderSource(i,s),t.compileShader(i),this.set(e,{shaderGPU:i})}destroyProgram(){console.warn("Abstract class.")}createRenderPipeline(e,t){const r=this.gl,s=e.pipeline,{fragmentProgram:i,vertexProgram:n}=s,o=r.createProgram(),a=this.get(i).shaderGPU,u=this.get(n).shaderGPU;if(r.attachShader(o,a),r.attachShader(o,u),r.linkProgram(o),this.set(s,{programGPU:o,fragmentShader:a,vertexShader:u}),null!==t&&this.parallel){const i=new Promise((t=>{const i=this.parallel,n=()=>{r.getProgramParameter(o,i.COMPLETION_STATUS_KHR)?(this._completeCompile(e,s),t()):requestAnimationFrame(n)};n()}));t.push(i)}else this._completeCompile(e,s)}_handleSource(e,t){const r=e.split("\n"),s=[],i=Math.max(t-6,0),n=Math.min(t+6,r.length);for(let e=i;e":" "} ${i}: ${r[e]}`)}return s.join("\n")}_getShaderErrors(e,t,r){const s=e.getShaderParameter(t,e.COMPILE_STATUS),i=e.getShaderInfoLog(t).trim();if(s&&""===i)return"";const n=/ERROR: 0:(\d+)/.exec(i);if(n){const s=parseInt(n[1]);return r.toUpperCase()+"\n\n"+i+"\n\n"+this._handleSource(e.getShaderSource(t),s)}return i}_logProgramError(e,t,r){if(this.renderer.debug.checkShaderErrors){const s=this.gl,i=s.getProgramInfoLog(e).trim();if(!1===s.getProgramParameter(e,s.LINK_STATUS))if("function"==typeof this.renderer.debug.onShaderError)this.renderer.debug.onShaderError(s,e,r,t);else{const n=this._getShaderErrors(s,r,"vertex"),o=this._getShaderErrors(s,t,"fragment");console.error("THREE.WebGLProgram: Shader Error "+s.getError()+" - VALIDATE_STATUS "+s.getProgramParameter(e,s.VALIDATE_STATUS)+"\n\nProgram Info Log: "+i+"\n"+n+"\n"+o)}else""!==i&&console.warn("THREE.WebGLProgram: Program Info Log:",i)}}_completeCompile(e,t){const{state:r,gl:s}=this,i=this.get(t),{programGPU:n,fragmentShader:o,vertexShader:a}=i;!1===s.getProgramParameter(n,s.LINK_STATUS)&&this._logProgramError(n,o,a),r.useProgram(n);const u=e.getBindings();this._setupBindings(u,n),this.set(t,{programGPU:n})}createComputePipeline(e,t){const{state:r,gl:s}=this,i={stage:"fragment",code:"#version 300 es\nprecision highp float;\nvoid main() {}"};this.createProgram(i);const{computeProgram:n}=e,o=s.createProgram(),a=this.get(i).shaderGPU,u=this.get(n).shaderGPU,l=n.transforms,d=[],c=[];for(let e=0;eF_[t]===e)),r=this.extensions;for(let e=0;e0){if(void 0===d){const s=[];d=t.createFramebuffer(),r.bindFramebuffer(t.FRAMEBUFFER,d);const i=[],l=e.textures;for(let r=0;r,\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:G_,stripIndexFormat:sv},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:G_,stripIndexFormat:sv},layout:"auto"}),this.flipYPipelines[e]=t),t}flipY(e,t,r=0){const s=t.format,{width:i,height:n}=t.size,o=this.getTransferPipeline(s),a=this.getFlipYPipeline(s),u=this.device.createTexture({size:{width:i,height:n,depthOrArrayLayers:1},format:s,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),l=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:Yv,baseArrayLayer:r}),d=u.createView({baseMipLevel:0,mipLevelCount:1,dimension:Yv,baseArrayLayer:0}),c=this.device.createCommandEncoder({}),h=(e,t,r)=>{const s=e.getBindGroupLayout(0),i=this.device.createBindGroup({layout:s,entries:[{binding:0,resource:this.flipYSampler},{binding:1,resource:t}]}),n=c.beginRenderPass({colorAttachments:[{view:r,loadOp:Q_,storeOp:X_,clearValue:[0,0,0,0]}]});n.setPipeline(e),n.setBindGroup(0,i),n.draw(4,1,0,0),n.end()};h(o,l,d),h(a,d,l),this.device.queue.submit([c.finish()]),u.destroy()}generateMipmaps(e,t,r=0){const s=this.get(e);void 0===s.useCount&&(s.useCount=0,s.layers=[]);const i=s.layers[r]||this._mipmapCreateBundles(e,t,r),n=this.device.createCommandEncoder({});this._mipmapRunBundles(n,i),this.device.queue.submit([n.finish()]),0!==s.useCount&&(s.layers[r]=i),s.useCount++}_mipmapCreateBundles(e,t,r){const s=this.getTransferPipeline(t.format),i=s.getBindGroupLayout(0);let n=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:Yv,baseArrayLayer:r});const o=[];for(let a=1;a1;for(let o=0;o]*\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/i,mN=/([a-z_0-9]+)\s*:\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/gi,fN={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 yN extends ET{constructor(e){const{type:t,inputs:r,name:s,inputsCode:i,blockCode:n,outputType:o}=(e=>{const t=(e=e.trim()).match(gN);if(null!==t&&4===t.length){const r=t[2],s=[];let i=null;for(;null!==(i=mN.exec(r));)s.push({name:i[1],type:i[2]});const n=[];for(let e=0;e "+this.outputType:"";return`fn ${e} ( ${this.inputsCode.trim()} ) ${t}`+this.blockCode}}class bN extends CT{parseFunction(e){return new yN(e)}}const xN="undefined"!=typeof self?self.GPUShaderStage:{VERTEX:1,FRAGMENT:2,COMPUTE:4},TN={[Ss.READ_ONLY]:"read",[Ss.WRITE_ONLY]:"write",[Ss.READ_WRITE]:"read_write"},_N={[dr]:"repeat",[cr]:"clamp",[hr]:"mirror"},vN={vertex:xN?xN.VERTEX:1,fragment:xN?xN.FRAGMENT:2,compute:xN?xN.COMPUTE:4},NN={instance:!0,swizzleAssign:!1,storageBuffer:!0},SN={"^^":"tsl_xor"},AN={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",mat3:"mat3x3",mat4:"mat4x4"},RN={},CN={tsl_xor:new iy("fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }"),mod_float:new iy("fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }"),mod_vec2:new iy("fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }"),mod_vec3:new iy("fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }"),mod_vec4:new iy("fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }"),equals_bool:new iy("fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }"),equals_bvec2:new iy("fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }"),equals_bvec3:new iy("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 iy("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_float:new iy("fn tsl_repeatWrapping_float( coord: f32 ) -> f32 { return fract( coord ); }"),mirrorWrapping_float:new iy("fn tsl_mirrorWrapping_float( coord: f32 ) -> f32 { let mirrored = fract( coord * 0.5 ) * 2.0; return 1.0 - abs( 1.0 - mirrored ); }"),clampWrapping_float:new iy("fn tsl_clampWrapping_float( coord: f32 ) -> f32 { return clamp( coord, 0.0, 1.0 ); }"),biquadraticTexture:new iy("\nfn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, iRes : vec2u, level : u32 ) -> vec4f {\n\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, vec2u( iuv + vec2( 0.5, 0.5 ) ) % iRes, level );\n\tlet rg2 = textureLoad( map, vec2u( iuv + vec2( 1.5, 0.5 ) ) % iRes, level );\n\tlet rg3 = textureLoad( map, vec2u( iuv + vec2( 0.5, 1.5 ) ) % iRes, level );\n\tlet rg4 = textureLoad( map, vec2u( 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")},EN={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"};"undefined"!=typeof navigator&&/Windows/g.test(navigator.userAgent)&&(CN.pow_float=new iy("fn tsl_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }"),CN.pow_vec2=new iy("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 ) ); }",[CN.pow_float]),CN.pow_vec3=new iy("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 ) ); }",[CN.pow_float]),CN.pow_vec4=new iy("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 ) ); }",[CN.pow_float]),EN.pow_float="tsl_pow_float",EN.pow_vec2="tsl_pow_vec2",EN.pow_vec3="tsl_pow_vec3",EN.pow_vec4="tsl_pow_vec4");let wN="";!0!==("undefined"!=typeof navigator&&/Firefox|Deno/g.test(navigator.userAgent))&&(wN+="diagnostic( off, derivative_uniformity );\n");class MN extends gT{constructor(e,t){super(e,t,new bN),this.uniformGroups={},this.builtins={},this.directives={},this.scopedArrays=new Map}needsToWorkingColorSpace(e){return!0===e.isVideoTexture&&e.colorSpace!==m}_generateTextureSample(e,t,r,s,i=this.shaderStage){return"fragment"===i?s?`textureSample( ${t}, ${t}_sampler, ${r}, ${s} )`:`textureSample( ${t}, ${t}_sampler, ${r} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,r):this.generateTextureLod(e,t,r,s,"0")}_generateVideoSample(e,t,r=this.shaderStage){if("fragment"===r)return`textureSampleBaseClampToEdge( ${e}, ${e}_sampler, vec2( ${t}.x, 1.0 - ${t}.y ) )`;console.error(`WebGPURenderer: THREE.VideoTexture does not support ${r} shader.`)}_generateTextureSampleLevel(e,t,r,s,i,n=this.shaderStage){return"fragment"!==n&&"compute"!==n||!1!==this.isUnfilterable(e)?this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,r,s):this.generateTextureLod(e,t,r,i,s):`textureSampleLevel( ${t}, ${t}_sampler, ${r}, ${s} )`}generateWrapFunction(e){const t=`tsl_coord_${_N[e.wrapS]}S_${_N[e.wrapT]}T`;let r=RN[t];if(void 0===r){const s=[];let i=`fn ${t}( coord : vec2f ) -> vec2f {\n\n\treturn vec2f(\n`;const n=(e,t)=>{e===dr?(s.push(CN.repeatWrapping_float),i+=`\t\ttsl_repeatWrapping_float( coord.${t} )`):e===cr?(s.push(CN.clampWrapping_float),i+=`\t\ttsl_clampWrapping_float( coord.${t} )`):e===hr?(s.push(CN.mirrorWrapping_float),i+=`\t\ttsl_mirrorWrapping_float( coord.${t} )`):(i+=`\t\tcoord.${t}`,console.warn(`WebGPURenderer: Unsupported texture wrap type "${e}" for vertex shader.`))};n(e.wrapS,"x"),i+=",\n",n(e.wrapT,"y"),i+="\n\t);\n\n}\n",RN[t]=r=new iy(i,s)}return r.build(this),t}generateTextureDimension(e,t,r){const s=this.getDataFromNode(e,this.shaderStage,this.globalCache);void 0===s.dimensionsSnippet&&(s.dimensionsSnippet={});let i=s.dimensionsSnippet[r];if(void 0===s.dimensionsSnippet[r]){let n;const{primarySamples:o}=this.renderer.backend.utils.getTextureSampleData(e);n=o>1?t:`${t}, u32( ${r} )`,i=new Aa(new ou(`textureDimensions( ${n} )`,"uvec2")),s.dimensionsSnippet[r]=i}return i.build(this)}generateFilteredTexture(e,t,r,s="0u"){this._include("biquadraticTexture");return`tsl_biquadraticTexture( ${t}, ${this.generateWrapFunction(e)}( ${r} ), ${this.generateTextureDimension(e,t,s)}, u32( ${s} ) )`}generateTextureLod(e,t,r,s,i="0u"){const n=`vec2u( ${this.generateWrapFunction(e)}( ${r} ) * vec2f( ${this.generateTextureDimension(e,t,i)} ) )`;return this.generateTextureLoad(e,t,n,s,i)}generateTextureLoad(e,t,r,s,i="0u"){return!0===e.isVideoTexture||!0===e.isStorageTexture?`textureLoad( ${t}, ${r} )`:s?`textureLoad( ${t}, ${r}, ${s}, u32( ${i} ) )`:`textureLoad( ${t}, ${r}, u32( ${i} ) )`}generateTextureStore(e,t,r,s){return`textureStore( ${t}, ${r}, ${s} )`}isSampleCompare(e){return!0===e.isDepthTexture&&null!==e.compareFunction}isUnfilterable(e){return"float"!==this.getComponentTypeFromTexture(e)||!this.isAvailable("float32Filterable")&&!0===e.isDataTexture&&e.type===E||!1===this.isSampleCompare(e)&&e.minFilter===pr&&e.magFilter===pr||this.renderer.backend.utils.getTextureSampleData(e).primarySamples>1}generateTexture(e,t,r,s,i=this.shaderStage){let n=null;return n=!0===e.isVideoTexture?this._generateVideoSample(t,r,i):this.isUnfilterable(e)?this.generateTextureLod(e,t,r,s,"0",i):this._generateTextureSample(e,t,r,s,i),n}generateTextureGrad(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleGrad( ${t}, ${t}_sampler, ${r}, ${s[0]}, ${s[1]} )`;console.error(`WebGPURenderer: THREE.TextureNode.gradient() does not support ${n} shader.`)}generateTextureCompare(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleCompare( ${t}, ${t}_sampler, ${r}, ${s} )`;console.error(`WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${n} shader.`)}generateTextureLevel(e,t,r,s,i,n=this.shaderStage){let o=null;return o=!0===e.isVideoTexture?this._generateVideoSample(t,r,n):this._generateTextureSampleLevel(e,t,r,s,i,n),o}generateTextureBias(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleBias( ${t}, ${t}_sampler, ${r}, ${s} )`;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,r=e.type;return"texture"===r||"cubeTexture"===r||"storageTexture"===r||"texture3D"===r?t:"buffer"===r||"storageBuffer"===r||"indirectStorageBuffer"===r?`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=SN[e];return void 0!==t?(this._include(t),t):null}getNodeAccess(e,t){return"compute"!==t?Ss.READ_ONLY:e.access}getStorageAccess(e,t){return TN[this.getNodeAccess(e,t)]}getUniformFromNode(e,t,r,s=null){const i=super.getUniformFromNode(e,t,r,s),n=this.getDataFromNode(e,r,this.globalCache);if(void 0===n.uniformGPU){let s;const o=e.groupNode,a=o.name,u=this.getBindGroupArray(a,r);if("texture"===t||"cubeTexture"===t||"storageTexture"===t||"texture3D"===t){let n=null;const a=this.getNodeAccess(e,r);if("texture"===t||"storageTexture"===t?n=new o_(i.name,i.node,o,a):"cubeTexture"===t?n=new a_(i.name,i.node,o,a):"texture3D"===t&&(n=new u_(i.name,i.node,o,a)),n.store=!0===e.isStorageTextureNode,n.setVisibility(vN[r]),"fragment"!==r&&"compute"!==r||!1!==this.isUnfilterable(e.value)||!1!==n.store)u.push(n),s=[n];else{const e=new nN(`${i.name}_sampler`,i.node,o);e.setVisibility(vN[r]),u.push(e,n),s=[e,n]}}else if("buffer"===t||"storageBuffer"===t||"indirectStorageBuffer"===t){const i=new("buffer"===t?e_:uN)(e,o);i.setVisibility(vN[r]),u.push(i),s=i}else{const e=this.uniformGroups[r]||(this.uniformGroups[r]={});let n=e[a];void 0===n&&(n=new s_(a,o),n.setVisibility(vN[r]),e[a]=n,u.push(n)),s=this.getNodeUniform(i,t),n.addUniform(s)}n.uniformGPU=s}return i}getBuiltin(e,t,r,s=this.shaderStage){const i=this.builtins[s]||(this.builtins[s]=new Map);return!1===i.has(e)&&i.set(e,{name:e,property:t,type:r}),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,r=this.flowShaderNode(e),s=[];for(const e of t.inputs)s.push(e.name+" : "+this.getType(e.type));let i=`fn ${t.name}( ${s.join(", ")} ) -> ${this.getType(t.type)} {\n${r.vars}\n${r.code}\n`;return r.result&&(i+=`\treturn ${r.result};\n`),i+="\n}\n",i}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")}getClipDistance(){return"varyings.hw_clip_distances"}isFlipY(){return!1}enableDirective(e,t=this.shaderStage){(this.directives[t]||(this.directives[t]=new Set)).add(e)}getDirectives(e){const t=[],r=this.directives[e];if(void 0!==r)for(const e of r)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")}enableHardwareClipping(e){this.enableClipDistances(),this.getBuiltin("clip_distances","hw_clip_distances",`array`,"vertex")}getBuiltins(e){const t=[],r=this.builtins[e];if(void 0!==r)for(const{name:e,property:s,type:i}of r.values())t.push(`@builtin( ${e} ) ${s} : ${i}`);return t.join(",\n\t")}getScopedArray(e,t,r,s){return!1===this.scopedArrays.has(e)&&this.scopedArrays.set(e,{name:e,scope:t,bufferType:r,bufferCount:s}),e}getScopedArrays(e){if("compute"!==e)return;const t=[];for(const{name:e,scope:r,bufferType:s,bufferCount:i}of this.scopedArrays.values()){const n=this.getType(s);t.push(`var<${r}> ${e}: array< ${n}, ${i} >;`)}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 r=this.getAttributesArray();for(let e=0,s=r.length;e`)}const s=this.getBuiltins("output");return s&&t.push("\t"+s),t.join(",\n")}getStructs(e){const t=[],r=this.structs[e];for(let e=0,s=r.length;e output : ${i};\n\n`)}return t.join("\n\n")}getVar(e,t){return`var ${t} : ${this.getType(e)}`}getVars(e){const t=[],r=this.vars[e];if(void 0!==r)for(const e of r)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 r=this.varyings,s=this.vars[e];for(let i=0;i1&&(n="_multisampled"),!0===t.isCubeTexture)s="texture_cube";else if(!0===t.isDataArrayTexture||!0===t.isCompressedArrayTexture)s="texture_2d_array";else if(!0===t.isDepthTexture)s=`texture_depth${n}_2d`;else if(!0===t.isVideoTexture)s="texture_external";else if(!0===t.isData3DTexture)s="texture_3d";else if(!0===i.node.isStorageTextureNode){s=`texture_storage_2d<${pN(t)}, ${this.getStorageAccess(i.node,e)}>`}else{s=`texture${n}_2d<${this.getComponentTypeFromTexture(t).charAt(0)}32>`}r.push(`@binding( ${o.binding++} ) @group( ${o.group} ) var ${i.name} : ${s};`)}else if("buffer"===i.type||"storageBuffer"===i.type||"indirectStorageBuffer"===i.type){const t=i.node,r=this.getType(t.bufferType),n=t.bufferCount,a=n>0&&"buffer"===i.type?", "+n:"",u=t.isAtomic?`atomic<${r}>`:`${r}`,l=`\t${i.name} : array< ${u}${a} >\n`,d=t.isStorageBufferNode?`storage, ${this.getStorageAccess(t,e)}`:"uniform";s.push(this._getWGSLStructBinding("NodeBuffer_"+t.id,l,d,o.binding++,o.group))}else{const e=this.getType(this.getVectorType(i.type)),t=i.groupNode.name;(n[t]||(n[t]={index:o.binding++,id:o.group,snippets:[]})).snippets.push(`\t${i.name} : ${e}`)}}for(const e in n){const t=n[e];i.push(this._getWGSLStructBinding(e,t.snippets.join(",\n"),"uniform",t.index,t.id))}let o=r.join("\n");return o+=s.join("\n"),o+=i.join("\n"),o}buildCode(){const e=null!==this.material?{fragment:{},vertex:{}}:{compute:{}};this.sortBindingGroups();for(const t in e){const r=e[t];r.uniforms=this.getUniforms(t),r.attributes=this.getAttributes(t),r.varyings=this.getVaryings(t),r.structs=this.getStructs(t),r.vars=this.getVars(t),r.codes=this.getCodes(t),r.directives=this.getDirectives(t),r.scopedArrays=this.getScopedArrays(t);let s="// code\n\n";s+=this.flowCode[t];const i=this.flowNodes[t],n=i[i.length-1],o=n.outputNode,a=void 0!==o&&!0===o.isOutputStructNode;for(const e of i){const i=this.getFlowData(e),u=e.name;if(u&&(s.length>0&&(s+="\n"),s+=`\t// flow -> ${u}\n\t`),s+=`${i.code}\n\t`,e===n&&"compute"!==t)if(s+="// result\n\n\t","vertex"===t)s+=`varyings.Vertex = ${i.result};`;else if("fragment"===t)if(a)r.returnType=o.nodeType,s+=`return ${i.result};`;else{let e="\t@location(0) color: vec4";const t=this.getBuiltins("output");t&&(e+=",\n\t"+t),r.returnType="OutputStruct",r.structs+=this._getWGSLStruct("OutputStruct",e),r.structs+="\nvar output : OutputStruct;\n\n",s+=`output.color = ${i.result};\n\n\treturn output;`}}r.flow=s}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 r;return null!==t&&(r=this._getWGSLMethod(e+"_"+t)),void 0===r&&(r=this._getWGSLMethod(e)),r||e}getType(e){return AN[e]||e}isAvailable(e){let t=NN[e];return void 0===t&&("float32Filterable"===e?t=this.renderer.hasFeature("float32-filterable"):"clipDistance"===e&&(t=this.renderer.hasFeature("clip-distances")),NN[e]=t),t}_getWGSLMethod(e){return void 0!==CN[e]&&this._include(e),EN[e]}_include(e){const t=CN[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${wN}\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,r,s=0,i=0){const n=e+"Struct";return`${this._getWGSLStruct(n,t)}\n@binding( ${s} ) @group( ${i} )\nvar<${r}> ${e} : ${n};`}}class BN{constructor(e){this.backend=e}getCurrentDepthStencilFormat(e){let t;return null!==e.depthTexture?t=this.getTextureFormatGPU(e.depthTexture):e.depth&&e.stencil?t=iv.Depth24PlusStencil8:e.depth&&(t=iv.Depth24Plus),t}getTextureFormatGPU(e){return this.backend.get(e).format}getTextureSampleData(e){let t;if(e.isFramebufferTexture)t=1;else if(e.isDepthTexture&&!e.renderTarget){const e=this.backend.renderer,r=e.getRenderTarget();t=r?r.samples:e.samples}else e.renderTarget&&(t=e.renderTarget.samples);t=t||1;const r=t>1&&null!==e.renderTarget&&!0!==e.isDepthTexture&&!0!==e.isFramebufferTexture;return{samples:t,primarySamples:r?1:t,isMSAA:r}}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?L_:e.isLineSegments||e.isMesh&&!0===t.wireframe?D_:e.isLine?V_:e.isMesh?O_: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")?iv.BGRA8Unorm:navigator.gpu.getPreferredCanvasFormat()}}const UN=new Map([[Int8Array,["sint8","snorm8"]],[Uint8Array,["uint8","unorm8"]],[Int16Array,["sint16","snorm16"]],[Uint16Array,["uint16","unorm16"]],[Int32Array,["sint32","snorm32"]],[Uint32Array,["uint32","unorm32"]],[Float32Array,["float32"]]]),FN=new Map([[Le,["float16"]]]),PN=new Map([[Int32Array,"sint32"],[Int16Array,"sint32"],[Uint32Array,"uint32"],[Uint16Array,"uint32"],[Float32Array,"float32"]]);class IN{constructor(e){this.backend=e}createAttribute(e,t){const r=this._getBufferAttribute(e),s=this.backend,i=s.get(r);let n=i.buffer;if(void 0===n){const o=s.device;let a=r.array;if(!1===e.normalized&&(a.constructor===Int16Array||a.constructor===Uint16Array)){const e=new Uint32Array(a.length);for(let t=0;t1&&(s.multisampled=!0,r.texture.isDepthTexture||(s.sampleType=Hv)),r.texture.isDepthTexture)s.sampleType=Wv;else if(r.texture.isDataTexture||r.texture.isDataArrayTexture||r.texture.isData3DTexture){const e=r.texture.type;e===y?s.sampleType=jv:e===f?s.sampleType=qv:e===E&&(this.backend.hasFeature("float32-filterable")?s.sampleType=$v:s.sampleType=Hv)}r.isSampledCubeTexture?s.viewDimension=Zv:r.texture.isDataArrayTexture||r.texture.isCompressedArrayTexture?s.viewDimension=Qv:r.isSampledTexture3D&&(s.viewDimension=Jv),e.texture=s}else console.error(`WebGPUBindingUtils: Unsupported binding "${r}".`);s.push(e)}return r.createBindGroupLayout({entries:s})}createBindings(e,t,r,s=0){const{backend:i,bindGroupLayoutCache:n}=this,o=i.get(e);let a,u=n.get(e.bindingsReference);void 0===u&&(u=this.createBindingsLayout(e),n.set(e.bindingsReference,u)),r>0&&(void 0===o.groups&&(o.groups=[],o.versions=[]),o.versions[r]===s&&(a=o.groups[r])),void 0===a&&(a=this.createBindGroup(e,u),r>0&&(o.groups[r]=a,o.versions[r]=s)),o.group=a,o.layout=u}updateBinding(e){const t=this.backend,r=t.device,s=e.buffer,i=t.get(e).buffer;r.queue.writeBuffer(i,0,s,0)}createBindGroup(e,t){const r=this.backend,s=r.device;let i=0;const n=[];for(const t of e.bindings){if(t.isUniformBuffer){const e=r.get(t);if(void 0===e.buffer){const r=t.byteLength,i=GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,n=s.createBuffer({label:"bindingBuffer_"+t.name,size:r,usage:i});e.buffer=n}n.push({binding:i,resource:{buffer:e.buffer}})}else if(t.isStorageBuffer){const e=r.get(t);if(void 0===e.buffer){const s=t.attribute;e.buffer=r.get(s).buffer}n.push({binding:i,resource:{buffer:e.buffer}})}else if(t.isSampler){const e=r.get(t.texture);n.push({binding:i,resource:e.sampler})}else if(t.isSampledTexture){const e=r.get(t.texture);let o;if(void 0!==e.externalTexture)o=s.importExternalTexture({source:e.externalTexture});else{const r=t.store?1:e.texture.mipLevelCount,s=`view-${e.texture.width}-${e.texture.height}-${r}`;if(o=e[s],void 0===o){const i=eN;let n;n=t.isSampledCubeTexture?Zv:t.isSampledTexture3D?Jv:t.texture.isDataArrayTexture||t.texture.isCompressedArrayTexture?Qv:Yv,o=e[s]=e.texture.createView({aspect:i,dimension:n,mipLevelCount:r})}}n.push({binding:i,resource:o})}i++}return s.createBindGroup({label:"bindGroup_"+e.name,layout:t,entries:n})}}class DN{constructor(e){this.backend=e}_getSampleCount(e){return this.backend.utils.getSampleCountRenderContext(e)}createRenderPipeline(e,t){const{object:r,material:s,geometry:i,pipeline:n}=e,{vertexProgram:o,fragmentProgram:a}=n,u=this.backend,l=u.device,d=u.utils,c=u.get(n),h=[];for(const t of e.getBindings()){const e=u.get(t);h.push(e.layout)}const p=u.attributeUtils.createShaderVertexBuffers(e);let g;!0===s.transparent&&s.blending!==D&&(g=this._getBlending(s));let m={};!0===s.stencilWrite&&(m={compare:this._getStencilCompare(s),failOp:this._getStencilOperation(s.stencilFail),depthFailOp:this._getStencilOperation(s.stencilZFail),passOp:this._getStencilOperation(s.stencilZPass)});const f=this._getColorWriteMask(s),y=[];if(null!==e.context.textures){const t=e.context.textures;for(let e=0;e1},layout:l.createPipelineLayout({bindGroupLayouts:h})},A={},R=e.context.depth,C=e.context.stencil;if(!0!==R&&!0!==C||(!0===R&&(A.format=v,A.depthWriteEnabled=s.depthWrite,A.depthCompare=_),!0===C&&(A.stencilFront=m,A.stencilBack={},A.stencilReadMask=s.stencilFuncMask,A.stencilWriteMask=s.stencilWriteMask),S.depthStencil=A),null===t)c.pipeline=l.createRenderPipeline(S);else{const e=new Promise((e=>{l.createRenderPipelineAsync(S).then((t=>{c.pipeline=t,e()}))}));t.push(e)}}createBundleEncoder(e){const t=this.backend,{utils:r,device:s}=t,i=r.getCurrentDepthStencilFormat(e),n={label:"renderBundleEncoder",colorFormats:[r.getCurrentColorFormat(e)],depthStencilFormat:i,sampleCount:this._getSampleCount(e)};return s.createRenderBundleEncoder(n)}createComputePipeline(e,t){const r=this.backend,s=r.device,i=r.get(e.computeProgram).module,n=r.get(e),o=[];for(const e of t){const t=r.get(e);o.push(t.layout)}n.pipeline=s.createComputePipeline({compute:i,layout:s.createPipelineLayout({bindGroupLayouts:o})})}_getBlending(e){let t,r;const s=e.blending,i=e.blendSrc,n=e.blendDst,o=e.blendEquation;if(s===ft){const s=null!==e.blendSrcAlpha?e.blendSrcAlpha:i,a=null!==e.blendDstAlpha?e.blendDstAlpha:n,u=null!==e.blendEquationAlpha?e.blendEquationAlpha:o;t={srcFactor:this._getBlendFactor(i),dstFactor:this._getBlendFactor(n),operation:this._getBlendOperation(o)},r={srcFactor:this._getBlendFactor(s),dstFactor:this._getBlendFactor(a),operation:this._getBlendOperation(u)}}else{const i=(e,s,i,n)=>{t={srcFactor:e,dstFactor:s,operation:Nv},r={srcFactor:i,dstFactor:n,operation:Nv}};if(e.premultipliedAlpha)switch(s){case F:i(cv,mv,cv,mv);break;case xt:i(cv,cv,cv,cv);break;case bt:i(dv,pv,dv,cv);break;case yt:i(dv,hv,dv,gv)}else switch(s){case F:i(gv,mv,cv,mv);break;case xt:i(gv,cv,gv,cv);break;case bt:i(dv,pv,dv,cv);break;case yt:i(dv,hv,dv,hv)}}if(void 0!==t&&void 0!==r)return{color:t,alpha:r};console.error("THREE.WebGPURenderer: Invalid blending: ",s)}_getBlendFactor(e){let t;switch(e){case rt:t=dv;break;case st:t=cv;break;case it:t=hv;break;case lt:t=pv;break;case nt:t=gv;break;case dt:t=mv;break;case at:t=fv;break;case ct:t=yv;break;case ut:t=bv;break;case ht:t=xv;break;case ot:t=Tv;break;case 211:t=_v;break;case 212:t=vv;break;default:console.error("THREE.WebGPURenderer: Blend factor not supported.",e)}return t}_getStencilCompare(e){let t;const r=e.stencilFunc;switch(r){case Mr:t=k_;break;case wr:t=K_;break;case Er:t=z_;break;case Cr:t=H_;break;case Rr:t=$_;break;case Ar:t=q_;break;case Sr:t=W_;break;case Nr:t=j_;break;default:console.error("THREE.WebGPURenderer: Invalid stencil function.",r)}return t}_getStencilOperation(e){let t;switch(e){case Vr:t=Mv;break;case Dr:t=Bv;break;case Lr:t=Uv;break;case Ir:t=Fv;break;case Pr:t=Pv;break;case Fr:t=Iv;break;case Ur:t=Lv;break;case Br:t=Dv;break;default:console.error("THREE.WebGPURenderer: Invalid stencil operation.",t)}return t}_getBlendOperation(e){let t;switch(e){case Je:t=Nv;break;case et:t=Sv;break;case tt:t=Av;break;case Gr:t=Rv;break;case Or:t=Cv;break;default:console.error("THREE.WebGPUPipelineUtils: Blend equation not supported.",e)}return t}_getPrimitiveState(e,t,r){const s={},i=this.backend.utils;switch(s.topology=i.getPrimitiveTopology(e,r),null!==t.index&&!0===e.isLine&&!0!==e.isLineSegments&&(s.stripIndexFormat=t.index.array instanceof Uint16Array?rv:sv),r.side){case Ge:s.frontFace=Z_,s.cullMode=tv;break;case x:s.frontFace=Z_,s.cullMode=ev;break;case le:s.frontFace=Z_,s.cullMode=J_;break;default:console.error("THREE.WebGPUPipelineUtils: Unknown material.side value.",r.side)}return s}_getColorWriteMask(e){return!0===e.colorWrite?wv:Ev}_getDepthCompare(e){let t;if(!1===e.depthTest)t=K_;else{const r=e.depthFunc;switch(r){case Ct:t=k_;break;case Rt:t=K_;break;case At:t=z_;break;case St:t=H_;break;case Nt:t=$_;break;case vt:t=q_;break;case _t:t=W_;break;case Tt:t=j_;break;default:console.error("THREE.WebGPUPipelineUtils: Invalid depth function.",r)}}return t}}class VN extends y_{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 BN(this),this.attributeUtils=new IN(this),this.bindingUtils=new LN(this),this.pipelineUtils=new DN(this),this.textureUtils=new hN(this),this.occludedResolveCache=new Map}async init(e){await super.init(e);const t=this.parameters;let r;if(void 0===t.device){const e={powerPreference:t.powerPreference},s="undefined"!=typeof navigator?await navigator.gpu.requestAdapter(e):null;if(null===s)throw new Error("WebGPUBackend: Unable to create WebGPU adapter.");const i=Object.values(sN),n=[];for(const e of i)s.features.has(e)&&n.push(e);const o={requiredFeatures:n,requiredLimits:t.requiredLimits};r=await s.requestDevice(o)}else r=t.device;r.lost.then((t=>{const r={api:"WebGPU",message:t.message||"Unknown reason",reason:t.reason||null,originalEvent:t};e.onDeviceLost(r)}));const s=void 0!==t.context?t.context:e.domElement.getContext("webgpu");this.device=r,this.context=s;const i=t.alpha?"premultiplied":"opaque";this.trackTimestamp=this.trackTimestamp&&this.hasFeature(sN.TimestampQuery),this.context.configure({device:this.device,format:this.utils.getPreferredCanvasFormat(),usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:i}),this.updateSize()}get coordinateSystem(){return v}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}]},!0!==this.renderer.depth&&!0!==this.renderer.stencil||(e.depthStencilAttachment={view:this.textureUtils.getDepthBuffer(t.depth,t.stencil).createView()});const r=e.colorAttachments[0];this.renderer.samples>0?r.view=this.colorBuffer.createView():r.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,r=this.get(t);let s=r.descriptors;if(void 0===s||r.width!==t.width||r.height!==t.height||r.activeMipmapLevel!==t.activeMipmapLevel||r.samples!==t.samples){s={},r.descriptors=s;const e=()=>{t.removeEventListener("dispose",e),this.delete(t)};t.addEventListener("dispose",e)}const i=e.getCacheKey();let n=s[i];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,i=r.createQuerySet({type:"occlusion",count:s,label:`occlusionQuerySet_${e.id}`}),t.occlusionQuerySet=i,t.occlusionQueryIndex=0,t.occlusionQueryObjects=new Array(s),t.lastOcclusionObject=null),n=null===e.textures?this._getDefaultRenderPassDescriptor():this._getRenderPassDescriptor(e),this.initTimestampQuery(e,n),n.occlusionQuerySet=i;const o=n.depthStencilAttachment;if(null!==e.textures){const t=n.colorAttachments;for(let r=0;r0&&t.currentPass.executeBundles(t.renderBundles),r>t.occlusionQueryIndex&&t.currentPass.endOcclusionQuery(),t.currentPass.end(),r>0){const s=8*r;let i=this.occludedResolveCache.get(s);void 0===i&&(i=this.device.createBuffer({size:s,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),this.occludedResolveCache.set(s,i));const n=this.device.createBuffer({size:s,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});t.encoder.resolveQuerySet(t.occlusionQuerySet,0,r,i,0),t.encoder.copyBufferToBuffer(i,0,n,0,s),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?(u.x=Math.min(t.dispatchCount,o),u.y=Math.ceil(t.dispatchCount/o)):u.x=t.dispatchCount,i.dispatchWorkgroups(u.x,u.y,u.z)}finishCompute(e){const t=this.get(e);t.passEncoderGPU.end(),this.prepareTimestampBuffer(e,t.cmdEncoderGPU),this.device.queue.submit([t.cmdEncoderGPU.finish()])}async waitForGPU(){await this.device.queue.onSubmittedWorkDone()}draw(e,t){const{object:r,context:s,pipeline:i}=e,n=e.getBindings(),o=this.get(s),a=this.get(i).pipeline,u=o.currentSets,l=o.currentPass,d=e.getDrawParameters();if(null===d)return;u.pipeline!==a&&(l.setPipeline(a),u.pipeline=a);const c=u.bindingGroups;for(let e=0,t=n.length;e1?0:r;l.drawIndexed(t[r],s,e[r]/n,0,o)}}else if(!0===p){const{vertexCount:s,instanceCount:i,firstVertex:n}=d,o=e.getIndirect();if(null!==o){const e=this.get(o).buffer;l.drawIndexedIndirect(e,0)}else l.drawIndexed(s,i,n,0,0);t.update(r,s,i)}else{const{vertexCount:s,instanceCount:i,firstVertex:n}=d,o=e.getIndirect();if(null!==o){const e=this.get(o).buffer;l.drawIndirect(e,0)}else l.draw(s,i,n,0);t.update(r,s,i)}}needsRenderUpdate(e){const t=this.get(e),{object:r,material:s}=e,i=this.utils,n=i.getSampleCountRenderContext(e.context),o=i.getCurrentColorSpace(e.context),a=i.getCurrentColorFormat(e.context),u=i.getCurrentDepthStencilFormat(e.context),l=i.getPrimitiveTopology(r,s);let d=!1;return t.material===s&&t.materialVersion===s.version&&t.transparent===s.transparent&&t.blending===s.blending&&t.premultipliedAlpha===s.premultipliedAlpha&&t.blendSrc===s.blendSrc&&t.blendDst===s.blendDst&&t.blendEquation===s.blendEquation&&t.blendSrcAlpha===s.blendSrcAlpha&&t.blendDstAlpha===s.blendDstAlpha&&t.blendEquationAlpha===s.blendEquationAlpha&&t.colorWrite===s.colorWrite&&t.depthWrite===s.depthWrite&&t.depthTest===s.depthTest&&t.depthFunc===s.depthFunc&&t.stencilWrite===s.stencilWrite&&t.stencilFunc===s.stencilFunc&&t.stencilFail===s.stencilFail&&t.stencilZFail===s.stencilZFail&&t.stencilZPass===s.stencilZPass&&t.stencilFuncMask===s.stencilFuncMask&&t.stencilWriteMask===s.stencilWriteMask&&t.side===s.side&&t.alphaToCoverage===s.alphaToCoverage&&t.sampleCount===n&&t.colorSpace===o&&t.colorFormat===a&&t.depthStencilFormat===u&&t.primitiveTopology===l&&t.clippingContextCacheKey===e.clippingContextCacheKey||(t.material=s,t.materialVersion=s.version,t.transparent=s.transparent,t.blending=s.blending,t.premultipliedAlpha=s.premultipliedAlpha,t.blendSrc=s.blendSrc,t.blendDst=s.blendDst,t.blendEquation=s.blendEquation,t.blendSrcAlpha=s.blendSrcAlpha,t.blendDstAlpha=s.blendDstAlpha,t.blendEquationAlpha=s.blendEquationAlpha,t.colorWrite=s.colorWrite,t.depthWrite=s.depthWrite,t.depthTest=s.depthTest,t.depthFunc=s.depthFunc,t.stencilWrite=s.stencilWrite,t.stencilFunc=s.stencilFunc,t.stencilFail=s.stencilFail,t.stencilZFail=s.stencilZFail,t.stencilZPass=s.stencilZPass,t.stencilFuncMask=s.stencilFuncMask,t.stencilWriteMask=s.stencilWriteMask,t.side=s.side,t.alphaToCoverage=s.alphaToCoverage,t.sampleCount=n,t.colorSpace=o,t.colorFormat=a,t.depthStencilFormat=u,t.primitiveTopology=l,t.clippingContextCacheKey=e.clippingContextCacheKey,d=!0),d}getRenderCacheKey(e){const{object:t,material:r}=e,s=this.utils,i=e.context;return[r.transparent,r.blending,r.premultipliedAlpha,r.blendSrc,r.blendDst,r.blendEquation,r.blendSrcAlpha,r.blendDstAlpha,r.blendEquationAlpha,r.colorWrite,r.depthWrite,r.depthTest,r.depthFunc,r.stencilWrite,r.stencilFunc,r.stencilFail,r.stencilZFail,r.stencilZPass,r.stencilFuncMask,r.stencilWriteMask,r.side,s.getSampleCountRenderContext(i),s.getCurrentColorSpace(i),s.getCurrentColorFormat(i),s.getCurrentDepthStencilFormat(i),s.getPrimitiveTopology(t,r),e.getGeometryCacheKey(),e.clippingContextCacheKey].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,r,s,i,n){return this.textureUtils.copyTextureToBuffer(e,t,r,s,i,n)}initTimestampQuery(e,t){if(!this.trackTimestamp)return;const r=this.get(e);if(!r.timeStampQuerySet){const s=e.isComputeNode?"compute":"render",i=this.device.createQuerySet({type:"timestamp",count:2,label:`timestamp_${s}_${e.id}`}),n={querySet:i,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1};Object.assign(t,{timestampWrites:n}),r.timeStampQuerySet=i}}prepareTimestampBuffer(e,t){if(!this.trackTimestamp)return;const r=this.get(e),s=2*BigInt64Array.BYTES_PER_ELEMENT;void 0===r.currentTimestampQueryBuffers&&(r.currentTimestampQueryBuffers={resolveBuffer:this.device.createBuffer({label:"timestamp resolve buffer",size:s,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),resultBuffer:this.device.createBuffer({label:"timestamp result buffer",size:s,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ})});const{resolveBuffer:i,resultBuffer:n}=r.currentTimestampQueryBuffers;t.resolveQuerySet(r.timeStampQuerySet,0,2,i,0),"unmapped"===n.mapState&&t.copyBufferToBuffer(i,0,n,0,s)}async resolveTimestampAsync(e,t="render"){if(!this.trackTimestamp)return;const r=this.get(e);if(void 0===r.currentTimestampQueryBuffers)return;const{resultBuffer:s}=r.currentTimestampQueryBuffers;"unmapped"===s.mapState&&s.mapAsync(GPUMapMode.READ).then((()=>{const e=new BigUint64Array(s.getMappedRange()),r=Number(e[1]-e[0])/1e6;this.renderer.info.updateTimestamp(t,r),s.unmap()}))}createNodeBuilder(e,t){return new MN(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 r=this.get(e),s=r.currentPass.finish();this.get(t).bundleGPU=s,r.currentSets=r._currentSets,r.currentPass=r._currentPass}addBundle(e,t){this.get(e).renderBundles.push(this.get(t).bundleGPU)}createBindings(e,t,r,s){this.bindingUtils.createBindings(e,t,r,s)}updateBindings(e,t,r,s){this.bindingUtils.createBindings(e,t,r,s)}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)}createIndirectStorageAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.STORAGE|GPUBufferUsage.INDIRECT|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,r=null,s=null,i=0){let n=0,o=0,a=0,u=0,l=0,d=0,c=e.image.width,h=e.image.height;null!==r&&(u=r.x,l=r.y,d=r.z||0,c=r.width,h=r.height),null!==s&&(n=s.x,o=s.y,a=s.z||0);const p=this.device.createCommandEncoder({label:"copyTextureToTexture_"+e.id+"_"+t.id}),g=this.get(e).texture,m=this.get(t).texture;p.copyTextureToTexture({texture:g,mipLevel:i,origin:{x:u,y:l,z:d}},{texture:m,mipLevel:i,origin:{x:n,y:o,z:a}},[c,h,1]),this.device.queue.submit([p.finish()])}copyFramebufferToTexture(e,t,r){const s=this.get(t);let i=null;i=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 n=this.get(e).texture;if(i.format!==n.format)return void console.error("WebGPUBackend: copyFramebufferToTexture: Source and destination formats do not match.",i.format,n.format);let o;if(s.currentPass?(s.currentPass.end(),o=s.encoder):o=this.device.createCommandEncoder({label:"copyFramebufferToTexture_"+e.id}),o.copyTextureToTexture({texture:i,origin:[r.x,r.y,0]},{texture:n},[r.z,r.w]),e.generateMipmaps&&this.textureUtils.generateMipmaps(e),s.currentPass){const{descriptor:e}=s;for(let t=0;t(console.warn("THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend."),new I_(e)));super(new t(e),e),this.library=new GN,this.isWebGPURenderer=!0}}class zN extends es{constructor(){super(),this.isBundleGroup=!0,this.type="BundleGroup",this.static=!0,this.version=0}set needsUpdate(e){!0===e&&this.version++}}const $N=new Yc,HN=new Jm($N);class WN{constructor(e,t=Oi(0,0,1,1)){this.renderer=e,this.outputNode=t,this.outputColorTransform=!0,this.needsUpdate=!0,$N.name="PostProcessing"}render(){this.update();const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;e.toneMapping=d,e.outputColorSpace=Ae,HN.render(e),e.toneMapping=t,e.outputColorSpace=r}update(){if(!0===this.needsUpdate){const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;HN.material.fragmentNode=!0===this.outputColorTransform?du(this.outputNode,t,r):this.outputNode.context({toneMapping:t,outputColorSpace:r}),HN.material.needsUpdate=!0,this.needsUpdate=!1}}async renderAsync(){this.update();const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;e.toneMapping=d,e.outputColorSpace=Ae,await HN.renderAsync(e),e.toneMapping=t,e.outputColorSpace=r}}function jN(t,r={}){return r.toneMapping=t.toneMapping,r.toneMappingExposure=t.toneMappingExposure,r.outputColorSpace=t.outputColorSpace,r.renderTarget=t.getRenderTarget(),r.activeCubeFace=t.getActiveCubeFace(),r.activeMipmapLevel=t.getActiveMipmapLevel(),r.renderObjectFunction=t.getRenderObjectFunction(),r.pixelRatio=t.getPixelRatio(),r.mrt=t.getMRT(),r.clearColor=t.getClearColor(r.clearColor||new e),r.clearAlpha=t.getClearAlpha(),r.autoClear=t.autoClear,r.scissorTest=t.getScissorTest(),r}function qN(e,t){e.toneMapping=t.toneMapping,e.toneMappingExposure=t.toneMappingExposure,e.outputColorSpace=t.outputColorSpace,e.setRenderTarget(t.renderTarget,t.activeCubeFace,t.activeMipmapLevel),e.setRenderObjectFunction(t.renderObjectFunction),e.setPixelRatio(t.pixelRatio),e.setMRT(t.mrt),e.setClearColor(t.clearColor,t.clearAlpha),e.autoClear=t.autoClear,e.setScissorTest(t.scissorTest)}function KN(e,t,r={}){return(r=jN(e,r)).background=t.background,r.backgroundNode=t.backgroundNode,r.overrideMaterial=t.overrideMaterial,r}var XN=Object.freeze({__proto__:null,resetRendererAndSceneState:function(e,t,r){return r=KN(e,t,r),t.background=null,t.backgroundNode=null,t.overrideMaterial=null,r},resetRendererState:function(e,t){return t=jN(e,t),e.setMRT(null),e.setRenderObjectFunction(null),e.setClearColor(0,1),e.autoClear=!0,t},restoreRendererAndSceneState:function(e,t,r){qN(e,r),t.background=r.background,t.backgroundNode=r.backgroundNode,t.overrideMaterial=r.overrideMaterial},restoreRendererState:qN,saveRendererAndSceneState:KN,saveRendererState:jN});class YN extends ee{constructor(e=1,t=1){super(),this.image={width:e,height:t},this.magFilter=$,this.minFilter=$,this.isStorageTexture=!0}}class QN extends uf{constructor(e,t){super(e,t,Uint32Array),this.isIndirectStorageBufferAttribute=!0}}class ZN extends ts{constructor(e){super(e),this.textures={},this.nodes={}}load(e,t,r,s){const i=new rs(this.manager);i.setPath(this.path),i.setRequestHeader(this.requestHeader),i.setWithCredentials(this.withCredentials),i.load(e,(r=>{try{t(this.parse(JSON.parse(r)))}catch(t){s?s(t):console.error(t),this.manager.itemError(e)}}),r,s)}parseNodes(e){const t={};if(void 0!==e){for(const r of e){const{uuid:e,type:s}=r;t[e]=this.createNodeFromType(s),t[e].uuid=e}const r={nodes:t,textures:this.textures};for(const s of e){s.meta=r;t[s.uuid].deserialize(s),delete s.meta}}return t}parse(e){const t=this.createNodeFromType(e.type);t.uuid=e.uuid;const r={nodes:this.parseNodes(e.nodes),textures:this.textures};return e.meta=r,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),Ci()):fi(new this.nodes[e])}}class JN extends ss{constructor(e){super(e),this.nodes={},this.nodeMaterials={}}parse(e){const t=super.parse(e),r=this.nodes,s=e.inputNodes;for(const e in s){const i=s[e];t[e]=r[i]}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 eS extends is{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 r=super.parse(e,t);return this._nodesJSON=null,r}parseNodes(e,t){if(void 0!==e){const r=new ZN;return r.setNodes(this.nodes),r.setTextures(t),r.parseNodes(e)}return{}}parseMaterials(e,t){const r={};if(void 0!==e){const s=this.parseNodes(this._nodesJSON,t),i=new JN;i.setTextures(t),i.setNodes(s),i.setNodeMaterials(this.nodeMaterials);for(let t=0,s=e.length;t0){const{width:r,height:s}=e.context;t.bufferWidth=r,t.bufferHeight=s}this.renderObjects.set(e,t)}return t}getAttributesData(e){const t={};for(const r in e){const s=e[r];t[r]={version:s.version}}return t}containsNode(e){const t=e.material;for(const e in t)if(t[e]&&t[e].isNode)return!0;return null!==e.renderer.nodes.modelViewMatrix||null!==e.renderer.nodes.modelNormalViewMatrix}getMaterialData(e){const t={};for(const r of this.refreshUniforms){const s=e[r];null!=s&&("object"==typeof s&&void 0!==s.clone?!0===s.isTexture?t[r]={id:s.id,version:s.version}:t[r]=s.clone():t[r]=s)}return t}equals(e){const{object:t,material:r,geometry:s}=e,i=this.getRenderObjectData(e);if(!0!==i.worldMatrix.equals(t.matrixWorld))return i.worldMatrix.copy(t.matrixWorld),!1;const n=i.material;for(const e in n){const t=n[e],s=r[e];if(void 0!==t.equals){if(!1===t.equals(s))return t.copy(s),!1}else if(!0===s.isTexture){if(t.id!==s.id||t.version!==s.version)return t.id=s.id,t.version=s.version,!1}else if(t!==s)return n[e]=s,!1}if(n.transmission>0){const{width:t,height:r}=e.context;if(i.bufferWidth!==t||i.bufferHeight!==r)return i.bufferWidth=t,i.bufferHeight=r,!1}const o=i.geometry,a=s.attributes,u=o.attributes,l=Object.keys(u),d=Object.keys(a);if(l.length!==d.length)return i.geometry.attributes=this.getAttributesData(a),!1;for(const e of l){const t=u[e],r=a[e];if(void 0===r)return delete u[e],!1;if(t.version!==r.version)return t.version=r.version,!1}const c=s.index,h=o.indexVersion,p=c?c.version:null;if(h!==p)return o.indexVersion=p,!1;if(o.drawRange.start!==s.drawRange.start||o.drawRange.count!==s.drawRange.count)return o.drawRange.start=s.drawRange.start,o.drawRange.count=s.drawRange.count,!1;if(i.morphTargetInfluences){let e=!1;for(let r=0;r>>16,2246822507),r^=Math.imul(s^s>>>13,3266489909),s=Math.imul(s^s>>>16,2246822507),s^=Math.imul(r^r>>>13,3266489909),4294967296*(2097151&s)+(r>>>0)}const ls=e=>us(e),ds=e=>us(e),cs=(...e)=>us(e);function hs(e,t=!1){const r=[];!0===e.isNode&&(r.push(e.id),e=e.getSelf());for(const{property:s,childNode:i}of ps(e))r.push(us(s.slice(0,-4)),i.getCacheKey(t));return us(r)}function*ps(e,t=!1){for(const r in e){if(!0===r.startsWith("_"))continue;const s=e[r];if(!0===Array.isArray(s))for(let e=0;ee.charCodeAt(0))).buffer}var Ss=Object.freeze({__proto__:null,arrayBufferToBase64:vs,base64ToArrayBuffer:Ns,getCacheKey:hs,getDataFromObject:_s,getLengthFromType:bs,getNodeChildren:ps,getTypeFromLength:fs,getTypedArrayFromType:ys,getValueFromType:Ts,getValueType:xs,hash:cs,hashArray:ds,hashString:ls});const As={VERTEX:"vertex",FRAGMENT:"fragment"},Rs={NONE:"none",FRAME:"frame",RENDER:"render",OBJECT:"object"},Cs={BOOLEAN:"bool",INTEGER:"int",FLOAT:"float",VECTOR2:"vec2",VECTOR3:"vec3",VECTOR4:"vec4",MATRIX2:"mat2",MATRIX3:"mat3",MATRIX4:"mat4"},Es={READ_ONLY:"readOnly",WRITE_ONLY:"writeOnly",READ_WRITE:"readWrite"},ws=["fragment","vertex"],Ms=["setup","analyze","generate"],Bs=[...ws,"compute"],Us=["x","y","z","w"];let Fs=0;class Ps extends o{static get type(){return"Node"}constructor(e=null){super(),this.nodeType=e,this.updateType=Rs.NONE,this.updateBeforeType=Rs.NONE,this.updateAfterType=Rs.NONE,this.uuid=a.generateUUID(),this.version=0,this.global=!1,this.isNode=!0,this._cacheKey=null,this._cacheKeyVersion=0,Object.defineProperty(this,"id",{value:Fs++})}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,Rs.FRAME)}onRenderUpdate(e){return this.onUpdate(e,Rs.RENDER)}onObjectUpdate(e){return this.onUpdate(e,Rs.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 ps(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=cs(hs(this,e),this.customCacheKey()),this._cacheKeyVersion=this.version),this._cacheKey}customCacheKey(){return 0}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 r=0;for(const e of this.getChildren())t["node"+r++]=e;return t.outputNode||null}analyze(e){if(1===e.increaseUsage(this)){const t=e.getNodeProperties(this);for(const r of Object.values(t))r&&!0===r.isNode&&r.build(e)}}generate(e,t){const{outputNode:r}=e.getNodeProperties(this);if(r&&!0===r.isNode)return r.build(e,t)}updateBefore(){console.warn("Abstract function.")}updateAfter(){console.warn("Abstract function.")}update(){console.warn("Abstract function.")}build(e,t=null){const r=this.getShared(e);if(this!==r)return r.build(e,t);e.addNode(this),e.addChain(this);let s=null;const i=e.getBuildStage();if("setup"===i){this.updateReference(e);const t=e.getNodeProperties(this);if(!0!==t.initialized){t.initialized=!0;const r=this.setup(e),s=r&&!0===r.isNode;for(const r of Object.values(t))r&&!0===r.isNode&&r.build(e);s&&r.build(e),t.outputNode=r}}else if("analyze"===i)this.analyze(e);else if("generate"===i){if(1===this.generate.length){const r=this.getNodeType(e),i=e.getDataFromNode(this);s=i.snippet,void 0===s?(s=this.generate(e)||"",i.snippet=s):void 0!==i.flowCodes&&void 0!==e.context.nodeBlock&&e.addFlowCodeHierarchy(this,e.context.nodeBlock),s=e.format(s,r,t)}else s=this.generate(e,t)||""}return e.removeChain(this),e.addSequentialNode(this),s}getSerializeChildren(){return ps(this)}serialize(e){const t=this.getSerializeChildren(),r={};for(const{property:s,index:i,childNode:n}of t)void 0!==i?(void 0===r[s]&&(r[s]=Number.isInteger(i)?[]:{}),r[s][i]=n.toJSON(e.meta).uuid):r[s]=n.toJSON(e.meta).uuid;Object.keys(r).length>0&&(e.inputNodes=r)}deserialize(e){if(void 0!==e.inputNodes){const t=e.meta.nodes;for(const r in e.inputNodes)if(Array.isArray(e.inputNodes[r])){const s=[];for(const i of e.inputNodes[r])s.push(t[i]);this[r]=s}else if("object"==typeof e.inputNodes[r]){const s={};for(const i in e.inputNodes[r]){const n=e.inputNodes[r][i];s[i]=t[n]}this[r]=s}else{const s=e.inputNodes[r];this[r]=t[s]}}}toJSON(e){const{uuid:t,type:r}=this,s=void 0===e||"string"==typeof e;s&&(e={textures:{},images:{},nodes:{}});let i=e.nodes[t];function n(e){const t=[];for(const r in e){const s=e[r];delete s.metadata,t.push(s)}return t}if(void 0===i&&(i={uuid:t,type:r,meta:e,metadata:{version:4.6,type:"Node",generator:"Node.toJSON"}},!0!==s&&(e.nodes[i.uuid]=i),this.serialize(i),delete i.meta),s){const t=n(e.textures),r=n(e.images),s=n(e.nodes);t.length>0&&(i.textures=t),r.length>0&&(i.images=r),s.length>0&&(i.nodes=s)}return i}}class Is extends Ps{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 Ds extends Ps{static get type(){return"ConvertNode"}constructor(e,t){super(),this.node=e,this.convertTo=t}getNodeType(e){const t=this.node.getNodeType(e);let r=null;for(const s of this.convertTo.split("|"))null!==r&&e.getTypeLength(t)!==e.getTypeLength(s)||(r=s);return r}serialize(e){super.serialize(e),e.convertTo=this.convertTo}deserialize(e){super.deserialize(e),this.convertTo=e.convertTo}generate(e,t){const r=this.node,s=this.getNodeType(e),i=r.build(e,s);return e.format(i,s,t)}}class Ls extends Ps{static get type(){return"TempNode"}constructor(e=null){super(e),this.isTempNode=!0}hasDependencies(e){return e.getDataFromNode(this).usageCount>1}build(e,t){if("generate"===e.getBuildStage()){const r=e.getVectorType(this.getNodeType(e,t)),s=e.getDataFromNode(this);if(void 0!==s.propertyName)return e.format(s.propertyName,r,t);if("void"!==r&&"void"!==t&&this.hasDependencies(e)){const i=super.build(e,r),n=e.getVarFromNode(this,null,r),o=e.getPropertyName(n);return e.addLineFlowCode(`${o} = ${i}`,this),s.snippet=i,s.propertyName=o,e.format(s.propertyName,r,t)}}return super.build(e,t)}}class Vs extends Ls{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,r)=>t+e.getTypeLength(r.getNodeType(e))),0))}generate(e,t){const r=this.getNodeType(e),s=this.nodes,i=e.getComponentType(r),n=[];for(const t of s){let r=t.build(e);const s=e.getComponentType(t.getNodeType(e));s!==i&&(r=e.format(r,s,i)),n.push(r)}const o=`${e.getType(r)}( ${n.join(", ")} )`;return e.format(o,r,t)}}const Os=Us.join("");class Gs extends Ps{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(Us.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 r=this.node,s=e.getTypeLength(r.getNodeType(e));let i=null;if(s>1){let n=null;this.getVectorLength()>=s&&(n=e.getTypeFromLength(this.getVectorLength(),this.getComponentType(e)));const o=r.build(e,n);i=this.components.length===s&&this.components===Os.slice(0,this.components.length)?e.format(o,n,t):e.format(`${o}.${this.components}`,this.getNodeType(e),t)}else i=r.build(e,t);return i}serialize(e){super.serialize(e),e.components=this.components}deserialize(e){super.deserialize(e),this.components=e.components}}class ks extends Ls{static get type(){return"SetNode"}constructor(e,t,r){super(),this.sourceNode=e,this.components=t,this.targetNode=r}getNodeType(e){return this.sourceNode.getNodeType(e)}generate(e){const{sourceNode:t,components:r,targetNode:s}=this,i=this.getNodeType(e),n=e.getComponentType(s.getNodeType(e)),o=e.getTypeFromLength(r.length,n),a=s.build(e,o),u=t.build(e,i),l=e.getTypeLength(i),d=[];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"),Xs=e=>Ks(e).split("").sort().join(""),Ys={setup(e,t){const r=t.shift();return e(_i(r),...t)},get(e,t,r){if("string"==typeof t&&void 0===e[t]){if(!0!==e.isStackNode&&"assign"===t)return(...e)=>(Ws.assign(r,...e),r);if(js.has(t)){const s=js.get(t);return e.isStackNode?(...e)=>r.add(s(...e)):(...e)=>s(r,...e)}if("self"===t)return e;if(t.endsWith("Assign")&&js.has(t.slice(0,t.length-6))){const s=js.get(t.slice(0,t.length-6));return e.isStackNode?(...e)=>r.assign(e[0],s(...e)):(...e)=>r.assign(s(r,...e))}if(!0===/^[xyzwrgbastpq]{1,4}$/.test(t))return t=Ks(t),Ti(new Gs(r,t));if(!0===/^set[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Xs(t.slice(3).toLowerCase()),r=>Ti(new ks(e,t,r));if(!0===/^flip[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Xs(t.slice(4).toLowerCase()),()=>Ti(new zs(Ti(e),t));if("width"===t||"height"===t||"depth"===t)return"width"===t?t="x":"height"===t?t="y":"depth"===t&&(t="z"),Ti(new Gs(e,t));if(!0===/^\d+$/.test(t))return Ti(new Is(r,new Hs(Number(t),"uint")))}return Reflect.get(e,t,r)},set:(e,t,r,s)=>"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,r,s):(s[t].assign(r),!0)},Qs=new WeakMap,Zs=new WeakMap,Js=function(e,t=null){for(const r in e)e[r]=Ti(e[r],t);return e},ei=function(e,t=null){const r=e.length;for(let s=0;sTi(null!==s?Object.assign(e,s):e);return null===t?(...t)=>i(new e(...vi(t))):null!==r?(r=Ti(r),(...s)=>i(new e(t,...vi(s),r))):(...r)=>i(new e(t,...vi(r)))},ri=function(e,...t){return Ti(new e(...vi(t)))};class si extends Ps{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:r}=this,s=e.getNodeProperties(t);if(s.onceOutput)return s.onceOutput;let i=null;if(t.layout){let s=Zs.get(e.constructor);void 0===s&&(s=new WeakMap,Zs.set(e.constructor,s));let n=s.get(t);void 0===n&&(n=Ti(e.buildFunctionNode(t)),s.set(t,n)),null!==e.currentFunctionNode&&e.currentFunctionNode.includes.push(n),i=Ti(n.call(r))}else{const s=t.jsFunc,n=null!==r||s.length>1?s(r||[],e):s(e);i=Ti(n)}return t.once&&(s.onceOutput=i),i}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 ii extends Ps{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 _i(e),Ti(new si(this,e))}setup(){return this.call()}}const ni=[!1,!0],oi=[0,1,2,3],ai=[-1,-2],ui=[.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],li=new Map;for(const e of ni)li.set(e,new Hs(e));const di=new Map;for(const e of oi)di.set(e,new Hs(e,"uint"));const ci=new Map([...di].map((e=>new Hs(e.value,"int"))));for(const e of ai)ci.set(e,new Hs(e,"int"));const hi=new Map([...ci].map((e=>new Hs(e.value))));for(const e of ui)hi.set(e,new Hs(e));for(const e of ui)hi.set(-e,new Hs(-e));const pi={bool:li,uint:di,ints:ci,float:hi},gi=new Map([...li,...hi]),mi=(e,t)=>gi.has(e)?gi.get(e):!0===e.isNode?e:new Hs(e,t),fi=function(e,t=null){return(...r)=>{if((0===r.length||!["bool","float","int","uint"].includes(e)&&r.every((e=>"object"!=typeof e)))&&(r=[Ts(e,...r)]),1===r.length&&null!==t&&t.has(r[0]))return Ti(t.get(r[0]));if(1===r.length){const t=mi(r[0],e);return(e=>{try{return e.getNodeType()}catch(e){return}})(t)===e?Ti(t):Ti(new Ds(t,e))}const s=r.map((e=>mi(e)));return Ti(new Vs(s,e))}},yi=e=>"object"==typeof e&&null!==e?e.value:e,bi=e=>null!=e?e.nodeType||e.convertTo||("string"==typeof e?e:null):null;function xi(e,t){return new Proxy(new ii(e,t),Ys)}const Ti=(e,t=null)=>function(e,t=null){const r=xs(e);if("node"===r){let t=Qs.get(e);return void 0===t&&(t=new Proxy(e,Ys),Qs.set(e,t),Qs.set(t,t)),t}return null===t&&("float"===r||"boolean"===r)||r&&"shader"!==r&&"string"!==r?Ti(mi(e,t)):"shader"===r?Ai(e):e}(e,t),_i=(e,t=null)=>new Js(e,t),vi=(e,t=null)=>new ei(e,t),Ni=(...e)=>new ti(...e),Si=(...e)=>new ri(...e),Ai=(e,t)=>{const r=new xi(e,t),s=(...e)=>{let t;return _i(e),t=e[0]&&e[0].isNode?[...e]:e[0],r.call(t)};return s.shaderNode=r,s.setLayout=e=>(r.setLayout(e),s),s.once=()=>(r.once=!0,s),s};qs("toGlobal",(e=>(e.global=!0,e)));const Ri=e=>{Ws=e},Ci=()=>Ws,Ei=(...e)=>Ws.If(...e);function wi(e){return Ws&&Ws.add(e),e}qs("append",wi);const Mi=new fi("color"),Bi=new fi("float",pi.float),Ui=new fi("int",pi.ints),Fi=new fi("uint",pi.uint),Pi=new fi("bool",pi.bool),Ii=new fi("vec2"),Di=new fi("ivec2"),Li=new fi("uvec2"),Vi=new fi("bvec2"),Oi=new fi("vec3"),Gi=new fi("ivec3"),ki=new fi("uvec3"),zi=new fi("bvec3"),$i=new fi("vec4"),Hi=new fi("ivec4"),Wi=new fi("uvec4"),ji=new fi("bvec4"),qi=new fi("mat2"),Ki=new fi("mat3"),Xi=new fi("mat4");qs("toColor",Mi),qs("toFloat",Bi),qs("toInt",Ui),qs("toUint",Fi),qs("toBool",Pi),qs("toVec2",Ii),qs("toIVec2",Di),qs("toUVec2",Li),qs("toBVec2",Vi),qs("toVec3",Oi),qs("toIVec3",Gi),qs("toUVec3",ki),qs("toBVec3",zi),qs("toVec4",$i),qs("toIVec4",Hi),qs("toUVec4",Wi),qs("toBVec4",ji),qs("toMat2",qi),qs("toMat3",Ki),qs("toMat4",Xi);const Yi=Ni(Is),Qi=(e,t)=>Ti(new Ds(Ti(e),t));qs("element",Yi),qs("convert",Qi);class Zi extends Ps{static get type(){return"UniformGroupNode"}constructor(e,t=!1,r=1){super("string"),this.name=e,this.shared=t,this.order=r,this.isUniformGroup=!0}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 Ji=e=>new Zi(e),en=(e,t=0)=>new Zi(e,!0,t),tn=en("frame"),rn=en("render"),sn=Ji("object");class nn extends $s{static get type(){return"UniformNode"}constructor(e,t=null){super(e,t),this.isUniformNode=!0,this.name="",this.groupNode=sn}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 r=this.getSelf();return e=e.bind(r),super.onUpdate((t=>{const s=e(t,r);void 0!==s&&(this.value=s)}),t)}generate(e,t){const r=this.getNodeType(e),s=this.getUniformHash(e);let i=e.getNodeFromHash(s);void 0===i&&(e.setHashNode(this,s),i=this);const n=i.getInputType(e),o=e.getUniformFromNode(i,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,r,t)}}const on=(e,t)=>{const r=bi(t||e),s=e&&!0===e.isNode?e.node&&e.node.value||e.value:e;return Ti(new nn(s,r))};class an extends Ps{static get type(){return"PropertyNode"}constructor(e,t=null,r=!1){super(e),this.name=t,this.varying=r,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 un=(e,t)=>Ti(new an(e,t)),ln=(e,t)=>Ti(new an(e,t,!0)),dn=Si(an,"vec4","DiffuseColor"),cn=Si(an,"vec3","EmissiveColor"),hn=Si(an,"float","Roughness"),pn=Si(an,"float","Metalness"),gn=Si(an,"float","Clearcoat"),mn=Si(an,"float","ClearcoatRoughness"),fn=Si(an,"vec3","Sheen"),yn=Si(an,"float","SheenRoughness"),bn=Si(an,"float","Iridescence"),xn=Si(an,"float","IridescenceIOR"),Tn=Si(an,"float","IridescenceThickness"),_n=Si(an,"float","AlphaT"),vn=Si(an,"float","Anisotropy"),Nn=Si(an,"vec3","AnisotropyT"),Sn=Si(an,"vec3","AnisotropyB"),An=Si(an,"color","SpecularColor"),Rn=Si(an,"float","SpecularF90"),Cn=Si(an,"float","Shininess"),En=Si(an,"vec4","Output"),wn=Si(an,"float","dashSize"),Mn=Si(an,"float","gapSize"),Bn=Si(an,"float","pointWidth"),Un=Si(an,"float","IOR"),Fn=Si(an,"float","Transmission"),Pn=Si(an,"float","Thickness"),In=Si(an,"float","AttenuationDistance"),Dn=Si(an,"color","AttenuationColor"),Ln=Si(an,"float","Dispersion");class Vn extends Ls{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 r=e.getTypeLength(t.node.getNodeType(e));return Us.join("").slice(0,r)!==t.components}return!1}generate(e,t){const{targetNode:r,sourceNode:s}=this,i=this.needsSplitAssign(e),n=r.getNodeType(e),o=r.context({assign:!0}).build(e),a=s.build(e,n),u=s.getNodeType(e),l=e.getDataFromNode(this);let d;if(!0===l.initialized)"void"!==t&&(d=o);else if(i){const s=e.getVarFromNode(this,null,n),i=e.getPropertyName(s);e.addLineFlowCode(`${i} = ${a}`,this);const u=r.node.context({assign:!0}).build(e);for(let t=0;t{const s=r.type;let i;return i="pointer"===s?"&"+t.build(e):t.build(e,s),i};if(Array.isArray(i))for(let e=0;e(t=t.length>1||t[0]&&!0===t[0].isNode?vi(t):_i(t[0]),Ti(new Gn(Ti(e),t)));qs("call",kn);class zn extends Ls{static get type(){return"OperatorNode"}constructor(e,t,r,...s){if(super(),s.length>0){let i=new zn(e,t,r);for(let t=0;t>"===r||"<<"===r)return e.getIntegerType(n);if("!"===r||"=="===r||"&&"===r||"||"===r||"^^"===r)return"bool";if("<"===r||">"===r||"<="===r||">="===r){const r=t?e.getTypeLength(t):Math.max(e.getTypeLength(n),e.getTypeLength(o));return r>1?`bvec${r}`:"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 r=this.op,s=this.aNode,i=this.bNode,n=this.getNodeType(e,t);let o=null,a=null;"void"!==n?(o=s.getNodeType(e),a=void 0!==i?i.getNodeType(e):null,"<"===r||">"===r||"<="===r||">="===r||"=="===r?e.isVector(o)?a=o:o!==a&&(o=a="float"):">>"===r||"<<"===r?(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 u=s.build(e,o),l=void 0!==i?i.build(e,a):null,d=e.getTypeLength(t),c=e.getFunctionOperator(r);return"void"!==t?"<"===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThan",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} < ${l} )`,n,t):"<="===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThanEqual",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} <= ${l} )`,n,t):">"===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThan",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} > ${l} )`,n,t):">="===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThanEqual",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} >= ${l} )`,n,t):"!"===r||"~"===r?e.format(`(${r}${u})`,o,t):c?e.format(`${c}( ${u}, ${l} )`,n,t):e.format(`( ${u} ${r} ${l} )`,n,t):"void"!==o?c?e.format(`${c}( ${u}, ${l} )`,n,t):e.format(`${u} ${r} ${l}`,n,t):void 0}serialize(e){super.serialize(e),e.op=this.op}deserialize(e){super.deserialize(e),this.op=e.op}}const $n=Ni(zn,"+"),Hn=Ni(zn,"-"),Wn=Ni(zn,"*"),jn=Ni(zn,"/"),qn=Ni(zn,"%"),Kn=Ni(zn,"=="),Xn=Ni(zn,"!="),Yn=Ni(zn,"<"),Qn=Ni(zn,">"),Zn=Ni(zn,"<="),Jn=Ni(zn,">="),eo=Ni(zn,"&&"),to=Ni(zn,"||"),ro=Ni(zn,"!"),so=Ni(zn,"^^"),io=Ni(zn,"&"),no=Ni(zn,"~"),oo=Ni(zn,"|"),ao=Ni(zn,"^"),uo=Ni(zn,"<<"),lo=Ni(zn,">>");qs("add",$n),qs("sub",Hn),qs("mul",Wn),qs("div",jn),qs("modInt",qn),qs("equal",Kn),qs("notEqual",Xn),qs("lessThan",Yn),qs("greaterThan",Qn),qs("lessThanEqual",Zn),qs("greaterThanEqual",Jn),qs("and",eo),qs("or",to),qs("not",ro),qs("xor",so),qs("bitAnd",io),qs("bitNot",no),qs("bitOr",oo),qs("bitXor",ao),qs("shiftLeft",uo),qs("shiftRight",lo);const co=(...e)=>(console.warn("TSL.OperatorNode: .remainder() has been renamed to .modInt()."),qn(...e));qs("remainder",co);class ho extends Ls{static get type(){return"MathNode"}constructor(e,t,r=null,s=null){super(),this.method=e,this.aNode=t,this.bNode=r,this.cNode=s,this.isMathNode=!0}getInputType(e){const t=this.aNode.getNodeType(e),r=this.bNode?this.bNode.getNodeType(e):null,s=this.cNode?this.cNode.getNodeType(e):null,i=e.isMatrix(t)?0:e.getTypeLength(t),n=e.isMatrix(r)?0:e.getTypeLength(r),o=e.isMatrix(s)?0:e.getTypeLength(s);return i>n&&i>o?t:n>o?r:o>i?s:t}getNodeType(e){const t=this.method;return t===ho.LENGTH||t===ho.DISTANCE||t===ho.DOT?"float":t===ho.CROSS?"vec3":t===ho.ALL?"bool":t===ho.EQUALS?e.changeComponentType(this.aNode.getNodeType(e),"bool"):t===ho.MOD?this.aNode.getNodeType(e):this.getInputType(e)}generate(e,t){let r=this.method;const s=this.getNodeType(e),i=this.getInputType(e),n=this.aNode,o=this.bNode,a=this.cNode,d=e.renderer.coordinateSystem;if(r===ho.TRANSFORM_DIRECTION){let r=n,s=o;e.isMatrix(r.getNodeType(e))?s=$i(Oi(s),0):r=$i(Oi(r),0);const i=Wn(r,s).xyz;return wo(i).build(e,t)}if(r===ho.NEGATE)return e.format("( - "+n.build(e,i)+" )",s,t);if(r===ho.ONE_MINUS)return Hn(1,n).build(e,t);if(r===ho.RECIPROCAL)return jn(1,n).build(e,t);if(r===ho.DIFFERENCE)return Lo(Hn(n,o)).build(e,t);{const c=[];return r===ho.CROSS||r===ho.MOD?c.push(n.build(e,s),o.build(e,s)):d===u&&r===ho.STEP?c.push(n.build(e,1===e.getTypeLength(n.getNodeType(e))?"float":i),o.build(e,i)):d===u&&(r===ho.MIN||r===ho.MAX)||r===ho.MOD?c.push(n.build(e,i),o.build(e,1===e.getTypeLength(o.getNodeType(e))?"float":i)):r===ho.REFRACT?c.push(n.build(e,i),o.build(e,i),a.build(e,"float")):r===ho.MIX?c.push(n.build(e,i),o.build(e,i),a.build(e,1===e.getTypeLength(a.getNodeType(e))?"float":i)):(d===l&&r===ho.ATAN&&null!==o&&(r="atan2"),c.push(n.build(e,i)),null!==o&&c.push(o.build(e,i)),null!==a&&c.push(a.build(e,i))),e.format(`${e.getMethod(r,s)}( ${c.join(", ")} )`,s,t)}}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}ho.ALL="all",ho.ANY="any",ho.RADIANS="radians",ho.DEGREES="degrees",ho.EXP="exp",ho.EXP2="exp2",ho.LOG="log",ho.LOG2="log2",ho.SQRT="sqrt",ho.INVERSE_SQRT="inversesqrt",ho.FLOOR="floor",ho.CEIL="ceil",ho.NORMALIZE="normalize",ho.FRACT="fract",ho.SIN="sin",ho.COS="cos",ho.TAN="tan",ho.ASIN="asin",ho.ACOS="acos",ho.ATAN="atan",ho.ABS="abs",ho.SIGN="sign",ho.LENGTH="length",ho.NEGATE="negate",ho.ONE_MINUS="oneMinus",ho.DFDX="dFdx",ho.DFDY="dFdy",ho.ROUND="round",ho.RECIPROCAL="reciprocal",ho.TRUNC="trunc",ho.FWIDTH="fwidth",ho.TRANSPOSE="transpose",ho.BITCAST="bitcast",ho.EQUALS="equals",ho.MIN="min",ho.MAX="max",ho.MOD="mod",ho.STEP="step",ho.REFLECT="reflect",ho.DISTANCE="distance",ho.DIFFERENCE="difference",ho.DOT="dot",ho.CROSS="cross",ho.POW="pow",ho.TRANSFORM_DIRECTION="transformDirection",ho.MIX="mix",ho.CLAMP="clamp",ho.REFRACT="refract",ho.SMOOTHSTEP="smoothstep",ho.FACEFORWARD="faceforward";const po=Bi(1e-6),go=Bi(1e6),mo=Bi(Math.PI),fo=Bi(2*Math.PI),yo=Ni(ho,ho.ALL),bo=Ni(ho,ho.ANY),xo=Ni(ho,ho.RADIANS),To=Ni(ho,ho.DEGREES),_o=Ni(ho,ho.EXP),vo=Ni(ho,ho.EXP2),No=Ni(ho,ho.LOG),So=Ni(ho,ho.LOG2),Ao=Ni(ho,ho.SQRT),Ro=Ni(ho,ho.INVERSE_SQRT),Co=Ni(ho,ho.FLOOR),Eo=Ni(ho,ho.CEIL),wo=Ni(ho,ho.NORMALIZE),Mo=Ni(ho,ho.FRACT),Bo=Ni(ho,ho.SIN),Uo=Ni(ho,ho.COS),Fo=Ni(ho,ho.TAN),Po=Ni(ho,ho.ASIN),Io=Ni(ho,ho.ACOS),Do=Ni(ho,ho.ATAN),Lo=Ni(ho,ho.ABS),Vo=Ni(ho,ho.SIGN),Oo=Ni(ho,ho.LENGTH),Go=Ni(ho,ho.NEGATE),ko=Ni(ho,ho.ONE_MINUS),zo=Ni(ho,ho.DFDX),$o=Ni(ho,ho.DFDY),Ho=Ni(ho,ho.ROUND),Wo=Ni(ho,ho.RECIPROCAL),jo=Ni(ho,ho.TRUNC),qo=Ni(ho,ho.FWIDTH),Ko=Ni(ho,ho.TRANSPOSE),Xo=Ni(ho,ho.BITCAST),Yo=Ni(ho,ho.EQUALS),Qo=Ni(ho,ho.MIN),Zo=Ni(ho,ho.MAX),Jo=Ni(ho,ho.MOD),ea=Ni(ho,ho.STEP),ta=Ni(ho,ho.REFLECT),ra=Ni(ho,ho.DISTANCE),sa=Ni(ho,ho.DIFFERENCE),ia=Ni(ho,ho.DOT),na=Ni(ho,ho.CROSS),oa=Ni(ho,ho.POW),aa=Ni(ho,ho.POW,2),ua=Ni(ho,ho.POW,3),la=Ni(ho,ho.POW,4),da=Ni(ho,ho.TRANSFORM_DIRECTION),ca=e=>Wn(Vo(e),oa(Lo(e),1/3)),ha=e=>ia(e,e),pa=Ni(ho,ho.MIX),ga=(e,t=0,r=1)=>Ti(new ho(ho.CLAMP,Ti(e),Ti(t),Ti(r))),ma=e=>ga(e),fa=Ni(ho,ho.REFRACT),ya=Ni(ho,ho.SMOOTHSTEP),ba=Ni(ho,ho.FACEFORWARD),xa=Ai((([e])=>{const t=ia(e.xy,Ii(12.9898,78.233)),r=Jo(t,mo);return Mo(Bo(r).mul(43758.5453))})),Ta=(e,t,r)=>pa(t,r,e),_a=(e,t,r)=>ya(t,r,e),va=(e,t)=>(console.warn('THREE.TSL: "atan2" is overloaded. Use "atan" instead.'),Do(e,t)),Na=ba,Sa=Ro;qs("all",yo),qs("any",bo),qs("equals",Yo),qs("radians",xo),qs("degrees",To),qs("exp",_o),qs("exp2",vo),qs("log",No),qs("log2",So),qs("sqrt",Ao),qs("inverseSqrt",Ro),qs("floor",Co),qs("ceil",Eo),qs("normalize",wo),qs("fract",Mo),qs("sin",Bo),qs("cos",Uo),qs("tan",Fo),qs("asin",Po),qs("acos",Io),qs("atan",Do),qs("abs",Lo),qs("sign",Vo),qs("length",Oo),qs("lengthSq",ha),qs("negate",Go),qs("oneMinus",ko),qs("dFdx",zo),qs("dFdy",$o),qs("round",Ho),qs("reciprocal",Wo),qs("trunc",jo),qs("fwidth",qo),qs("atan2",va),qs("min",Qo),qs("max",Zo),qs("mod",Jo),qs("step",ea),qs("reflect",ta),qs("distance",ra),qs("dot",ia),qs("cross",na),qs("pow",oa),qs("pow2",aa),qs("pow3",ua),qs("pow4",la),qs("transformDirection",da),qs("mix",Ta),qs("clamp",ga),qs("refract",fa),qs("smoothstep",_a),qs("faceForward",ba),qs("difference",sa),qs("saturate",ma),qs("cbrt",ca),qs("transpose",Ko),qs("rand",xa);class Aa extends Ps{static get type(){return"ConditionalNode"}constructor(e,t,r=null){super(),this.condNode=e,this.ifNode=t,this.elseNode=r}getNodeType(e){const{ifNode:t,elseNode:r}=e.getNodeProperties(this);if(void 0===t)return this.setup(e),this.getNodeType(e);const s=t.getNodeType(e);if(null!==r){const t=r.getNodeType(e);if(e.getTypeLength(t)>e.getTypeLength(s))return t}return s}setup(e){const t=this.condNode.cache(),r=this.ifNode.cache(),s=this.elseNode?this.elseNode.cache():null,i=e.context.nodeBlock;e.getDataFromNode(r).parentNodeBlock=i,null!==s&&(e.getDataFromNode(s).parentNodeBlock=i);const n=e.getNodeProperties(this);n.condNode=t,n.ifNode=r.context({nodeBlock:r}),n.elseNode=s?s.context({nodeBlock:s}):null}generate(e,t){const r=this.getNodeType(e),s=e.getDataFromNode(this);if(void 0!==s.nodeProperty)return s.nodeProperty;const{condNode:i,ifNode:n,elseNode:o}=e.getNodeProperties(this),a="void"!==t,u=a?un(r).build(e):"";s.nodeProperty=u;const l=i.build(e,"bool");e.addFlowCode(`\n${e.tab}if ( ${l} ) {\n\n`).addFlowTab();let d=n.build(e,r);if(d&&(d=a?u+" = "+d+";":"return "+d+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+d+"\n\n"+e.tab+"}"),null!==o){e.addFlowCode(" else {\n\n").addFlowTab();let t=o.build(e,r);t&&(t=a?u+" = "+t+";":"return "+t+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+t+"\n\n"+e.tab+"}\n\n")}else e.addFlowCode("\n\n");return e.format(u,r,t)}}const Ra=Ni(Aa);qs("select",Ra);const Ca=(...e)=>(console.warn("TSL.ConditionalNode: cond() has been renamed to select()."),Ra(...e));qs("cond",Ca);class Ea extends Ps{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 r=this.node.build(e);return e.setContext(t),r}generate(e,t){const r=e.getContext();e.setContext({...e.context,...this.value});const s=this.node.build(e,t);return e.setContext(r),s}}const wa=Ni(Ea),Ma=(e,t)=>wa(e,{label:t});qs("context",wa),qs("label",Ma);class Ba extends Ps{static get type(){return"VarNode"}constructor(e,t=null,r=!1){super(),this.node=e,this.name=t,this.global=!0,this.isVarNode=!0,this.readOnly=r}getHash(e){return this.name||super.getHash(e)}getNodeType(e){return this.node.getNodeType(e)}generate(e){const{node:t,name:r,readOnly:s}=this,{renderer:i}=e,n=!0===i.backend.isWebGPUBackend;let o=!1,a=!1;s&&(o=e.isDeterministic(t),a=n?s:o);const u=e.getVectorType(this.getNodeType(e)),l=t.build(e,u),d=e.getVarFromNode(this,r,u,void 0,a),c=e.getPropertyName(d);let h=c;if(a){const t=e.getType(d.type);h=n?o?`const ${c}`:`let ${c}`:`const ${t} ${c}`}return e.addLineFlowCode(`${h} = ${l}`,this),c}}const Ua=Ni(Ba),Fa=(e,t=null)=>Ua(e,t).append(),Pa=(e,t=null)=>Ua(e,t,!0).append();qs("toVar",Fa),qs("toConst",Pa);const Ia=e=>(console.warn('TSL: "temp( node )" is deprecated. Use "Var( node )" or "node.toVar()" instead.'),Ua(e));qs("temp",Ia);class Da extends Ps{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 r=t.varying;if(void 0===r){const s=this.name,i=this.getNodeType(e);t.varying=r=e.getVaryingFromNode(this,s,i),t.node=this.node}return r.needsInterpolation||(r.needsInterpolation="fragment"===e.shaderStage),r}setup(e){this.setupVarying(e)}analyze(e){return this.setupVarying(e),this.node.analyze(e)}generate(e){const t=e.getNodeProperties(this),r=this.setupVarying(e),s="fragment"===e.shaderStage&&!0===t.reassignPosition&&e.context.needsPositionReassign;if(void 0===t.propertyName||s){const i=this.getNodeType(e),n=e.getPropertyName(r,As.VERTEX);e.flowNodeFromShaderStage(As.VERTEX,this.node,i,n),t.propertyName=n,s?t.reassignPosition=!1:void 0===t.reassignPosition&&e.context.isPositionNodeInput&&(t.reassignPosition=!0)}return e.getPropertyName(r)}}const La=Ni(Da),Va=e=>La(e);qs("varying",La),qs("vertexStage",Va);const Oa=Ai((([e])=>{const t=e.mul(.9478672986).add(.0521327014).pow(2.4),r=e.mul(.0773993808),s=e.lessThanEqual(.04045);return pa(t,r,s)})).setLayout({name:"sRGBTransferEOTF",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),Ga=Ai((([e])=>{const t=e.pow(.41666).mul(1.055).sub(.055),r=e.mul(12.92),s=e.lessThanEqual(.0031308);return pa(t,r,s)})).setLayout({name:"sRGBTransferOETF",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),ka="WorkingColorSpace",za="OutputColorSpace";class $a extends Ls{static get type(){return"ColorSpaceNode"}constructor(e,t,r){super("vec4"),this.colorNode=e,this.source=t,this.target=r}resolveColorSpace(e,t){return t===ka?d.workingColorSpace:t===za?e.context.outputColorSpace||e.renderer.outputColorSpace:t}setup(e){const{colorNode:t}=this,r=this.resolveColorSpace(e,this.source),s=this.resolveColorSpace(e,this.target);let n=t;return!1!==d.enabled&&r!==s&&r&&s?(d.getTransfer(r)===c&&(n=$i(Oa(n.rgb),n.a)),d.getPrimaries(r)!==d.getPrimaries(s)&&(n=$i(Ki(d._getMatrix(new i,r,s)).mul(n.rgb),n.a)),d.getTransfer(s)===c&&(n=$i(Ga(n.rgb),n.a)),n):n}}const Ha=e=>Ti(new $a(Ti(e),ka,za)),Wa=e=>Ti(new $a(Ti(e),za,ka)),ja=(e,t)=>Ti(new $a(Ti(e),ka,t)),qa=(e,t)=>Ti(new $a(Ti(e),t,ka));qs("toOutputColorSpace",Ha),qs("toWorkingColorSpace",Wa),qs("workingToColorSpace",ja),qs("colorSpaceToWorking",qa);let Ka=class extends Is{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),r=this.referenceNode.getNodeType(),s=this.getNodeType();return e.format(t,r,s)}};class Xa extends Ps{static get type(){return"ReferenceBaseNode"}constructor(e,t,r=null,s=null){super(),this.property=e,this.uniformType=t,this.object=r,this.count=s,this.properties=e.split("."),this.reference=r,this.node=null,this.group=null,this.updateType=Rs.OBJECT}setGroup(e){return this.group=e,this}element(e){return Ti(new Ka(this,Ti(e)))}setNodeType(e){const t=on(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 r=e[t[0]];for(let e=1;eTi(new Ya(e,t,r));class Za extends Ls{static get type(){return"ToneMappingNode"}constructor(e,t=eu,r=null){super("vec3"),this.toneMapping=e,this.exposureNode=t,this.colorNode=r}customCacheKey(){return cs(this.toneMapping)}setup(e){const t=this.colorNode||e.context.color,r=this.toneMapping;if(r===h)return t;let s=null;const i=e.renderer.library.getToneMappingFunction(r);return null!==i?s=$i(i(t.rgb,this.exposureNode),t.a):(console.error("ToneMappingNode: Unsupported Tone Mapping configuration.",r),s=t),s}}const Ja=(e,t,r)=>Ti(new Za(e,Ti(t),Ti(r))),eu=Qa("toneMappingExposure","float");qs("toneMapping",((e,t,r)=>Ja(t,r,e)));class tu extends $s{static get type(){return"BufferAttributeNode"}constructor(e,t=null,r=0,s=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferStride=r,this.bufferOffset=s,this.usage=p,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),r=this.value,s=e.getTypeLength(t),i=this.bufferStride||s,n=this.bufferOffset,o=!0===r.isInterleavedBuffer?r:new g(r,i),a=new f(o,s,n);o.setUsage(this.usage),this.attribute=a,this.attribute.isInstancedBufferAttribute=this.instanced}generate(e){const t=this.getNodeType(e),r=e.getBufferAttributeFromNode(this,t),s=e.getPropertyName(r);let i=null;if("vertex"===e.shaderStage||"compute"===e.shaderStage)this.name=s,i=s;else{i=La(this).build(e,t)}return i}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 ru=(e,t=null,r=0,s=0)=>Ti(new tu(e,t,r,s)),su=(e,t=null,r=0,s=0)=>ru(e,t,r,s).setUsage(m),iu=(e,t=null,r=0,s=0)=>ru(e,t,r,s).setInstanced(!0),nu=(e,t=null,r=0,s=0)=>su(e,t,r,s).setInstanced(!0);qs("toAttribute",(e=>ru(e.value)));class ou extends Ps{static get type(){return"ComputeNode"}constructor(e,t,r=[64]){super("void"),this.isComputeNode=!0,this.computeNode=e,this.count=t,this.workgroupSize=r,this.dispatchCount=0,this.version=1,this.name="",this.updateBeforeType=Rs.OBJECT,this.onInitFunction=null,this.updateDispatchCount()}dispose(){this.dispatchEvent({type:"dispose"})}label(e){return this.name=e,this}updateDispatchCount(){const{count:e,workgroupSize:t}=this;let r=t[0];for(let e=1;eTi(new ou(Ti(e),t,r));qs("compute",au);class uu extends Ps{static get type(){return"CacheNode"}constructor(e,t=!0){super(),this.node=e,this.parent=t,this.isCacheNode=!0}getNodeType(e){const t=e.getCache(),r=e.getCacheFromNode(this,this.parent);e.setCache(r);const s=this.node.getNodeType(e);return e.setCache(t),s}build(e,...t){const r=e.getCache(),s=e.getCacheFromNode(this,this.parent);e.setCache(s);const i=this.node.build(e,...t);return e.setCache(r),i}}const lu=(e,t)=>Ti(new uu(Ti(e),t));qs("cache",lu);class du extends Ps{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 cu=Ni(du);qs("bypass",cu);class hu extends Ps{static get type(){return"RemapNode"}constructor(e,t,r,s=Bi(0),i=Bi(1)){super(),this.node=e,this.inLowNode=t,this.inHighNode=r,this.outLowNode=s,this.outHighNode=i,this.doClamp=!0}setup(){const{node:e,inLowNode:t,inHighNode:r,outLowNode:s,outHighNode:i,doClamp:n}=this;let o=e.sub(t).div(r.sub(t));return!0===n&&(o=o.clamp()),o.mul(i.sub(s)).add(s)}}const pu=Ni(hu,null,null,{doClamp:!1}),gu=Ni(hu);qs("remap",pu),qs("remapClamp",gu);class mu extends Ps{static get type(){return"ExpressionNode"}constructor(e="",t="void"){super(t),this.snippet=e}generate(e,t){const r=this.getNodeType(e),s=this.snippet;if("void"!==r)return e.format(`( ${s} )`,r,t);e.addLineFlowCode(s,this)}}const fu=Ni(mu),yu=e=>(e?Ra(e,fu("discard")):fu("discard")).append();qs("discard",yu);class bu extends Ls{static get type(){return"RenderOutputNode"}constructor(e,t,r){super("vec4"),this.colorNode=e,this.toneMapping=t,this.outputColorSpace=r,this.isRenderOutputNode=!0}setup({context:e}){let t=this.colorNode||e.color;const r=(null!==this.toneMapping?this.toneMapping:e.toneMapping)||h,s=(null!==this.outputColorSpace?this.outputColorSpace:e.outputColorSpace)||y;return r!==h&&(t=t.toneMapping(r)),s!==y&&s!==d.workingColorSpace&&(t=t.workingToColorSpace(s)),t}}const xu=(e,t=null,r=null)=>Ti(new bu(Ti(e),t,r));qs("renderOutput",xu);class Tu extends Ps{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 r=this.getAttributeName(e);if(e.hasGeometryAttribute(r)){const s=e.geometry.getAttribute(r);t=e.getTypeFromAttribute(s)}else t="float"}return t}setAttributeName(e){return this._attributeName=e,this}getAttributeName(){return this._attributeName}generate(e){const t=this.getAttributeName(e),r=this.getNodeType(e);if(!0===e.hasGeometryAttribute(t)){const s=e.geometry.getAttribute(t),i=e.getTypeFromAttribute(s),n=e.getAttribute(t,i);if("vertex"===e.shaderStage)return e.format(n.name,i,r);return La(this).build(e,r)}return console.warn(`AttributeNode: Vertex attribute "${t}" not found on geometry.`),e.generateConst(r)}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 _u=(e,t)=>Ti(new Tu(e,t)),vu=(e=0)=>_u("uv"+(e>0?e:""),"vec2");class Nu extends Ps{static get type(){return"TextureSizeNode"}constructor(e,t=null){super("uvec2"),this.isTextureSizeNode=!0,this.textureNode=e,this.levelNode=t}generate(e,t){const r=this.textureNode.build(e,"property"),s=null===this.levelNode?"0":this.levelNode.build(e,"int");return e.format(`${e.getMethod("textureDimensions")}( ${r}, ${s} )`,this.getNodeType(e),t)}}const Su=Ni(Nu);class Au extends nn{static get type(){return"MaxMipLevelNode"}constructor(e){super(0),this._textureNode=e,this.updateType=Rs.FRAME}get textureNode(){return this._textureNode}get texture(){return this._textureNode.value}update(){const e=this.texture,t=e.images,r=t&&t.length>0?t[0]&&t[0].image||t[0]:e.image;if(r&&void 0!==r.width){const{width:e,height:t}=r;this.value=Math.log2(Math.max(e,t))}}}const Ru=Ni(Au);class Cu extends nn{static get type(){return"TextureNode"}constructor(e,t=null,r=null,s=null){super(e),this.isTextureNode=!0,this.uvNode=t,this.levelNode=r,this.biasNode=s,this.compareNode=null,this.depthNode=null,this.gradNode=null,this.sampler=!0,this.updateMatrix=!1,this.updateType=Rs.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===b?"uvec4":this.value.type===x?"ivec4":"vec4"}getInputType(){return"texture"}getDefaultUV(){return vu(this.value.channel)}updateReference(){return this.value}getTransformedUV(e){return null===this._matrixUniform&&(this._matrixUniform=on(this.value.matrix)),this._matrixUniform.mul(Oi(e,1)).xy}setUpdateMatrix(e){return this.updateMatrix=e,this.updateType=e?Rs.RENDER:Rs.NONE,this}setupUV(e,t){const r=this.value;return e.isFlipY()&&(r.image instanceof ImageBitmap&&!0===r.flipY||!0===r.isRenderTargetTexture||!0===r.isFramebufferTexture||!0===r.isDepthTexture)&&(t=this.sampler?t.flipY():t.setY(Ui(Su(this,this.levelNode).y).sub(t.y).sub(1))),t}setup(e){const t=e.getNodeProperties(this);t.referenceNode=this.referenceNode;const r=this.value;if(!r||!0!==r.isTexture)throw new Error("THREE.TSL: `texture( value )` function expects a valid instance of THREE.Texture().");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,r,s,i,n,o,a){const u=this.value;let l;return l=s?e.generateTextureLevel(u,t,r,s,n):i?e.generateTextureBias(u,t,r,i,n):a?e.generateTextureGrad(u,t,r,a,n):o?e.generateTextureCompare(u,t,r,o,n):!1===this.sampler?e.generateTextureLoad(u,t,r,n):e.generateTexture(u,t,r,n),l}generate(e,t){const r=this.value,s=e.getNodeProperties(this),i=super.generate(e,"property");if("sampler"===t)return i+"_sampler";if(e.isReference(t))return i;{const n=e.getDataFromNode(this);let o=n.propertyName;if(void 0===o){const{uvNode:t,levelNode:r,biasNode:a,compareNode:u,depthNode:l,gradNode:d}=s,c=this.generateUV(e,t),h=r?r.build(e,"float"):null,p=a?a.build(e,"float"):null,g=l?l.build(e,"int"):null,m=u?u.build(e,"float"):null,f=d?[d[0].build(e,"vec2"),d[1].build(e,"vec2")]:null,y=e.getVarFromNode(this);o=e.getPropertyName(y);const b=this.generateSnippet(e,i,c,h,p,g,m,f);e.addLineFlowCode(`${o} = ${b}`,this),n.snippet=b,n.propertyName=o}let a=o;const u=this.getNodeType(e);return e.needsToWorkingColorSpace(r)&&(a=qa(fu(a,u),r.colorSpace).setup(e).build(e,u)),e.format(a,u,t)}}setSampler(e){return this.sampler=e,this}getSampler(){return this.sampler}uv(e){return console.warn("THREE.TextureNode: .uv() has been renamed. Use .sample() instead."),this.sample(e)}sample(e){const t=this.clone();return t.uvNode=Ti(e),t.referenceNode=this.getSelf(),Ti(t)}blur(e){const t=this.clone();return t.biasNode=Ti(e).mul(Ru(t)),t.referenceNode=this.getSelf(),Ti(t)}level(e){const t=this.clone();return t.levelNode=Ti(e),t.referenceNode=this.getSelf(),Ti(t)}size(e){return Su(this,e)}bias(e){const t=this.clone();return t.biasNode=Ti(e),t.referenceNode=this.getSelf(),Ti(t)}compare(e){const t=this.clone();return t.compareNode=Ti(e),t.referenceNode=this.getSelf(),Ti(t)}grad(e,t){const r=this.clone();return r.gradNode=[Ti(e),Ti(t)],r.referenceNode=this.getSelf(),Ti(r)}depth(e){const t=this.clone();return t.depthNode=Ti(e),t.referenceNode=this.getSelf(),Ti(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 Eu=Ni(Cu),wu=(...e)=>Eu(...e).setSampler(!1),Mu=on("float").label("cameraNear").setGroup(rn).onRenderUpdate((({camera:e})=>e.near)),Bu=on("float").label("cameraFar").setGroup(rn).onRenderUpdate((({camera:e})=>e.far)),Uu=on("mat4").label("cameraProjectionMatrix").setGroup(rn).onRenderUpdate((({camera:e})=>e.projectionMatrix)),Fu=on("mat4").label("cameraProjectionMatrixInverse").setGroup(rn).onRenderUpdate((({camera:e})=>e.projectionMatrixInverse)),Pu=on("mat4").label("cameraViewMatrix").setGroup(rn).onRenderUpdate((({camera:e})=>e.matrixWorldInverse)),Iu=on("mat4").label("cameraWorldMatrix").setGroup(rn).onRenderUpdate((({camera:e})=>e.matrixWorld)),Du=on("mat3").label("cameraNormalMatrix").setGroup(rn).onRenderUpdate((({camera:e})=>e.normalMatrix)),Lu=on(new r).label("cameraPosition").setGroup(rn).onRenderUpdate((({camera:e},t)=>t.value.setFromMatrixPosition(e.matrixWorld)));class Vu extends Ps{static get type(){return"Object3DNode"}constructor(e,t=null){super(),this.scope=e,this.object3d=t,this.updateType=Rs.OBJECT,this._uniformNode=new nn(null)}getNodeType(){const e=this.scope;return e===Vu.WORLD_MATRIX?"mat4":e===Vu.POSITION||e===Vu.VIEW_POSITION||e===Vu.DIRECTION||e===Vu.SCALE?"vec3":void 0}update(e){const t=this.object3d,s=this._uniformNode,i=this.scope;if(i===Vu.WORLD_MATRIX)s.value=t.matrixWorld;else if(i===Vu.POSITION)s.value=s.value||new r,s.value.setFromMatrixPosition(t.matrixWorld);else if(i===Vu.SCALE)s.value=s.value||new r,s.value.setFromMatrixScale(t.matrixWorld);else if(i===Vu.DIRECTION)s.value=s.value||new r,t.getWorldDirection(s.value);else if(i===Vu.VIEW_POSITION){const i=e.camera;s.value=s.value||new r,s.value.setFromMatrixPosition(t.matrixWorld),s.value.applyMatrix4(i.matrixWorldInverse)}}generate(e){const t=this.scope;return t===Vu.WORLD_MATRIX?this._uniformNode.nodeType="mat4":t!==Vu.POSITION&&t!==Vu.VIEW_POSITION&&t!==Vu.DIRECTION&&t!==Vu.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}}Vu.WORLD_MATRIX="worldMatrix",Vu.POSITION="position",Vu.SCALE="scale",Vu.VIEW_POSITION="viewPosition",Vu.DIRECTION="direction";const Ou=Ni(Vu,Vu.DIRECTION),Gu=Ni(Vu,Vu.WORLD_MATRIX),ku=Ni(Vu,Vu.POSITION),zu=Ni(Vu,Vu.SCALE),$u=Ni(Vu,Vu.VIEW_POSITION);class Hu extends Vu{static get type(){return"ModelNode"}constructor(e){super(e)}update(e){this.object3d=e.object,super.update(e)}}const Wu=Si(Hu,Hu.DIRECTION),ju=Si(Hu,Hu.WORLD_MATRIX),qu=Si(Hu,Hu.POSITION),Ku=Si(Hu,Hu.SCALE),Xu=Si(Hu,Hu.VIEW_POSITION),Yu=on(new i).onObjectUpdate((({object:e},t)=>t.value.getNormalMatrix(e.matrixWorld))),Qu=on(new n).onObjectUpdate((({object:e},t)=>t.value.copy(e.matrixWorld).invert())),Zu=Ai((e=>e.renderer.nodes.modelViewMatrix||Ju)).once()().toVar("modelViewMatrix"),Ju=Pu.mul(ju),el=Ai((e=>(e.context.isHighPrecisionModelViewMatrix=!0,on("mat4").onObjectUpdate((({object:e,camera:t})=>e.modelViewMatrix.multiplyMatrices(t.matrixWorldInverse,e.matrixWorld)))))).once()().toVar("highpModelViewMatrix"),tl=Ai((e=>{const t=e.context.isHighPrecisionModelViewMatrix;return on("mat3").onObjectUpdate((({object:e,camera:r})=>(!0!==t&&e.modelViewMatrix.multiplyMatrices(r.matrixWorldInverse,e.matrixWorld),e.normalMatrix.getNormalMatrix(e.modelViewMatrix))))})).once()().toVar("highpModelNormalViewMatrix"),rl=_u("position","vec3"),sl=rl.varying("positionLocal"),il=rl.varying("positionPrevious"),nl=ju.mul(sl).xyz.varying("v_positionWorld").context({needsPositionReassign:!0}),ol=sl.transformDirection(ju).varying("v_positionWorldDirection").normalize().toVar("positionWorldDirection").context({needsPositionReassign:!0}),al=Ai((e=>e.context.setupPositionView()),"vec3").once()().varying("v_positionView").context({needsPositionReassign:!0}),ul=al.negate().varying("v_positionViewDirection").normalize().toVar("positionViewDirection");class ll extends Ps{static get type(){return"FrontFacingNode"}constructor(){super("bool"),this.isFrontFacingNode=!0}generate(e){const{renderer:t,material:r}=e;return t.coordinateSystem===u&&r.side===T?"false":e.getFrontFacing()}}const dl=Si(ll),cl=Bi(dl).mul(2).sub(1),hl=_u("normal","vec3"),pl=Ai((e=>!1===e.geometry.hasAttribute("normal")?(console.warn('TSL.NormalNode: Vertex attribute "normal" not found on geometry.'),Oi(0,1,0)):hl),"vec3").once()().toVar("normalLocal"),gl=al.dFdx().cross(al.dFdy()).normalize().toVar("normalFlat"),ml=Ai((e=>{let t;return t=!0===e.material.flatShading?gl:La(_l(pl),"v_normalView").normalize(),t}),"vec3").once()().toVar("normalView"),fl=La(ml.transformDirection(Pu),"v_normalWorld").normalize().toVar("normalWorld"),yl=Ai((e=>e.context.setupNormal().context({getUV:null})),"vec3").once()().mul(cl).toVar("transformedNormalView"),bl=yl.transformDirection(Pu).toVar("transformedNormalWorld"),xl=Ai((e=>e.context.setupClearcoatNormal().context({getUV:null})),"vec3").once()().mul(cl).toVar("transformedClearcoatNormalView"),Tl=Ai((([e,t=ju])=>{const r=Ki(t),s=e.div(Oi(r[0].dot(r[0]),r[1].dot(r[1]),r[2].dot(r[2])));return r.mul(s).xyz})),_l=Ai((([e],t)=>{const r=t.renderer.nodes.modelNormalViewMatrix;if(null!==r)return r.transformDirection(e);const s=Yu.mul(e);return Pu.transformDirection(s)})),vl=on(0).onReference((({material:e})=>e)).onRenderUpdate((({material:e})=>e.refractionRatio)),Nl=ul.negate().reflect(yl),Sl=ul.negate().refract(yl,vl),Al=Nl.transformDirection(Pu).toVar("reflectVector"),Rl=Sl.transformDirection(Pu).toVar("reflectVector");class Cl extends Cu{static get type(){return"CubeTextureNode"}constructor(e,t=null,r=null,s=null){super(e,t,r,s),this.isCubeTextureNode=!0}getInputType(){return"cubeTexture"}getDefaultUV(){const e=this.value;return e.mapping===_?Al:e.mapping===v?Rl:(console.error('THREE.CubeTextureNode: Mapping "%s" not supported.',e.mapping),Oi(0,0,0))}setUpdateMatrix(){}setupUV(e,t){const r=this.value;return e.renderer.coordinateSystem!==l&&r.isRenderTargetTexture?t:Oi(t.x.negate(),t.yz)}generateUV(e,t){return t.build(e,"vec3")}}const El=Ni(Cl);class wl extends nn{static get type(){return"BufferNode"}constructor(e,t,r=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferCount=r}getElementType(e){return this.getNodeType(e)}getInputType(){return"buffer"}}const Ml=(e,t,r)=>Ti(new wl(e,t,r));class Bl extends Is{static get type(){return"UniformArrayElementNode"}constructor(e,t){super(e,t),this.isArrayBufferElementNode=!0}generate(e){const t=super.generate(e),r=this.getNodeType(),s=this.node.getPaddedType();return e.format(t,s,r)}}class Ul extends wl{static get type(){return"UniformArrayNode"}constructor(e,t=null){super(null),this.array=e,this.elementType=null===t?xs(e[0]):t,this.paddedType=this.getPaddedType(),this.updateType=Rs.RENDER,this.isArrayBufferNode=!0}getNodeType(){return this.paddedType}getElementType(){return this.elementType}getPaddedType(){const e=this.elementType;let t="vec4";return"mat2"===e?t="mat2":!0===/mat/.test(e)?t="mat4":"i"===e.charAt(0)?t="ivec4":"u"===e.charAt(0)&&(t="uvec4"),t}update(){const{array:e,value:t}=this,r=this.elementType;if("float"===r||"int"===r||"uint"===r)for(let r=0;rTi(new Ul(e,t));class Pl extends Is{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),r=this.referenceNode.getNodeType(),s=this.getNodeType();return e.format(t,r,s)}}class Il extends Ps{static get type(){return"ReferenceNode"}constructor(e,t,r=null,s=null){super(),this.property=e,this.uniformType=t,this.object=r,this.count=s,this.properties=e.split("."),this.reference=r,this.node=null,this.group=null,this.name=null,this.updateType=Rs.OBJECT}element(e){return Ti(new Pl(this,Ti(e)))}setGroup(e){return this.group=e,this}label(e){return this.name=e,this}setNodeType(e){let t=null;t=null!==this.count?Ml(null,e,this.count):Array.isArray(this.getValueFromReference())?Fl(null,e):"texture"===e?Eu(null):"cubeTexture"===e?El(null):on(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 r=e[t[0]];for(let e=1;eTi(new Il(e,t,r)),Ll=(e,t,r,s)=>Ti(new Il(e,t,s,r));class Vl extends Il{static get type(){return"MaterialReferenceNode"}constructor(e,t,r=null){super(e,t,r),this.material=r,this.isMaterialReferenceNode=!0}updateReference(e){return this.reference=null!==this.material?this.material:e.material,this.reference}}const Ol=(e,t,r=null)=>Ti(new Vl(e,t,r)),Gl=Ai((e=>(!1===e.geometry.hasAttribute("tangent")&&e.geometry.computeTangents(),_u("tangent","vec4"))))(),kl=Gl.xyz.toVar("tangentLocal"),zl=Zu.mul($i(kl,0)).xyz.varying("v_tangentView").normalize().toVar("tangentView"),$l=zl.transformDirection(Pu).varying("v_tangentWorld").normalize().toVar("tangentWorld"),Hl=zl.toVar("transformedTangentView"),Wl=Hl.transformDirection(Pu).normalize().toVar("transformedTangentWorld"),jl=e=>e.mul(Gl.w).xyz,ql=La(jl(hl.cross(Gl)),"v_bitangentGeometry").normalize().toVar("bitangentGeometry"),Kl=La(jl(pl.cross(kl)),"v_bitangentLocal").normalize().toVar("bitangentLocal"),Xl=La(jl(ml.cross(zl)),"v_bitangentView").normalize().toVar("bitangentView"),Yl=La(jl(fl.cross($l)),"v_bitangentWorld").normalize().toVar("bitangentWorld"),Ql=jl(yl.cross(Hl)).normalize().toVar("transformedBitangentView"),Zl=Ql.transformDirection(Pu).normalize().toVar("transformedBitangentWorld"),Jl=Ki(zl,Xl,ml),ed=ul.mul(Jl),td=(()=>{let e=Sn.cross(ul);return e=e.cross(Sn).normalize(),e=pa(e,yl,vn.mul(hn.oneMinus()).oneMinus().pow2().pow2()).normalize(),e})(),rd=Ai((e=>{const{eye_pos:t,surf_norm:r,mapN:s,uv:i}=e,n=t.dFdx(),o=t.dFdy(),a=i.dFdx(),u=i.dFdy(),l=r,d=o.cross(l),c=l.cross(n),h=d.mul(a.x).add(c.mul(u.x)),p=d.mul(a.y).add(c.mul(u.y)),g=h.dot(h).max(p.dot(p)),m=cl.mul(g.inverseSqrt());return $n(h.mul(s.x,m),p.mul(s.y,m),l.mul(s.z)).normalize()}));class sd extends Ls{static get type(){return"NormalMapNode"}constructor(e,t=null){super("vec3"),this.node=e,this.scaleNode=t,this.normalMapType=N}setup(e){const{normalMapType:t,scaleNode:r}=this;let s=this.node.mul(2).sub(1);null!==r&&(s=Oi(s.xy.mul(r),s.z));let i=null;if(t===S)i=_l(s);else if(t===N){i=!0===e.hasGeometryAttribute("tangent")?Jl.mul(s).normalize():rd({eye_pos:al,surf_norm:ml,mapN:s,uv:vu()})}return i}}const id=Ni(sd),nd=Ai((({textureNode:e,bumpScale:t})=>{const r=t=>e.cache().context({getUV:e=>t(e.uvNode||vu()),forceUVContext:!0}),s=Bi(r((e=>e)));return Ii(Bi(r((e=>e.add(e.dFdx())))).sub(s),Bi(r((e=>e.add(e.dFdy())))).sub(s)).mul(t)})),od=Ai((e=>{const{surf_pos:t,surf_norm:r,dHdxy:s}=e,i=t.dFdx().normalize(),n=r,o=t.dFdy().normalize().cross(n),a=n.cross(i),u=i.dot(o).mul(cl),l=u.sign().mul(s.x.mul(o).add(s.y.mul(a)));return u.abs().mul(r).sub(l).normalize()}));class ad extends Ls{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=nd({textureNode:this.textureNode,bumpScale:e});return od({surf_pos:al,surf_norm:ml,dHdxy:t})}}const ud=Ni(ad),ld=new Map;class dd extends Ps{static get type(){return"MaterialNode"}constructor(e){super(),this.scope=e}getCache(e,t){let r=ld.get(e);return void 0===r&&(r=Ol(e,t),ld.set(e,r)),r}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,r=this.scope;let s=null;if(r===dd.COLOR){const e=void 0!==t.color?this.getColor(r):Oi();s=t.map&&!0===t.map.isTexture?e.mul(this.getTexture("map")):e}else if(r===dd.OPACITY){const e=this.getFloat(r);s=t.alphaMap&&!0===t.alphaMap.isTexture?e.mul(this.getTexture("alpha")):e}else if(r===dd.SPECULAR_STRENGTH)s=t.specularMap&&!0===t.specularMap.isTexture?this.getTexture("specular").r:Bi(1);else if(r===dd.SPECULAR_INTENSITY){const e=this.getFloat(r);s=t.specularIntensityMap&&!0===t.specularIntensityMap.isTexture?e.mul(this.getTexture(r).a):e}else if(r===dd.SPECULAR_COLOR){const e=this.getColor(r);s=t.specularColorMap&&!0===t.specularColorMap.isTexture?e.mul(this.getTexture(r).rgb):e}else if(r===dd.ROUGHNESS){const e=this.getFloat(r);s=t.roughnessMap&&!0===t.roughnessMap.isTexture?e.mul(this.getTexture(r).g):e}else if(r===dd.METALNESS){const e=this.getFloat(r);s=t.metalnessMap&&!0===t.metalnessMap.isTexture?e.mul(this.getTexture(r).b):e}else if(r===dd.EMISSIVE){const e=this.getFloat("emissiveIntensity"),i=this.getColor(r).mul(e);s=t.emissiveMap&&!0===t.emissiveMap.isTexture?i.mul(this.getTexture(r)):i}else if(r===dd.NORMAL)t.normalMap?(s=id(this.getTexture("normal"),this.getCache("normalScale","vec2")),s.normalMapType=t.normalMapType):s=t.bumpMap?ud(this.getTexture("bump").r,this.getFloat("bumpScale")):ml;else if(r===dd.CLEARCOAT){const e=this.getFloat(r);s=t.clearcoatMap&&!0===t.clearcoatMap.isTexture?e.mul(this.getTexture(r).r):e}else if(r===dd.CLEARCOAT_ROUGHNESS){const e=this.getFloat(r);s=t.clearcoatRoughnessMap&&!0===t.clearcoatRoughnessMap.isTexture?e.mul(this.getTexture(r).r):e}else if(r===dd.CLEARCOAT_NORMAL)s=t.clearcoatNormalMap?id(this.getTexture(r),this.getCache(r+"Scale","vec2")):ml;else if(r===dd.SHEEN){const e=this.getColor("sheenColor").mul(this.getFloat("sheen"));s=t.sheenColorMap&&!0===t.sheenColorMap.isTexture?e.mul(this.getTexture("sheenColor").rgb):e}else if(r===dd.SHEEN_ROUGHNESS){const e=this.getFloat(r);s=t.sheenRoughnessMap&&!0===t.sheenRoughnessMap.isTexture?e.mul(this.getTexture(r).a):e,s=s.clamp(.07,1)}else if(r===dd.ANISOTROPY)if(t.anisotropyMap&&!0===t.anisotropyMap.isTexture){const e=this.getTexture(r);s=qi(Kd.x,Kd.y,Kd.y.negate(),Kd.x).mul(e.rg.mul(2).sub(Ii(1)).normalize().mul(e.b))}else s=Kd;else if(r===dd.IRIDESCENCE_THICKNESS){const e=Dl("1","float",t.iridescenceThicknessRange);if(t.iridescenceThicknessMap){const i=Dl("0","float",t.iridescenceThicknessRange);s=e.sub(i).mul(this.getTexture(r).g).add(i)}else s=e}else if(r===dd.TRANSMISSION){const e=this.getFloat(r);s=t.transmissionMap?e.mul(this.getTexture(r).r):e}else if(r===dd.THICKNESS){const e=this.getFloat(r);s=t.thicknessMap?e.mul(this.getTexture(r).g):e}else if(r===dd.IOR)s=this.getFloat(r);else if(r===dd.LIGHT_MAP)s=this.getTexture(r).rgb.mul(this.getFloat("lightMapIntensity"));else if(r===dd.AO)s=this.getTexture(r).r.sub(1).mul(this.getFloat("aoMapIntensity")).add(1);else{const t=this.getNodeType(e);s=this.getCache(r,t)}return s}}dd.ALPHA_TEST="alphaTest",dd.COLOR="color",dd.OPACITY="opacity",dd.SHININESS="shininess",dd.SPECULAR="specular",dd.SPECULAR_STRENGTH="specularStrength",dd.SPECULAR_INTENSITY="specularIntensity",dd.SPECULAR_COLOR="specularColor",dd.REFLECTIVITY="reflectivity",dd.ROUGHNESS="roughness",dd.METALNESS="metalness",dd.NORMAL="normal",dd.CLEARCOAT="clearcoat",dd.CLEARCOAT_ROUGHNESS="clearcoatRoughness",dd.CLEARCOAT_NORMAL="clearcoatNormal",dd.EMISSIVE="emissive",dd.ROTATION="rotation",dd.SHEEN="sheen",dd.SHEEN_ROUGHNESS="sheenRoughness",dd.ANISOTROPY="anisotropy",dd.IRIDESCENCE="iridescence",dd.IRIDESCENCE_IOR="iridescenceIOR",dd.IRIDESCENCE_THICKNESS="iridescenceThickness",dd.IOR="ior",dd.TRANSMISSION="transmission",dd.THICKNESS="thickness",dd.ATTENUATION_DISTANCE="attenuationDistance",dd.ATTENUATION_COLOR="attenuationColor",dd.LINE_SCALE="scale",dd.LINE_DASH_SIZE="dashSize",dd.LINE_GAP_SIZE="gapSize",dd.LINE_WIDTH="linewidth",dd.LINE_DASH_OFFSET="dashOffset",dd.POINT_SIZE="size",dd.DISPERSION="dispersion",dd.LIGHT_MAP="light",dd.AO="ao";const cd=Si(dd,dd.ALPHA_TEST),hd=Si(dd,dd.COLOR),pd=Si(dd,dd.SHININESS),gd=Si(dd,dd.EMISSIVE),md=Si(dd,dd.OPACITY),fd=Si(dd,dd.SPECULAR),yd=Si(dd,dd.SPECULAR_INTENSITY),bd=Si(dd,dd.SPECULAR_COLOR),xd=Si(dd,dd.SPECULAR_STRENGTH),Td=Si(dd,dd.REFLECTIVITY),_d=Si(dd,dd.ROUGHNESS),vd=Si(dd,dd.METALNESS),Nd=Si(dd,dd.NORMAL),Sd=Si(dd,dd.CLEARCOAT),Ad=Si(dd,dd.CLEARCOAT_ROUGHNESS),Rd=Si(dd,dd.CLEARCOAT_NORMAL),Cd=Si(dd,dd.ROTATION),Ed=Si(dd,dd.SHEEN),wd=Si(dd,dd.SHEEN_ROUGHNESS),Md=Si(dd,dd.ANISOTROPY),Bd=Si(dd,dd.IRIDESCENCE),Ud=Si(dd,dd.IRIDESCENCE_IOR),Fd=Si(dd,dd.IRIDESCENCE_THICKNESS),Pd=Si(dd,dd.TRANSMISSION),Id=Si(dd,dd.THICKNESS),Dd=Si(dd,dd.IOR),Ld=Si(dd,dd.ATTENUATION_DISTANCE),Vd=Si(dd,dd.ATTENUATION_COLOR),Od=Si(dd,dd.LINE_SCALE),Gd=Si(dd,dd.LINE_DASH_SIZE),kd=Si(dd,dd.LINE_GAP_SIZE),zd=Si(dd,dd.LINE_WIDTH),$d=Si(dd,dd.LINE_DASH_OFFSET),Hd=Si(dd,dd.POINT_SIZE),Wd=Si(dd,dd.DISPERSION),jd=Si(dd,dd.LIGHT_MAP),qd=Si(dd,dd.AO),Kd=on(new t).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))})),Xd=Ai((e=>e.context.setupModelViewProjection()),"vec4").once()().varying("v_modelViewProjection");class Yd extends Ps{static get type(){return"IndexNode"}constructor(e){super("uint"),this.scope=e,this.isIndexNode=!0}generate(e){const t=this.getNodeType(e),r=this.scope;let s,i;if(r===Yd.VERTEX)s=e.getVertexIndex();else if(r===Yd.INSTANCE)s=e.getInstanceIndex();else if(r===Yd.DRAW)s=e.getDrawIndex();else if(r===Yd.INVOCATION_LOCAL)s=e.getInvocationLocalIndex();else if(r===Yd.INVOCATION_SUBGROUP)s=e.getInvocationSubgroupIndex();else{if(r!==Yd.SUBGROUP)throw new Error("THREE.IndexNode: Unknown scope: "+r);s=e.getSubgroupIndex()}if("vertex"===e.shaderStage||"compute"===e.shaderStage)i=s;else{i=La(this).build(e,t)}return i}}Yd.VERTEX="vertex",Yd.INSTANCE="instance",Yd.SUBGROUP="subgroup",Yd.INVOCATION_LOCAL="invocationLocal",Yd.INVOCATION_SUBGROUP="invocationSubgroup",Yd.DRAW="draw";const Qd=Si(Yd,Yd.VERTEX),Zd=Si(Yd,Yd.INSTANCE),Jd=Si(Yd,Yd.SUBGROUP),ec=Si(Yd,Yd.INVOCATION_SUBGROUP),tc=Si(Yd,Yd.INVOCATION_LOCAL),rc=Si(Yd,Yd.DRAW);class sc extends Ps{static get type(){return"InstanceNode"}constructor(e,t,r){super("void"),this.count=e,this.instanceMatrix=t,this.instanceColor=r,this.instanceMatrixNode=null,this.instanceColorNode=null,this.updateType=Rs.FRAME,this.buffer=null,this.bufferColor=null}setup(e){const{count:t,instanceMatrix:r,instanceColor:s}=this;let{instanceMatrixNode:i,instanceColorNode:n}=this;if(null===i){if(t<=1e3)i=Ml(r.array,"mat4",Math.max(t,1)).element(Zd);else{const e=new A(r.array,16,1);this.buffer=e;const t=r.usage===m?nu:iu,s=[t(e,"vec4",16,0),t(e,"vec4",16,4),t(e,"vec4",16,8),t(e,"vec4",16,12)];i=Xi(...s)}this.instanceMatrixNode=i}if(s&&null===n){const e=new R(s.array,3),t=s.usage===m?nu:iu;this.bufferColor=e,n=Oi(t(e,"vec3",3,0)),this.instanceColorNode=n}const o=i.mul(sl).xyz;if(sl.assign(o),e.hasGeometryAttribute("normal")){const e=Tl(pl,i);pl.assign(e)}null!==this.instanceColorNode&&ln("vec3","vInstanceColor").assign(this.instanceColorNode)}update(){this.instanceMatrix.usage!==m&&null!==this.buffer&&this.instanceMatrix.version!==this.buffer.version&&(this.buffer.version=this.instanceMatrix.version),this.instanceColor&&this.instanceColor.usage!==m&&null!==this.bufferColor&&this.instanceColor.version!==this.bufferColor.version&&(this.bufferColor.version=this.instanceColor.version)}}const ic=Ni(sc);class nc extends sc{static get type(){return"InstancedMeshNode"}constructor(e){const{count:t,instanceMatrix:r,instanceColor:s}=e;super(t,r,s),this.instancedMesh=e}}const oc=Ni(nc);class ac extends Ps{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=Zd:this.batchingIdNode=rc);const t=Ai((([e])=>{const t=Su(wu(this.batchMesh._indirectTexture),0),r=Ui(e).modInt(Ui(t)),s=Ui(e).div(Ui(t));return wu(this.batchMesh._indirectTexture,Di(r,s)).x})).setLayout({name:"getIndirectIndex",type:"uint",inputs:[{name:"id",type:"int"}]}),r=t(Ui(this.batchingIdNode)),s=this.batchMesh._matricesTexture,i=Su(wu(s),0),n=Bi(r).mul(4).toInt().toVar(),o=n.modInt(i),a=n.div(Ui(i)),u=Xi(wu(s,Di(o,a)),wu(s,Di(o.add(1),a)),wu(s,Di(o.add(2),a)),wu(s,Di(o.add(3),a))),l=this.batchMesh._colorsTexture;if(null!==l){const e=Ai((([e])=>{const t=Su(wu(l),0).x,r=e,s=r.modInt(t),i=r.div(t);return wu(l,Di(s,i)).rgb})).setLayout({name:"getBatchingColor",type:"vec3",inputs:[{name:"id",type:"int"}]}),t=e(r);ln("vec3","vBatchColor").assign(t)}const d=Ki(u);sl.assign(u.mul(sl));const c=pl.div(Oi(d[0].dot(d[0]),d[1].dot(d[1]),d[2].dot(d[2]))),h=d.mul(c).xyz;pl.assign(h),e.hasGeometryAttribute("tangent")&&kl.mulAssign(d)}}const uc=Ni(ac),lc=new WeakMap;class dc extends Ps{static get type(){return"SkinningNode"}constructor(e,t=!1){let r,s,i;super("void"),this.skinnedMesh=e,this.useReference=t,this.updateType=Rs.OBJECT,this.skinIndexNode=_u("skinIndex","uvec4"),this.skinWeightNode=_u("skinWeight","vec4"),t?(r=Dl("bindMatrix","mat4"),s=Dl("bindMatrixInverse","mat4"),i=Ll("skeleton.boneMatrices","mat4",e.skeleton.bones.length)):(r=on(e.bindMatrix,"mat4"),s=on(e.bindMatrixInverse,"mat4"),i=Ml(e.skeleton.boneMatrices,"mat4",e.skeleton.bones.length)),this.bindMatrixNode=r,this.bindMatrixInverseNode=s,this.boneMatricesNode=i,this.previousBoneMatricesNode=null}getSkinnedPosition(e=this.boneMatricesNode,t=sl){const{skinIndexNode:r,skinWeightNode:s,bindMatrixNode:i,bindMatrixInverseNode:n}=this,o=e.element(r.x),a=e.element(r.y),u=e.element(r.z),l=e.element(r.w),d=i.mul(t),c=$n(o.mul(s.x).mul(d),a.mul(s.y).mul(d),u.mul(s.z).mul(d),l.mul(s.w).mul(d));return n.mul(c).xyz}getSkinnedNormal(e=this.boneMatricesNode,t=pl){const{skinIndexNode:r,skinWeightNode:s,bindMatrixNode:i,bindMatrixInverseNode:n}=this,o=e.element(r.x),a=e.element(r.y),u=e.element(r.z),l=e.element(r.w);let d=$n(s.x.mul(o),s.y.mul(a),s.z.mul(u),s.w.mul(l));return d=n.mul(d).mul(i),d.transformDirection(t).xyz}getPreviousSkinnedPosition(e){const t=e.object;return null===this.previousBoneMatricesNode&&(t.skeleton.previousBoneMatrices=new Float32Array(t.skeleton.boneMatrices),this.previousBoneMatricesNode=Ll("skeleton.previousBoneMatrices","mat4",t.skeleton.bones.length)),this.getSkinnedPosition(this.previousBoneMatricesNode,il)}needsPreviousBoneMatrices(e){const t=e.renderer.getMRT();return t&&t.has("velocity")||!0===_s(e.object).useVelocity}setup(e){this.needsPreviousBoneMatrices(e)&&il.assign(this.getPreviousSkinnedPosition(e));const t=this.getSkinnedPosition();if(sl.assign(t),e.hasGeometryAttribute("normal")){const t=this.getSkinnedNormal();pl.assign(t),e.hasGeometryAttribute("tangent")&&kl.assign(t)}}generate(e,t){if("void"!==t)return sl.build(e,t)}update(e){const t=(this.useReference?e.object:this.skinnedMesh).skeleton;lc.get(t)!==e.frameId&&(lc.set(t,e.frameId),null!==this.previousBoneMatricesNode&&t.previousBoneMatrices.set(t.boneMatrices),t.update())}}const cc=e=>Ti(new dc(e,!0));class hc extends Ps{static get type(){return"LoopNode"}constructor(e=[]){super(),this.params=e}getVarName(e){return String.fromCharCode("i".charCodeAt(0)+e)}getProperties(e){const t=e.getNodeProperties(this);if(void 0!==t.stackNode)return t;const r={};for(let e=0,t=this.params.length-1;eNumber(n)?">=":"<"));const d={start:i,end:n,condition:u},c=d.start,h=d.end;let p="",g="",m="";l||(l="int"===a||"uint"===a?u.includes("<")?"++":"--":u.includes("<")?"+= 1.":"-= 1."),p+=e.getVar(a,o)+" = "+c,g+=o+" "+u+" "+h,m+=o+" "+l;const f=`for ( ${p}; ${g}; ${m} )`;e.addFlowCode((0===t?"\n":"")+e.tab+f+" {\n\n").addFlowTab()}const i=s.build(e,"void"),n=t.returnsNode?t.returnsNode.build(e):"";e.removeFlowTab().addFlowCode("\n"+e.tab+i);for(let t=0,r=this.params.length-1;tTi(new hc(vi(e,"int"))).append(),gc=()=>fu("break").append(),mc=new WeakMap,fc=new s,yc=Ai((({bufferMap:e,influence:t,stride:r,width:s,depth:i,offset:n})=>{const o=Ui(Qd).mul(r).add(n),a=o.div(s),u=o.sub(a.mul(s));return wu(e,Di(u,a)).depth(i).mul(t)}));class bc extends Ps{static get type(){return"MorphNode"}constructor(e){super("void"),this.mesh=e,this.morphBaseInfluence=on(1),this.updateType=Rs.OBJECT}setup(e){const{geometry:r}=e,s=void 0!==r.morphAttributes.position,i=r.hasAttribute("normal")&&void 0!==r.morphAttributes.normal,n=r.morphAttributes.position||r.morphAttributes.normal||r.morphAttributes.color,o=void 0!==n?n.length:0,{texture:a,stride:u,size:l}=function(e){const r=void 0!==e.morphAttributes.position,s=void 0!==e.morphAttributes.normal,i=void 0!==e.morphAttributes.color,n=e.morphAttributes.position||e.morphAttributes.normal||e.morphAttributes.color,o=void 0!==n?n.length:0;let a=mc.get(e);if(void 0===a||a.count!==o){void 0!==a&&a.texture.dispose();const u=e.morphAttributes.position||[],l=e.morphAttributes.normal||[],d=e.morphAttributes.color||[];let c=0;!0===r&&(c=1),!0===s&&(c=2),!0===i&&(c=3);let h=e.attributes.position.count*c,p=1;const g=4096;h>g&&(p=Math.ceil(h/g),h=g);const m=new Float32Array(h*p*4*o),f=new C(m,h,p,o);f.type=E,f.needsUpdate=!0;const y=4*c;for(let x=0;x{const t=Bi(0).toVar();this.mesh.count>1&&null!==this.mesh.morphTexture&&void 0!==this.mesh.morphTexture?t.assign(wu(this.mesh.morphTexture,Di(Ui(e).add(1),Ui(Zd))).r):t.assign(Dl("morphTargetInfluences","float").element(e).toVar()),!0===s&&sl.addAssign(yc({bufferMap:a,influence:t,stride:u,width:d,depth:e,offset:Ui(0)})),!0===i&&pl.addAssign(yc({bufferMap:a,influence:t,stride:u,width:d,depth:e,offset:Ui(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 xc=Ni(bc);class Tc extends Ps{static get type(){return"LightingNode"}constructor(){super("vec3"),this.isLightingNode=!0}}class _c extends Tc{static get type(){return"AONode"}constructor(e=null){super(),this.aoNode=e}setup(e){e.context.ambientOcclusion.mulAssign(this.aoNode)}}class vc extends Ea{static get type(){return"LightingContextNode"}constructor(e,t=null,r=null,s=null){super(e),this.lightingModel=t,this.backdropNode=r,this.backdropAlphaNode=s,this._value=null}getContext(){const{backdropNode:e,backdropAlphaNode:t}=this,r={directDiffuse:Oi().toVar("directDiffuse"),directSpecular:Oi().toVar("directSpecular"),indirectDiffuse:Oi().toVar("indirectDiffuse"),indirectSpecular:Oi().toVar("indirectSpecular")};return{radiance:Oi().toVar("radiance"),irradiance:Oi().toVar("irradiance"),iblIrradiance:Oi().toVar("iblIrradiance"),ambientOcclusion:Bi(1).toVar("ambientOcclusion"),reflectedLight:r,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 Nc=Ni(vc);class Sc extends Tc{static get type(){return"IrradianceNode"}constructor(e){super(),this.node=e}setup(e){e.context.irradiance.addAssign(this.node)}}let Ac,Rc;class Cc extends Ps{static get type(){return"ScreenNode"}constructor(e){super(),this.scope=e,this.isViewportNode=!0}getNodeType(){return this.scope===Cc.VIEWPORT?"vec4":"vec2"}getUpdateType(){let e=Rs.NONE;return this.scope!==Cc.SIZE&&this.scope!==Cc.VIEWPORT||(e=Rs.RENDER),this.updateType=e,e}update({renderer:e}){const t=e.getRenderTarget();this.scope===Cc.VIEWPORT?null!==t?Rc.copy(t.viewport):(e.getViewport(Rc),Rc.multiplyScalar(e.getPixelRatio())):null!==t?(Ac.width=t.width,Ac.height=t.height):e.getDrawingBufferSize(Ac)}setup(){const e=this.scope;let r=null;return r=e===Cc.SIZE?on(Ac||(Ac=new t)):e===Cc.VIEWPORT?on(Rc||(Rc=new s)):Ii(Mc.div(wc)),r}generate(e){if(this.scope===Cc.COORDINATE){let t=e.getFragCoord();if(e.isFlipY()){const r=e.getNodeProperties(wc).outputNode.build(e);t=`${e.getType("vec2")}( ${t}.x, ${r}.y - ${t}.y )`}return t}return super.generate(e)}}Cc.COORDINATE="coordinate",Cc.VIEWPORT="viewport",Cc.SIZE="size",Cc.UV="uv";const Ec=Si(Cc,Cc.UV),wc=Si(Cc,Cc.SIZE),Mc=Si(Cc,Cc.COORDINATE),Bc=Si(Cc,Cc.VIEWPORT),Uc=Bc.zw,Fc=Mc.sub(Bc.xy),Pc=Fc.div(Uc),Ic=Ai((()=>(console.warn('TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.'),wc)),"vec2").once()(),Dc=Ai((()=>(console.warn('TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.'),Ec)),"vec2").once()(),Lc=Ai((()=>(console.warn('TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.'),Ec.flipY())),"vec2").once()(),Vc=new t;class Oc extends Cu{static get type(){return"ViewportTextureNode"}constructor(e=Ec,t=null,r=null){null===r&&((r=new w).minFilter=M),super(r,e,t),this.generateMipmaps=!1,this.isOutputTextureNode=!0,this.updateBeforeType=Rs.FRAME}updateBefore(e){const t=e.renderer;t.getDrawingBufferSize(Vc);const r=this.value;r.image.width===Vc.width&&r.image.height===Vc.height||(r.image.width=Vc.width,r.image.height=Vc.height,r.needsUpdate=!0);const s=r.generateMipmaps;r.generateMipmaps=this.generateMipmaps,t.copyFramebufferToTexture(r),r.generateMipmaps=s}clone(){const e=new this.constructor(this.uvNode,this.levelNode,this.value);return e.generateMipmaps=this.generateMipmaps,e}}const Gc=Ni(Oc),kc=Ni(Oc,null,null,{generateMipmaps:!0});let zc=null;class $c extends Oc{static get type(){return"ViewportDepthTextureNode"}constructor(e=Ec,t=null){null===zc&&(zc=new B),super(e,t,zc)}}const Hc=Ni($c);class Wc extends Ps{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===Wc.DEPTH_BASE?e.getFragDepth():super.generate(e)}setup({camera:e}){const{scope:t}=this,r=this.valueNode;let s=null;if(t===Wc.DEPTH_BASE)null!==r&&(s=Yc().assign(r));else if(t===Wc.DEPTH)s=e.isPerspectiveCamera?qc(al.z,Mu,Bu):jc(al.z,Mu,Bu);else if(t===Wc.LINEAR_DEPTH)if(null!==r)if(e.isPerspectiveCamera){const e=Kc(r,Mu,Bu);s=jc(e,Mu,Bu)}else s=r;else s=jc(al.z,Mu,Bu);return s}}Wc.DEPTH_BASE="depthBase",Wc.DEPTH="depth",Wc.LINEAR_DEPTH="linearDepth";const jc=(e,t,r)=>e.add(t).div(t.sub(r)),qc=(e,t,r)=>t.add(e).mul(r).div(r.sub(t).mul(e)),Kc=(e,t,r)=>t.mul(r).div(r.sub(t).mul(e).sub(r)),Xc=(e,t,r)=>{t=t.max(1e-6).toVar();const s=So(e.negate().div(t)),i=So(r.div(t));return s.div(i)},Yc=Ni(Wc,Wc.DEPTH_BASE),Qc=Si(Wc,Wc.DEPTH),Zc=Ni(Wc,Wc.LINEAR_DEPTH),Jc=Zc(Hc());Qc.assign=e=>Yc(e);const eh=Ni(class extends Ps{constructor(e){super("float"),this.name=e,this.isBuiltinNode=!0}generate(){return this.name}});class th extends Ps{static get type(){return"ClippingNode"}constructor(e=th.DEFAULT){super(),this.scope=e}setup(e){super.setup(e);const t=e.clippingContext,{intersectionPlanes:r,unionPlanes:s}=t;return this.hardwareClipping=e.material.hardwareClipping,this.scope===th.ALPHA_TO_COVERAGE?this.setupAlphaToCoverage(r,s):this.scope===th.HARDWARE?this.setupHardwareClipping(s,e):this.setupDefault(r,s)}setupAlphaToCoverage(e,t){return Ai((()=>{const r=Bi().toVar("distanceToPlane"),s=Bi().toVar("distanceToGradient"),i=Bi(1).toVar("clipOpacity"),n=t.length;if(!1===this.hardwareClipping&&n>0){const e=Fl(t);pc(n,(({i:t})=>{const n=e.element(t);r.assign(al.dot(n.xyz).negate().add(n.w)),s.assign(r.fwidth().div(2)),i.mulAssign(ya(s.negate(),s,r))}))}const o=e.length;if(o>0){const t=Fl(e),n=Bi(1).toVar("intersectionClipOpacity");pc(o,(({i:e})=>{const i=t.element(e);r.assign(al.dot(i.xyz).negate().add(i.w)),s.assign(r.fwidth().div(2)),n.mulAssign(ya(s.negate(),s,r).oneMinus())})),i.mulAssign(n.oneMinus())}dn.a.mulAssign(i),dn.a.equal(0).discard()}))()}setupDefault(e,t){return Ai((()=>{const r=t.length;if(!1===this.hardwareClipping&&r>0){const e=Fl(t);pc(r,(({i:t})=>{const r=e.element(t);al.dot(r.xyz).greaterThan(r.w).discard()}))}const s=e.length;if(s>0){const t=Fl(e),r=Pi(!0).toVar("clipped");pc(s,(({i:e})=>{const s=t.element(e);r.assign(al.dot(s.xyz).greaterThan(s.w).and(r))})),r.discard()}}))()}setupHardwareClipping(e,t){const r=e.length;return t.enableHardwareClipping(r),Ai((()=>{const s=Fl(e),i=eh(t.getClipDistance());pc(r,(({i:e})=>{const t=s.element(e),r=al.dot(t.xyz).sub(t.w).negate();i.element(e).assign(r)}))}))()}}th.ALPHA_TO_COVERAGE="alphaToCoverage",th.DEFAULT="default",th.HARDWARE="hardware";const rh=Ai((([e])=>Mo(Wn(1e4,Bo(Wn(17,e.x).add(Wn(.1,e.y)))).mul($n(.1,Lo(Bo(Wn(13,e.y).add(e.x)))))))),sh=Ai((([e])=>rh(Ii(rh(e.xy),e.z)))),ih=Ai((([e])=>{const t=Zo(Oo(zo(e.xyz)),Oo($o(e.xyz))),r=Bi(1).div(Bi(.05).mul(t)).toVar("pixScale"),s=Ii(vo(Co(So(r))),vo(Eo(So(r)))),i=Ii(sh(Co(s.x.mul(e.xyz))),sh(Co(s.y.mul(e.xyz)))),n=Mo(So(r)),o=$n(Wn(n.oneMinus(),i.x),Wn(n,i.y)),a=Qo(n,n.oneMinus()),u=Oi(o.mul(o).div(Wn(2,a).mul(Hn(1,a))),o.sub(Wn(.5,a)).div(Hn(1,a)),Hn(1,Hn(1,o).mul(Hn(1,o)).div(Wn(2,a).mul(Hn(1,a))))),l=o.lessThan(a.oneMinus()).select(o.lessThan(a).select(u.x,u.y),u.z);return ga(l,1e-6,1)})).setLayout({name:"getAlphaHashThreshold",type:"float",inputs:[{name:"position",type:"vec3"}]});class nh extends U{static get type(){return"NodeMaterial"}get type(){return this.constructor.type}set type(e){}constructor(){super(),this.isNodeMaterial=!0,this.fog=!0,this.lights=!1,this.hardwareClipping=!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.geometryNode=null,this.depthNode=null,this.shadowPositionNode=null,this.receivedShadowNode=null,this.castShadowNode=null,this.outputNode=null,this.mrtNode=null,this.fragmentNode=null,this.vertexNode=null}customProgramCacheKey(){return this.type+hs(this)}build(e){this.setup(e)}setupObserver(e){return new as(e)}setup(e){e.context.setupNormal=()=>this.setupNormal(e),e.context.setupPositionView=()=>this.setupPositionView(e),e.context.setupModelViewProjection=()=>this.setupModelViewProjection(e);const t=e.renderer,r=t.getRenderTarget();e.addStack();const s=this.vertexNode||this.setupVertex(e);let i;e.stack.outputNode=s,this.setupHardwareClipping(e),null!==this.geometryNode&&(e.stack.outputNode=e.stack.outputNode.bypass(this.geometryNode)),e.addFlow("vertex",e.removeStack()),e.addStack();const n=this.setupClipping(e);if(!0!==this.depthWrite&&!0!==this.depthTest||(null!==r?!0===r.depthBuffer&&this.setupDepth(e):!0===t.depth&&this.setupDepth(e)),null===this.fragmentNode){this.setupDiffuseColor(e),this.setupVariants(e);const s=this.setupLighting(e);null!==n&&e.stack.add(n);const o=$i(s,dn.a).max(0);if(i=this.setupOutput(e,o),En.assign(i),null!==this.outputNode&&(i=this.outputNode),null!==r){const e=t.getMRT(),r=this.mrtNode;null!==e?(i=e,null!==r&&(i=e.merge(r))):null!==r&&(i=r)}}else{let t=this.fragmentNode;!0!==t.isOutputStructNode&&(t=$i(t)),i=this.setupOutput(e,t)}e.stack.outputNode=i,e.addFlow("fragment",e.removeStack()),e.monitor=this.setupObserver(e)}setupClipping(e){if(null===e.clippingContext)return null;const{unionPlanes:t,intersectionPlanes:r}=e.clippingContext;let s=null;if(t.length>0||r.length>0){const t=e.renderer.samples;this.alphaToCoverage&&t>1?s=Ti(new th(th.ALPHA_TO_COVERAGE)):e.stack.add(Ti(new th))}return s}setupHardwareClipping(e){if(this.hardwareClipping=!1,null===e.clippingContext)return;const t=e.clippingContext.unionPlanes.length;t>0&&t<=8&&e.isAvailable("clipDistance")&&(e.stack.add(Ti(new th(th.HARDWARE))),this.hardwareClipping=!0)}setupDepth(e){const{renderer:t,camera:r}=e;let s=this.depthNode;if(null===s){const e=t.getMRT();e&&e.has("depth")?s=e.get("depth"):!0===t.logarithmicDepthBuffer&&(s=r.isPerspectiveCamera?Xc(al.z,Mu,Bu):jc(al.z,Mu,Bu))}null!==s&&Qc.assign(s).append()}setupPositionView(){return Zu.mul(sl).xyz}setupModelViewProjection(){return Uu.mul(al)}setupVertex(e){return e.addStack(),this.setupPosition(e),e.context.vertex=e.removeStack(),Xd}setupPosition(e){const{object:t,geometry:r}=e;if((r.morphAttributes.position||r.morphAttributes.normal||r.morphAttributes.color)&&xc(t).append(),!0===t.isSkinnedMesh&&cc(t).append(),this.displacementMap){const e=Ol("displacementMap","texture"),t=Ol("displacementScale","float"),r=Ol("displacementBias","float");sl.addAssign(pl.normalize().mul(e.x.mul(t).add(r)))}return t.isBatchedMesh&&uc(t).append(),t.isInstancedMesh&&t.instanceMatrix&&!0===t.instanceMatrix.isInstancedBufferAttribute&&oc(t).append(),null!==this.positionNode&&sl.assign(this.positionNode.context({isPositionNodeInput:!0})),sl}setupDiffuseColor({object:e,geometry:t}){let r=this.colorNode?$i(this.colorNode):hd;if(!0===this.vertexColors&&t.hasAttribute("color")&&(r=$i(r.xyz.mul(_u("color","vec3")),r.a)),e.instanceColor){r=ln("vec3","vInstanceColor").mul(r)}if(e.isBatchedMesh&&e._colorsTexture){r=ln("vec3","vBatchColor").mul(r)}dn.assign(r);const s=this.opacityNode?Bi(this.opacityNode):md;if(dn.a.assign(dn.a.mul(s)),null!==this.alphaTestNode||this.alphaTest>0){const e=null!==this.alphaTestNode?Bi(this.alphaTestNode):cd;dn.a.lessThanEqual(e).discard()}!0===this.alphaHash&&dn.a.lessThan(ih(sl)).discard(),!1===this.transparent&&this.blending===F&&!1===this.alphaToCoverage&&dn.a.assign(1)}setupVariants(){}setupOutgoingLight(){return!0===this.lights?Oi(0):dn.rgb}setupNormal(){return this.normalNode?Oi(this.normalNode):Nd}setupEnvironment(){let e=null;return this.envNode?e=this.envNode:this.envMap&&(e=this.envMap.isCubeTexture?Ol("envMap","cubeTexture"):Ol("envMap","texture")),e}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new Sc(jd)),t}setupLights(e){const t=[],r=this.setupEnvironment(e);r&&r.isLightingNode&&t.push(r);const s=this.setupLightMap(e);if(s&&s.isLightingNode&&t.push(s),null!==this.aoNode||e.material.aoMap){const e=null!==this.aoNode?this.aoNode:qd;t.push(new _c(e))}let i=this.lightsNode||e.lightsNode;return t.length>0&&(i=e.renderer.lighting.createNode([...i.getLights(),...t])),i}setupLightingModel(){}setupLighting(e){const{material:t}=e,{backdropNode:r,backdropAlphaNode:s,emissiveNode:i}=this,n=!0===this.lights||null!==this.lightsNode?this.setupLights(e):null;let o=this.setupOutgoingLight(e);if(n&&n.getScope().hasLights){const t=this.setupLightingModel(e);o=Nc(n,t,r,s)}else null!==r&&(o=Oi(null!==s?pa(o,r,s):r));return(i&&!0===i.isNode||t.emissive&&!0===t.emissive.isColor)&&(cn.assign(Oi(i||gd)),o=o.add(cn)),o}setupOutput(e,t){if(!0===this.fog){const r=e.fogNode;r&&(En.assign(t),t=$i(r))}return t}setDefaultValues(e){for(const t in e){const r=e[t];void 0===this[t]&&(this[t]=r,r&&r.clone&&(this[t]=r.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 r=U.prototype.toJSON.call(this,e),s=ps(this);r.inputNodes={};for(const{property:t,childNode:i}of s)r.inputNodes[t]=i.toJSON(e).uuid;function i(e){const t=[];for(const r in e){const s=e[r];delete s.metadata,t.push(s)}return t}if(t){const t=i(e.textures),s=i(e.images),n=i(e.nodes);t.length>0&&(r.textures=t),s.length>0&&(r.images=s),n.length>0&&(r.nodes=n)}return r}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.geometryNode=e.geometryNode,this.depthNode=e.depthNode,this.shadowPositionNode=e.shadowPositionNode,this.receivedShadowNode=e.receivedShadowNode,this.castShadowNode=e.castShadowNode,this.outputNode=e.outputNode,this.mrtNode=e.mrtNode,this.fragmentNode=e.fragmentNode,this.vertexNode=e.vertexNode,super.copy(e)}}const oh=new P;class ah extends nh{static get type(){return"LineBasicNodeMaterial"}constructor(e){super(),this.isLineBasicNodeMaterial=!0,this.setDefaultValues(oh),this.setValues(e)}}const uh=new I;class lh extends nh{static get type(){return"LineDashedNodeMaterial"}constructor(e){super(),this.isLineDashedNodeMaterial=!0,this.setDefaultValues(uh),this.dashOffset=0,this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setupVariants(){const e=this.offsetNode?Bi(this.offsetNode):$d,t=this.dashScaleNode?Bi(this.dashScaleNode):Od,r=this.dashSizeNode?Bi(this.dashSizeNode):Gd,s=this.gapSizeNode?Bi(this.gapSizeNode):kd;wn.assign(r),Mn.assign(s);const i=La(_u("lineDistance").mul(t));(e?i.add(e):i).mod(wn.add(Mn)).greaterThan(wn).discard()}}let dh=null;class ch extends Oc{static get type(){return"ViewportSharedTextureNode"}constructor(e=Ec,t=null){null===dh&&(dh=new w),super(e,t,dh)}updateReference(){return this}}const hh=Ni(ch),ph=new I;class gh extends nh{static get type(){return"Line2NodeMaterial"}constructor(e={}){super(),this.isLine2NodeMaterial=!0,this.setDefaultValues(ph),this.useColor=e.vertexColors,this.dashOffset=0,this.lineWidth=1,this.lineColorNode=null,this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.blending=D,this._useDash=e.dashed,this._useAlphaToCoverage=!0,this._useWorldUnits=!1,this.setValues(e)}setup(e){const{renderer:t}=e,r=this._useAlphaToCoverage,s=this.useColor,i=this._useDash,n=this._useWorldUnits,o=Ai((({start:e,end:t})=>{const r=Uu.element(2).element(2),s=Uu.element(3).element(2).mul(-.5).div(r).sub(e.z).div(t.z.sub(e.z));return $i(pa(e.xyz,t.xyz,s),t.w)})).setLayout({name:"trimSegment",type:"vec4",inputs:[{name:"start",type:"vec4"},{name:"end",type:"vec4"}]});this.vertexNode=Ai((()=>{const e=_u("instanceStart"),t=_u("instanceEnd"),r=$i(Zu.mul($i(e,1))).toVar("start"),s=$i(Zu.mul($i(t,1))).toVar("end");if(i){const e=this.dashScaleNode?Bi(this.dashScaleNode):Od,t=this.offsetNode?Bi(this.offsetNode):$d,r=_u("instanceDistanceStart"),s=_u("instanceDistanceEnd");let i=rl.y.lessThan(.5).select(e.mul(r),e.mul(s));i=i.add(t),ln("float","lineDistance").assign(i)}n&&(ln("vec3","worldStart").assign(r.xyz),ln("vec3","worldEnd").assign(s.xyz));const a=Bc.z.div(Bc.w),u=Uu.element(2).element(3).equal(-1);Ei(u,(()=>{Ei(r.z.lessThan(0).and(s.z.greaterThan(0)),(()=>{s.assign(o({start:r,end:s}))})).ElseIf(s.z.lessThan(0).and(r.z.greaterThanEqual(0)),(()=>{r.assign(o({start:s,end:r}))}))}));const l=Uu.mul(r),d=Uu.mul(s),c=l.xyz.div(l.w),h=d.xyz.div(d.w),p=h.xy.sub(c.xy).toVar();p.x.assign(p.x.mul(a)),p.assign(p.normalize());const g=$i().toVar();if(n){const e=s.xyz.sub(r.xyz).normalize(),t=pa(r.xyz,s.xyz,.5).normalize(),n=e.cross(t).normalize(),o=e.cross(n),a=ln("vec4","worldPos");a.assign(rl.y.lessThan(.5).select(r,s));const u=zd.mul(.5);a.addAssign($i(rl.x.lessThan(0).select(n.mul(u),n.mul(u).negate()),0)),i||(a.addAssign($i(rl.y.lessThan(.5).select(e.mul(u).negate(),e.mul(u)),0)),a.addAssign($i(o.mul(u),0)),Ei(rl.y.greaterThan(1).or(rl.y.lessThan(0)),(()=>{a.subAssign($i(o.mul(2).mul(u),0))}))),g.assign(Uu.mul(a));const l=Oi().toVar();l.assign(rl.y.lessThan(.5).select(c,h)),g.z.assign(l.z.mul(g.w))}else{const e=Ii(p.y,p.x.negate()).toVar("offset");p.x.assign(p.x.div(a)),e.x.assign(e.x.div(a)),e.assign(rl.x.lessThan(0).select(e.negate(),e)),Ei(rl.y.lessThan(0),(()=>{e.assign(e.sub(p))})).ElseIf(rl.y.greaterThan(1),(()=>{e.assign(e.add(p))})),e.assign(e.mul(zd)),e.assign(e.div(Bc.w)),g.assign(rl.y.lessThan(.5).select(l,d)),e.assign(e.mul(g.w)),g.assign(g.add($i(e,0,0)))}return g}))();const a=Ai((({p1:e,p2:t,p3:r,p4:s})=>{const i=e.sub(r),n=s.sub(r),o=t.sub(e),a=i.dot(n),u=n.dot(o),l=i.dot(o),d=n.dot(n),c=o.dot(o).mul(d).sub(u.mul(u)),h=a.mul(u).sub(l.mul(d)).div(c).clamp(),p=a.add(u.mul(h)).div(d).clamp();return Ii(h,p)}));if(this.colorNode=Ai((()=>{const e=vu();if(i){const t=this.dashSizeNode?Bi(this.dashSizeNode):Gd,r=this.gapSizeNode?Bi(this.gapSizeNode):kd;wn.assign(t),Mn.assign(r);const s=ln("float","lineDistance");e.y.lessThan(-1).or(e.y.greaterThan(1)).discard(),s.mod(wn.add(Mn)).greaterThan(wn).discard()}const o=Bi(1).toVar("alpha");if(n){const e=ln("vec3","worldStart"),s=ln("vec3","worldEnd"),n=ln("vec4","worldPos").xyz.normalize().mul(1e5),u=s.sub(e),l=a({p1:e,p2:s,p3:Oi(0,0,0),p4:n}),d=e.add(u.mul(l.x)),c=n.mul(l.y),h=d.sub(c).length().div(zd);if(!i)if(r&&t.samples>1){const e=h.fwidth();o.assign(ya(e.negate().add(.5),e.add(.5),h).oneMinus())}else h.greaterThan(.5).discard()}else if(r&&t.samples>1){const t=e.x,r=e.y.greaterThan(0).select(e.y.sub(1),e.y.add(1)),s=t.mul(t).add(r.mul(r)),i=Bi(s.fwidth()).toVar("dlen");Ei(e.y.abs().greaterThan(1),(()=>{o.assign(ya(i.oneMinus(),i.add(1),s).oneMinus())}))}else Ei(e.y.abs().greaterThan(1),(()=>{const t=e.x,r=e.y.greaterThan(0).select(e.y.sub(1),e.y.add(1));t.mul(t).add(r.mul(r)).greaterThan(1).discard()}));let u;if(this.lineColorNode)u=this.lineColorNode;else if(s){const e=_u("instanceColorStart"),t=_u("instanceColorEnd");u=rl.y.lessThan(.5).select(e,t).mul(hd)}else u=hd;return $i(u,o)}))(),this.transparent){const e=this.opacityNode?Bi(this.opacityNode):md;this.outputNode=$i(this.colorNode.rgb.mul(e).add(hh().rgb.mul(e.oneMinus())),this.colorNode.a)}super.setup(e)}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 mh=e=>Ti(e).mul(.5).add(.5),fh=new L;class yh extends nh{static get type(){return"MeshNormalNodeMaterial"}constructor(e){super(),this.isMeshNormalNodeMaterial=!0,this.setDefaultValues(fh),this.setValues(e)}setupDiffuseColor(){const e=this.opacityNode?Bi(this.opacityNode):md;dn.assign($i(mh(yl),e))}}class bh extends Ls{static get type(){return"EquirectUVNode"}constructor(e=ol){super("vec2"),this.dirNode=e}setup(){const e=this.dirNode,t=e.z.atan(e.x).mul(1/(2*Math.PI)).add(.5),r=e.y.clamp(-1,1).asin().mul(1/Math.PI).add(.5);return Ii(t,r)}}const xh=Ni(bh);class Th extends V{constructor(e=1,t={}){super(e,t),this.isCubeRenderTarget=!0}fromEquirectangularTexture(e,t){const r=t.minFilter,s=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 i=new O(5,5,5),n=xh(ol),o=new nh;o.colorNode=Eu(t,n,0),o.side=T,o.blending=D;const a=new G(i,o),u=new k;u.add(a),t.minFilter===M&&(t.minFilter=z);const l=new $(1,10,this),d=e.getMRT();return e.setMRT(null),l.update(e,u),e.setMRT(d),t.minFilter=r,t.currentGenerateMipmaps=s,a.geometry.dispose(),a.material.dispose(),this}}const _h=new WeakMap;class vh extends Ls{static get type(){return"CubeMapNode"}constructor(e){super("vec3"),this.envNode=e,this._cubeTexture=null,this._cubeTextureNode=El();const t=new H;t.isRenderTargetTexture=!0,this._defaultTexture=t,this.updateBeforeType=Rs.RENDER}updateBefore(e){const{renderer:t,material:r}=e,s=this.envNode;if(s.isTextureNode||s.isMaterialReferenceNode){const e=s.isTextureNode?s.value:r[s.property];if(e&&e.isTexture){const r=e.mapping;if(r===W||r===j){if(_h.has(e)){const t=_h.get(e);Sh(t,e.mapping),this._cubeTexture=t}else{const r=e.image;if(function(e){return null!=e&&e.height>0}(r)){const s=new Th(r.height);s.fromEquirectangularTexture(t,e),Sh(s.texture,e.mapping),this._cubeTexture=s.texture,_h.set(e,s.texture),e.addEventListener("dispose",Nh)}else this._cubeTexture=this._defaultTexture}this._cubeTextureNode.value=this._cubeTexture}else this._cubeTextureNode=this.envNode}}}setup(e){return this.updateBefore(e),this._cubeTextureNode}}function Nh(e){const t=e.target;t.removeEventListener("dispose",Nh);const r=_h.get(t);void 0!==r&&(_h.delete(t),r.dispose())}function Sh(e,t){t===W?e.mapping=_:t===j&&(e.mapping=v)}const Ah=Ni(vh);class Rh extends Tc{static get type(){return"BasicEnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){e.context.environment=Ah(this.envNode)}}class Ch extends Tc{static get type(){return"BasicLightMapNode"}constructor(e=null){super(),this.lightMapNode=e}setup(e){const t=Bi(1/Math.PI);e.context.irradianceLightMap=this.lightMapNode.mul(t)}}class Eh{start(){}finish(){}direct(){}directRectArea(){}indirect(){}ambientOcclusion(){}}class wh extends Eh{constructor(){super()}indirect(e,t,r){const s=e.ambientOcclusion,i=e.reflectedLight,n=r.context.irradianceLightMap;i.indirectDiffuse.assign($i(0)),n?i.indirectDiffuse.addAssign(n):i.indirectDiffuse.addAssign($i(1,1,1,0)),i.indirectDiffuse.mulAssign(s),i.indirectDiffuse.mulAssign(dn.rgb)}finish(e,t,r){const s=r.material,i=e.outgoingLight,n=r.context.environment;if(n)switch(s.combine){case X:i.rgb.assign(pa(i.rgb,i.rgb.mul(n.rgb),xd.mul(Td)));break;case K:i.rgb.assign(pa(i.rgb,n.rgb,xd.mul(Td)));break;case q:i.rgb.addAssign(n.rgb.mul(xd.mul(Td)));break;default:console.warn("THREE.BasicLightingModel: Unsupported .combine value:",s.combine)}}}const Mh=new Y;class Bh extends nh{static get type(){return"MeshBasicNodeMaterial"}constructor(e){super(),this.isMeshBasicNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Mh),this.setValues(e)}setupNormal(){return ml}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new Rh(t):null}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new Ch(jd)),t}setupOutgoingLight(){return dn.rgb}setupLightingModel(){return new wh}}const Uh=Ai((({f0:e,f90:t,dotVH:r})=>{const s=r.mul(-5.55473).sub(6.98316).mul(r).exp2();return e.mul(s.oneMinus()).add(t.mul(s))})),Fh=Ai((e=>e.diffuseColor.mul(1/Math.PI))),Ph=Ai((({dotNH:e})=>Cn.mul(Bi(.5)).add(1).mul(Bi(1/Math.PI)).mul(e.pow(Cn)))),Ih=Ai((({lightDirection:e})=>{const t=e.add(ul).normalize(),r=yl.dot(t).clamp(),s=ul.dot(t).clamp(),i=Uh({f0:An,f90:1,dotVH:s}),n=Bi(.25),o=Ph({dotNH:r});return i.mul(n).mul(o)}));class Dh extends wh{constructor(e=!0){super(),this.specular=e}direct({lightDirection:e,lightColor:t,reflectedLight:r}){const s=yl.dot(e).clamp().mul(t);r.directDiffuse.addAssign(s.mul(Fh({diffuseColor:dn.rgb}))),!0===this.specular&&r.directSpecular.addAssign(s.mul(Ih({lightDirection:e})).mul(xd))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:r}){r.indirectDiffuse.addAssign(t.mul(Fh({diffuseColor:dn}))),r.indirectDiffuse.mulAssign(e)}}const Lh=new Q;class Vh extends nh{static get type(){return"MeshLambertNodeMaterial"}constructor(e){super(),this.isMeshLambertNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Lh),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new Rh(t):null}setupLightingModel(){return new Dh(!1)}}const Oh=new Z;class Gh extends nh{static get type(){return"MeshPhongNodeMaterial"}constructor(e){super(),this.isMeshPhongNodeMaterial=!0,this.lights=!0,this.shininessNode=null,this.specularNode=null,this.setDefaultValues(Oh),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new Rh(t):null}setupLightingModel(){return new Dh}setupVariants(){const e=(this.shininessNode?Bi(this.shininessNode):pd).max(1e-4);Cn.assign(e);const t=this.specularNode||fd;An.assign(t)}copy(e){return this.shininessNode=e.shininessNode,this.specularNode=e.specularNode,super.copy(e)}}const kh=Ai((e=>{if(!1===e.geometry.hasAttribute("normal"))return Bi(0);const t=ml.dFdx().abs().max(ml.dFdy().abs());return t.x.max(t.y).max(t.z)})),zh=Ai((e=>{const{roughness:t}=e,r=kh();let s=t.max(.0525);return s=s.add(r),s=s.min(1),s})),$h=Ai((({alpha:e,dotNL:t,dotNV:r})=>{const s=e.pow2(),i=t.mul(s.add(s.oneMinus().mul(r.pow2())).sqrt()),n=r.mul(s.add(s.oneMinus().mul(t.pow2())).sqrt());return jn(.5,i.add(n).max(po))})).setLayout({name:"V_GGX_SmithCorrelated",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNL",type:"float"},{name:"dotNV",type:"float"}]}),Hh=Ai((({alphaT:e,alphaB:t,dotTV:r,dotBV:s,dotTL:i,dotBL:n,dotNV:o,dotNL:a})=>{const u=a.mul(Oi(e.mul(r),t.mul(s),o).length()),l=o.mul(Oi(e.mul(i),t.mul(n),a).length());return jn(.5,u.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"}]}),Wh=Ai((({alpha:e,dotNH:t})=>{const r=e.pow2(),s=t.pow2().mul(r.oneMinus()).oneMinus();return r.div(s.pow2()).mul(1/Math.PI)})).setLayout({name:"D_GGX",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNH",type:"float"}]}),jh=Bi(1/Math.PI),qh=Ai((({alphaT:e,alphaB:t,dotNH:r,dotTH:s,dotBH:i})=>{const n=e.mul(t),o=Oi(t.mul(s),e.mul(i),n.mul(r)),a=o.dot(o),u=n.div(a);return jh.mul(n.mul(u.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"}]}),Kh=Ai((e=>{const{lightDirection:t,f0:r,f90:s,roughness:i,f:n,USE_IRIDESCENCE:o,USE_ANISOTROPY:a}=e,u=e.normalView||yl,l=i.pow2(),d=t.add(ul).normalize(),c=u.dot(t).clamp(),h=u.dot(ul).clamp(),p=u.dot(d).clamp(),g=ul.dot(d).clamp();let m,f,y=Uh({f0:r,f90:s,dotVH:g});if(yi(o)&&(y=bn.mix(y,n)),yi(a)){const e=Nn.dot(t),r=Nn.dot(ul),s=Nn.dot(d),i=Sn.dot(t),n=Sn.dot(ul),o=Sn.dot(d);m=Hh({alphaT:_n,alphaB:l,dotTV:r,dotBV:n,dotTL:e,dotBL:i,dotNV:h,dotNL:c}),f=qh({alphaT:_n,alphaB:l,dotNH:p,dotTH:s,dotBH:o})}else m=$h({alpha:l,dotNL:c,dotNV:h}),f=Wh({alpha:l,dotNH:p});return y.mul(m).mul(f)})),Xh=Ai((({roughness:e,dotNV:t})=>{const r=$i(-1,-.0275,-.572,.022),s=$i(1,.0425,1.04,-.04),i=e.mul(r).add(s),n=i.x.mul(i.x).min(t.mul(-9.28).exp2()).mul(i.x).add(i.y);return Ii(-1.04,1.04).mul(n).add(i.zw)})).setLayout({name:"DFGApprox",type:"vec2",inputs:[{name:"roughness",type:"float"},{name:"dotNV",type:"vec3"}]}),Yh=Ai((e=>{const{dotNV:t,specularColor:r,specularF90:s,roughness:i}=e,n=Xh({dotNV:t,roughness:i});return r.mul(n.x).add(s.mul(n.y))})),Qh=Ai((({f:e,f90:t,dotVH:r})=>{const s=r.oneMinus().saturate(),i=s.mul(s),n=s.mul(i,i).clamp(0,.9999);return e.sub(Oi(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"}]}),Zh=Ai((({roughness:e,dotNH:t})=>{const r=e.pow2(),s=Bi(1).div(r),i=t.pow2().oneMinus().max(.0078125);return Bi(2).add(s).mul(i.pow(s.mul(.5))).div(2*Math.PI)})).setLayout({name:"D_Charlie",type:"float",inputs:[{name:"roughness",type:"float"},{name:"dotNH",type:"float"}]}),Jh=Ai((({dotNV:e,dotNL:t})=>Bi(1).div(Bi(4).mul(t.add(e).sub(t.mul(e)))))).setLayout({name:"V_Neubelt",type:"float",inputs:[{name:"dotNV",type:"float"},{name:"dotNL",type:"float"}]}),ep=Ai((({lightDirection:e})=>{const t=e.add(ul).normalize(),r=yl.dot(e).clamp(),s=yl.dot(ul).clamp(),i=yl.dot(t).clamp(),n=Zh({roughness:yn,dotNH:i}),o=Jh({dotNV:s,dotNL:r});return fn.mul(n).mul(o)})),tp=Ai((({N:e,V:t,roughness:r})=>{const s=e.dot(t).saturate(),i=Ii(r,s.oneMinus().sqrt());return i.assign(i.mul(.984375).add(.0078125)),i})).setLayout({name:"LTC_Uv",type:"vec2",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"roughness",type:"float"}]}),rp=Ai((({f:e})=>{const t=e.length();return Zo(t.mul(t).add(e.z).div(t.add(1)),0)})).setLayout({name:"LTC_ClippedSphereFormFactor",type:"float",inputs:[{name:"f",type:"vec3"}]}),sp=Ai((({v1:e,v2:t})=>{const r=e.dot(t),s=r.abs().toVar(),i=s.mul(.0145206).add(.4965155).mul(s).add(.8543985).toVar(),n=s.add(4.1616724).mul(s).add(3.417594).toVar(),o=i.div(n),a=r.greaterThan(0).select(o,Zo(r.mul(r).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"}]}),ip=Ai((({N:e,V:t,P:r,mInv:s,p0:i,p1:n,p2:o,p3:a})=>{const u=n.sub(i).toVar(),l=a.sub(i).toVar(),d=u.cross(l),c=Oi().toVar();return Ei(d.dot(r.sub(i)).greaterThanEqual(0),(()=>{const u=t.sub(e.mul(t.dot(e))).normalize(),l=e.cross(u).negate(),d=s.mul(Ki(u,l,e).transpose()).toVar(),h=d.mul(i.sub(r)).normalize().toVar(),p=d.mul(n.sub(r)).normalize().toVar(),g=d.mul(o.sub(r)).normalize().toVar(),m=d.mul(a.sub(r)).normalize().toVar(),f=Oi(0).toVar();f.addAssign(sp({v1:h,v2:p})),f.addAssign(sp({v1:p,v2:g})),f.addAssign(sp({v1:g,v2:m})),f.addAssign(sp({v1:m,v2:h})),c.assign(Oi(rp({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"}]}),np=1/6,op=e=>Wn(np,Wn(e,Wn(e,e.negate().add(3)).sub(3)).add(1)),ap=e=>Wn(np,Wn(e,Wn(e,Wn(3,e).sub(6))).add(4)),up=e=>Wn(np,Wn(e,Wn(e,Wn(-3,e).add(3)).add(3)).add(1)),lp=e=>Wn(np,oa(e,3)),dp=e=>op(e).add(ap(e)),cp=e=>up(e).add(lp(e)),hp=e=>$n(-1,ap(e).div(op(e).add(ap(e)))),pp=e=>$n(1,lp(e).div(up(e).add(lp(e)))),gp=(e,t,r)=>{const s=e.uvNode,i=Wn(s,t.zw).add(.5),n=Co(i),o=Mo(i),a=dp(o.x),u=cp(o.x),l=hp(o.x),d=pp(o.x),c=hp(o.y),h=pp(o.y),p=Ii(n.x.add(l),n.y.add(c)).sub(.5).mul(t.xy),g=Ii(n.x.add(d),n.y.add(c)).sub(.5).mul(t.xy),m=Ii(n.x.add(l),n.y.add(h)).sub(.5).mul(t.xy),f=Ii(n.x.add(d),n.y.add(h)).sub(.5).mul(t.xy),y=dp(o.y).mul($n(a.mul(e.sample(p).level(r)),u.mul(e.sample(g).level(r)))),b=cp(o.y).mul($n(a.mul(e.sample(m).level(r)),u.mul(e.sample(f).level(r))));return y.add(b)},mp=Ai((([e,t=Bi(3)])=>{const r=Ii(e.size(Ui(t))),s=Ii(e.size(Ui(t.add(1)))),i=jn(1,r),n=jn(1,s),o=gp(e,$i(i,r),Co(t)),a=gp(e,$i(n,s),Eo(t));return Mo(t).mix(o,a)})),fp=Ai((([e,t,r,s,i])=>{const n=Oi(fa(t.negate(),wo(e),jn(1,s))),o=Oi(Oo(i[0].xyz),Oo(i[1].xyz),Oo(i[2].xyz));return wo(n).mul(r.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"}]}),yp=Ai((([e,t])=>e.mul(ga(t.mul(2).sub(2),0,1)))).setLayout({name:"applyIorToRoughness",type:"float",inputs:[{name:"roughness",type:"float"},{name:"ior",type:"float"}]}),bp=kc(),xp=kc(),Tp=Ai((([e,t,r],{material:s})=>{const i=(s.side===T?bp:xp).sample(e),n=So(wc.x).mul(yp(t,r));return mp(i,n)})),_p=Ai((([e,t,r])=>(Ei(r.notEqual(0),(()=>{const s=No(t).negate().div(r);return _o(s.negate().mul(e))})),Oi(1)))).setLayout({name:"volumeAttenuation",type:"vec3",inputs:[{name:"transmissionDistance",type:"float"},{name:"attenuationColor",type:"vec3"},{name:"attenuationDistance",type:"float"}]}),vp=Ai((([e,t,r,s,i,n,o,a,u,l,d,c,h,p,g])=>{let m,f;if(g){m=$i().toVar(),f=Oi().toVar();const i=d.sub(1).mul(g.mul(.025)),n=Oi(d.sub(i),d,d.add(i));pc({start:0,end:3},(({i:i})=>{const d=n.element(i),g=fp(e,t,c,d,a),y=o.add(g),b=l.mul(u.mul($i(y,1))),x=Ii(b.xy.div(b.w)).toVar();x.addAssign(1),x.divAssign(2),x.assign(Ii(x.x,x.y.oneMinus()));const T=Tp(x,r,d);m.element(i).assign(T.element(i)),m.a.addAssign(T.a),f.element(i).assign(s.element(i).mul(_p(Oo(g),h,p).element(i)))})),m.a.divAssign(3)}else{const i=fp(e,t,c,d,a),n=o.add(i),g=l.mul(u.mul($i(n,1))),y=Ii(g.xy.div(g.w)).toVar();y.addAssign(1),y.divAssign(2),y.assign(Ii(y.x,y.y.oneMinus())),m=Tp(y,r,d),f=s.mul(_p(Oo(i),h,p))}const y=f.rgb.mul(m.rgb),b=e.dot(t).clamp(),x=Oi(Yh({dotNV:b,specularColor:i,specularF90:n,roughness:r})),T=f.r.add(f.g,f.b).div(3);return $i(x.oneMinus().mul(y),m.a.oneMinus().mul(T).oneMinus())})),Np=Ki(3.2404542,-.969266,.0556434,-1.5371385,1.8760108,-.2040259,-.4985314,.041556,1.0572252),Sp=(e,t)=>e.sub(t).div(e.add(t)).pow2(),Ap=Ai((({outsideIOR:e,eta2:t,cosTheta1:r,thinFilmThickness:s,baseF0:i})=>{const n=pa(e,t,ya(0,.03,s)),o=e.div(n).pow2().mul(r.pow2().oneMinus()).oneMinus();Ei(o.lessThan(0),(()=>Oi(1)));const a=o.sqrt(),u=Sp(n,e),l=Uh({f0:u,f90:1,dotVH:r}),d=l.oneMinus(),c=n.lessThan(e).select(Math.PI,0),h=Bi(Math.PI).sub(c),p=(e=>{const t=e.sqrt();return Oi(1).add(t).div(Oi(1).sub(t))})(i.clamp(0,.9999)),g=Sp(p,n.toVec3()),m=Uh({f0:g,f90:1,dotVH:a}),f=Oi(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(s,a,2),b=Oi(h).add(f),x=l.mul(m).clamp(1e-5,.9999),T=x.sqrt(),_=d.pow2().mul(m).div(Oi(1).sub(x)),v=l.add(_).toVar(),N=_.sub(d).toVar();return pc({start:1,end:2,condition:"<=",name:"m"},(({m:e})=>{N.mulAssign(T);const t=((e,t)=>{const r=e.mul(2*Math.PI*1e-9),s=Oi(54856e-17,44201e-17,52481e-17),i=Oi(1681e3,1795300,2208400),n=Oi(43278e5,93046e5,66121e5),o=Bi(9747e-17*Math.sqrt(2*Math.PI*45282e5)).mul(r.mul(2239900).add(t.x).cos()).mul(r.pow2().mul(-45282e5).exp());let a=s.mul(n.mul(2*Math.PI).sqrt()).mul(i.mul(r).add(t).cos()).mul(r.pow2().negate().mul(n).exp());return a=Oi(a.x.add(o),a.y,a.z).div(1.0685e-7),Np.mul(a)})(Bi(e).mul(y),Bi(e).mul(b)).mul(2);v.addAssign(N.mul(t))})),v.max(Oi(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"}]}),Rp=Ai((({normal:e,viewDir:t,roughness:r})=>{const s=e.dot(t).saturate(),i=r.pow2(),n=Ra(r.lessThan(.25),Bi(-339.2).mul(i).add(Bi(161.4).mul(r)).sub(25.9),Bi(-8.48).mul(i).add(Bi(14.3).mul(r)).sub(9.95)),o=Ra(r.lessThan(.25),Bi(44).mul(i).sub(Bi(23.7).mul(r)).add(3.26),Bi(1.97).mul(i).sub(Bi(3.27).mul(r)).add(.72));return Ra(r.lessThan(.25),0,Bi(.1).mul(r).sub(.025)).add(n.mul(s).add(o).exp()).mul(1/Math.PI).saturate()})),Cp=Oi(.04),Ep=Bi(1);class wp extends Eh{constructor(e=!1,t=!1,r=!1,s=!1,i=!1,n=!1){super(),this.clearcoat=e,this.sheen=t,this.iridescence=r,this.anisotropy=s,this.transmission=i,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=Oi().toVar("clearcoatRadiance"),this.clearcoatSpecularDirect=Oi().toVar("clearcoatSpecularDirect"),this.clearcoatSpecularIndirect=Oi().toVar("clearcoatSpecularIndirect")),!0===this.sheen&&(this.sheenSpecularDirect=Oi().toVar("sheenSpecularDirect"),this.sheenSpecularIndirect=Oi().toVar("sheenSpecularIndirect")),!0===this.iridescence){const e=yl.dot(ul).clamp();this.iridescenceFresnel=Ap({outsideIOR:Bi(1),eta2:xn,cosTheta1:e,thinFilmThickness:Tn,baseF0:An}),this.iridescenceF0=Qh({f:this.iridescenceFresnel,f90:1,dotVH:e})}if(!0===this.transmission){const t=nl,r=Lu.sub(nl).normalize(),s=bl;e.backdrop=vp(s,r,hn,dn,An,Rn,t,ju,Pu,Uu,Un,Pn,Dn,In,this.dispersion?Ln:null),e.backdropAlpha=Fn,dn.a.mulAssign(pa(1,e.backdrop.a,Fn))}}computeMultiscattering(e,t,r){const s=yl.dot(ul).clamp(),i=Xh({roughness:hn,dotNV:s}),n=(this.iridescenceF0?bn.mix(An,this.iridescenceF0):An).mul(i.x).add(r.mul(i.y)),o=i.x.add(i.y).oneMinus(),a=An.add(An.oneMinus().mul(.047619)),u=n.mul(a).div(o.mul(a).oneMinus());e.addAssign(n),t.addAssign(u.mul(o))}direct({lightDirection:e,lightColor:t,reflectedLight:r}){const s=yl.dot(e).clamp().mul(t);if(!0===this.sheen&&this.sheenSpecularDirect.addAssign(s.mul(ep({lightDirection:e}))),!0===this.clearcoat){const r=xl.dot(e).clamp().mul(t);this.clearcoatSpecularDirect.addAssign(r.mul(Kh({lightDirection:e,f0:Cp,f90:Ep,roughness:mn,normalView:xl})))}r.directDiffuse.addAssign(s.mul(Fh({diffuseColor:dn.rgb}))),r.directSpecular.addAssign(s.mul(Kh({lightDirection:e,f0:An,f90:1,roughness:hn,iridescence:this.iridescence,f:this.iridescenceFresnel,USE_IRIDESCENCE:this.iridescence,USE_ANISOTROPY:this.anisotropy})))}directRectArea({lightColor:e,lightPosition:t,halfWidth:r,halfHeight:s,reflectedLight:i,ltc_1:n,ltc_2:o}){const a=t.add(r).sub(s),u=t.sub(r).sub(s),l=t.sub(r).add(s),d=t.add(r).add(s),c=yl,h=ul,p=al.toVar(),g=tp({N:c,V:h,roughness:hn}),m=n.sample(g).toVar(),f=o.sample(g).toVar(),y=Ki(Oi(m.x,0,m.y),Oi(0,1,0),Oi(m.z,0,m.w)).toVar(),b=An.mul(f.x).add(An.oneMinus().mul(f.y)).toVar();i.directSpecular.addAssign(e.mul(b).mul(ip({N:c,V:h,P:p,mInv:y,p0:a,p1:u,p2:l,p3:d}))),i.directDiffuse.addAssign(e.mul(dn).mul(ip({N:c,V:h,P:p,mInv:Ki(1,0,0,0,1,0,0,0,1),p0:a,p1:u,p2:l,p3:d})))}indirect(e,t,r){this.indirectDiffuse(e,t,r),this.indirectSpecular(e,t,r),this.ambientOcclusion(e,t,r)}indirectDiffuse({irradiance:e,reflectedLight:t}){t.indirectDiffuse.addAssign(e.mul(Fh({diffuseColor:dn})))}indirectSpecular({radiance:e,iblIrradiance:t,reflectedLight:r}){if(!0===this.sheen&&this.sheenSpecularIndirect.addAssign(t.mul(fn,Rp({normal:yl,viewDir:ul,roughness:yn}))),!0===this.clearcoat){const e=xl.dot(ul).clamp(),t=Yh({dotNV:e,specularColor:Cp,specularF90:Ep,roughness:mn});this.clearcoatSpecularIndirect.addAssign(this.clearcoatRadiance.mul(t))}const s=Oi().toVar("singleScattering"),i=Oi().toVar("multiScattering"),n=t.mul(1/Math.PI);this.computeMultiscattering(s,i,Rn);const o=s.add(i),a=dn.mul(o.r.max(o.g).max(o.b).oneMinus());r.indirectSpecular.addAssign(e.mul(s)),r.indirectSpecular.addAssign(i.mul(n)),r.indirectDiffuse.addAssign(a.mul(n))}ambientOcclusion({ambientOcclusion:e,reflectedLight:t}){const r=yl.dot(ul).clamp().add(e),s=hn.mul(-16).oneMinus().negate().exp2(),i=e.sub(r.pow(s).oneMinus()).clamp();!0===this.clearcoat&&this.clearcoatSpecularIndirect.mulAssign(e),!0===this.sheen&&this.sheenSpecularIndirect.mulAssign(e),t.indirectDiffuse.mulAssign(e),t.indirectSpecular.mulAssign(i)}finish(e){const{outgoingLight:t}=e;if(!0===this.clearcoat){const e=xl.dot(ul).clamp(),r=Uh({dotVH:e,f0:Cp,f90:Ep}),s=t.mul(gn.mul(r).oneMinus()).add(this.clearcoatSpecularDirect.add(this.clearcoatSpecularIndirect).mul(gn));t.assign(s)}if(!0===this.sheen){const e=fn.r.max(fn.g).max(fn.b).mul(.157).oneMinus(),r=t.mul(e).add(this.sheenSpecularDirect,this.sheenSpecularIndirect);t.assign(r)}}}const Mp=Bi(1),Bp=Bi(-2),Up=Bi(.8),Fp=Bi(-1),Pp=Bi(.4),Ip=Bi(2),Dp=Bi(.305),Lp=Bi(3),Vp=Bi(.21),Op=Bi(4),Gp=Bi(4),kp=Bi(16),zp=Ai((([e])=>{const t=Oi(Lo(e)).toVar(),r=Bi(-1).toVar();return Ei(t.x.greaterThan(t.z),(()=>{Ei(t.x.greaterThan(t.y),(()=>{r.assign(Ra(e.x.greaterThan(0),0,3))})).Else((()=>{r.assign(Ra(e.y.greaterThan(0),1,4))}))})).Else((()=>{Ei(t.z.greaterThan(t.y),(()=>{r.assign(Ra(e.z.greaterThan(0),2,5))})).Else((()=>{r.assign(Ra(e.y.greaterThan(0),1,4))}))})),r})).setLayout({name:"getFace",type:"float",inputs:[{name:"direction",type:"vec3"}]}),$p=Ai((([e,t])=>{const r=Ii().toVar();return Ei(t.equal(0),(()=>{r.assign(Ii(e.z,e.y).div(Lo(e.x)))})).ElseIf(t.equal(1),(()=>{r.assign(Ii(e.x.negate(),e.z.negate()).div(Lo(e.y)))})).ElseIf(t.equal(2),(()=>{r.assign(Ii(e.x.negate(),e.y).div(Lo(e.z)))})).ElseIf(t.equal(3),(()=>{r.assign(Ii(e.z.negate(),e.y).div(Lo(e.x)))})).ElseIf(t.equal(4),(()=>{r.assign(Ii(e.x.negate(),e.z).div(Lo(e.y)))})).Else((()=>{r.assign(Ii(e.x,e.y).div(Lo(e.z)))})),Wn(.5,r.add(1))})).setLayout({name:"getUV",type:"vec2",inputs:[{name:"direction",type:"vec3"},{name:"face",type:"float"}]}),Hp=Ai((([e])=>{const t=Bi(0).toVar();return Ei(e.greaterThanEqual(Up),(()=>{t.assign(Mp.sub(e).mul(Fp.sub(Bp)).div(Mp.sub(Up)).add(Bp))})).ElseIf(e.greaterThanEqual(Pp),(()=>{t.assign(Up.sub(e).mul(Ip.sub(Fp)).div(Up.sub(Pp)).add(Fp))})).ElseIf(e.greaterThanEqual(Dp),(()=>{t.assign(Pp.sub(e).mul(Lp.sub(Ip)).div(Pp.sub(Dp)).add(Ip))})).ElseIf(e.greaterThanEqual(Vp),(()=>{t.assign(Dp.sub(e).mul(Op.sub(Lp)).div(Dp.sub(Vp)).add(Lp))})).Else((()=>{t.assign(Bi(-2).mul(So(Wn(1.16,e))))})),t})).setLayout({name:"roughnessToMip",type:"float",inputs:[{name:"roughness",type:"float"}]}),Wp=Ai((([e,t])=>{const r=e.toVar();r.assign(Wn(2,r).sub(1));const s=Oi(r,1).toVar();return Ei(t.equal(0),(()=>{s.assign(s.zyx)})).ElseIf(t.equal(1),(()=>{s.assign(s.xzy),s.xz.mulAssign(-1)})).ElseIf(t.equal(2),(()=>{s.x.mulAssign(-1)})).ElseIf(t.equal(3),(()=>{s.assign(s.zyx),s.xz.mulAssign(-1)})).ElseIf(t.equal(4),(()=>{s.assign(s.xzy),s.xy.mulAssign(-1)})).ElseIf(t.equal(5),(()=>{s.z.mulAssign(-1)})),s})).setLayout({name:"getDirection",type:"vec3",inputs:[{name:"uv",type:"vec2"},{name:"face",type:"float"}]}),jp=Ai((([e,t,r,s,i,n])=>{const o=Bi(r),a=Oi(t),u=ga(Hp(o),Bp,n),l=Mo(u),d=Co(u),c=Oi(qp(e,a,d,s,i,n)).toVar();return Ei(l.notEqual(0),(()=>{const t=Oi(qp(e,a,d.add(1),s,i,n)).toVar();c.assign(pa(c,t,l))})),c})),qp=Ai((([e,t,r,s,i,n])=>{const o=Bi(r).toVar(),a=Oi(t),u=Bi(zp(a)).toVar(),l=Bi(Zo(Gp.sub(o),0)).toVar();o.assign(Zo(o,Gp));const d=Bi(vo(o)).toVar(),c=Ii($p(a,u).mul(d.sub(2)).add(1)).toVar();return Ei(u.greaterThan(2),(()=>{c.y.addAssign(d),u.subAssign(3)})),c.x.addAssign(u.mul(d)),c.x.addAssign(l.mul(Wn(3,kp))),c.y.addAssign(Wn(4,vo(n).sub(d))),c.x.mulAssign(s),c.y.mulAssign(i),e.sample(c).grad(Ii(),Ii())})),Kp=Ai((({envMap:e,mipInt:t,outputDirection:r,theta:s,axis:i,CUBEUV_TEXEL_WIDTH:n,CUBEUV_TEXEL_HEIGHT:o,CUBEUV_MAX_MIP:a})=>{const u=Uo(s),l=r.mul(u).add(i.cross(r).mul(Bo(s))).add(i.mul(i.dot(r).mul(u.oneMinus())));return qp(e,l,t,n,o,a)})),Xp=Ai((({n:e,latitudinal:t,poleAxis:r,outputDirection:s,weights:i,samples:n,dTheta:o,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c})=>{const h=Oi(Ra(t,r,na(r,s))).toVar();Ei(yo(h.equals(Oi(0))),(()=>{h.assign(Oi(s.z,0,s.x.negate()))})),h.assign(wo(h));const p=Oi().toVar();return p.addAssign(i.element(Ui(0)).mul(Kp({theta:0,axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c}))),pc({start:Ui(1),end:e},(({i:e})=>{Ei(e.greaterThanEqual(n),(()=>{gc()}));const t=Bi(o.mul(Bi(e))).toVar();p.addAssign(i.element(e).mul(Kp({theta:t.mul(-1),axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c}))),p.addAssign(i.element(e).mul(Kp({theta:t,axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c})))})),$i(p,1)}));let Yp=null;const Qp=new WeakMap;function Zp(e){let t=Qp.get(e);if((void 0!==t?t.pmremVersion:-1)!==e.pmremVersion){const r=e.image;if(e.isCubeTexture){if(!function(e){if(null==e)return!1;let t=0;const r=6;for(let s=0;s0}(r))return null;t=Yp.fromEquirectangular(e,t)}t.pmremVersion=e.pmremVersion,Qp.set(e,t)}return t.texture}class Jp extends Ls{static get type(){return"PMREMNode"}constructor(e,t=null,r=null){super("vec3"),this._value=e,this._pmrem=null,this.uvNode=t,this.levelNode=r,this._generator=null;const s=new J;s.isRenderTargetTexture=!0,this._texture=Eu(s),this._width=on(0),this._height=on(0),this._maxMip=on(0),this.updateBeforeType=Rs.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,r=1/e;return{texelWidth:1/(3*Math.max(Math.pow(2,t),112)),texelHeight:r,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,r=this._value;t!==r.pmremVersion&&(e=!0===r.isPMREMTexture?r:Zp(r),null!==e&&(this._pmrem=e,this.updateFromTexture(e)))}setup(e){null===Yp&&(Yp=e.createPMREMGenerator()),this.updateBefore(e);let t=this.uvNode;null===t&&e.context.getUV&&(t=e.context.getUV(this));const r=this.value;e.renderer.coordinateSystem===u&&!0!==r.isPMREMTexture&&!0===r.isRenderTargetTexture&&(t=Oi(t.x.negate(),t.yz)),t=Oi(t.x,t.y.negate(),t.z);let s=this.levelNode;return null===s&&e.context.getTextureLevel&&(s=e.context.getTextureLevel(this)),jp(this._texture,t,s,this._width,this._height,this._maxMip)}}const eg=Ni(Jp),tg=new WeakMap;class rg extends Tc{static get type(){return"EnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){const{material:t}=e;let r=this.envNode;if(r.isTextureNode||r.isMaterialReferenceNode){const e=r.isTextureNode?r.value:t[r.property];let s=tg.get(e);void 0===s&&(s=eg(e),tg.set(e,s)),r=s}const s=t.envMap?Dl("envMapIntensity","float",e.material):Dl("environmentIntensity","float",e.scene),i=!0===t.useAnisotropy||t.anisotropy>0?td:yl,n=r.context(sg(hn,i)).mul(s),o=r.context(ig(bl)).mul(Math.PI).mul(s),a=lu(n),u=lu(o);e.context.radiance.addAssign(a),e.context.iblIrradiance.addAssign(u);const l=e.context.lightingModel.clearcoatRadiance;if(l){const e=r.context(sg(mn,xl)).mul(s),t=lu(e);l.addAssign(t)}}}const sg=(e,t)=>{let r=null;return{getUV:()=>(null===r&&(r=ul.negate().reflect(t),r=e.mul(e).mix(r,t).normalize(),r=r.transformDirection(Pu)),r),getTextureLevel:()=>e}},ig=e=>({getUV:()=>e,getTextureLevel:()=>Bi(1)}),ng=new ee;class og extends nh{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(ng),this.setValues(e)}setupEnvironment(e){let t=super.setupEnvironment(e);return null===t&&e.environmentNode&&(t=e.environmentNode),t?new rg(t):null}setupLightingModel(){return new wp}setupSpecular(){const e=pa(Oi(.04),dn.rgb,pn);An.assign(e),Rn.assign(1)}setupVariants(){const e=this.metalnessNode?Bi(this.metalnessNode):vd;pn.assign(e);let t=this.roughnessNode?Bi(this.roughnessNode):_d;t=zh({roughness:t}),hn.assign(t),this.setupSpecular(),dn.assign($i(dn.rgb.mul(e.oneMinus()),dn.a))}copy(e){return this.emissiveNode=e.emissiveNode,this.metalnessNode=e.metalnessNode,this.roughnessNode=e.roughnessNode,super.copy(e)}}const ag=new te;class ug extends og{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(ag),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?Bi(this.iorNode):Dd;Un.assign(e),An.assign(pa(Qo(aa(Un.sub(1).div(Un.add(1))).mul(bd),Oi(1)).mul(yd),dn.rgb,pn)),Rn.assign(pa(yd,1,pn))}setupLightingModel(){return new wp(this.useClearcoat,this.useSheen,this.useIridescence,this.useAnisotropy,this.useTransmission,this.useDispersion)}setupVariants(e){if(super.setupVariants(e),this.useClearcoat){const e=this.clearcoatNode?Bi(this.clearcoatNode):Sd,t=this.clearcoatRoughnessNode?Bi(this.clearcoatRoughnessNode):Ad;gn.assign(e),mn.assign(zh({roughness:t}))}if(this.useSheen){const e=this.sheenNode?Oi(this.sheenNode):Ed,t=this.sheenRoughnessNode?Bi(this.sheenRoughnessNode):wd;fn.assign(e),yn.assign(t)}if(this.useIridescence){const e=this.iridescenceNode?Bi(this.iridescenceNode):Bd,t=this.iridescenceIORNode?Bi(this.iridescenceIORNode):Ud,r=this.iridescenceThicknessNode?Bi(this.iridescenceThicknessNode):Fd;bn.assign(e),xn.assign(t),Tn.assign(r)}if(this.useAnisotropy){const e=(this.anisotropyNode?Ii(this.anisotropyNode):Md).toVar();vn.assign(e.length()),Ei(vn.equal(0),(()=>{e.assign(Ii(1,0))})).Else((()=>{e.divAssign(Ii(vn)),vn.assign(vn.saturate())})),_n.assign(vn.pow2().mix(hn.pow2(),1)),Nn.assign(Jl[0].mul(e.x).add(Jl[1].mul(e.y))),Sn.assign(Jl[1].mul(e.x).sub(Jl[0].mul(e.y)))}if(this.useTransmission){const e=this.transmissionNode?Bi(this.transmissionNode):Pd,t=this.thicknessNode?Bi(this.thicknessNode):Id,r=this.attenuationDistanceNode?Bi(this.attenuationDistanceNode):Ld,s=this.attenuationColorNode?Oi(this.attenuationColorNode):Vd;if(Fn.assign(e),Pn.assign(t),In.assign(r),Dn.assign(s),this.useDispersion){const e=this.dispersionNode?Bi(this.dispersionNode):Wd;Ln.assign(e)}}}setupClearcoatNormal(){return this.clearcoatNormalNode?Oi(this.clearcoatNormalNode):Rd}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 lg extends wp{constructor(e=!1,t=!1,r=!1,s=!1,i=!1,n=!1,o=!1){super(e,t,r,s,i,n),this.useSSS=o}direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i){if(!0===this.useSSS){const s=i.material,{thicknessColorNode:n,thicknessDistortionNode:o,thicknessAmbientNode:a,thicknessAttenuationNode:u,thicknessPowerNode:l,thicknessScaleNode:d}=s,c=e.add(yl.mul(o)).normalize(),h=Bi(ul.dot(c.negate()).saturate().pow(l).mul(d)),p=Oi(h.add(a).mul(n));r.directDiffuse.addAssign(p.mul(u.mul(t)))}super.direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i)}}class dg extends ug{static get type(){return"MeshSSSNodeMaterial"}constructor(e){super(e),this.thicknessColorNode=null,this.thicknessDistortionNode=Bi(.1),this.thicknessAmbientNode=Bi(0),this.thicknessAttenuationNode=Bi(.1),this.thicknessPowerNode=Bi(2),this.thicknessScaleNode=Bi(10)}get useSSS(){return null!==this.thicknessColorNode}setupLightingModel(){return new lg(this.useClearcoat,this.useSheen,this.useIridescence,this.useAnisotropy,this.useTransmission,this.useDispersion,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 cg=Ai((({normal:e,lightDirection:t,builder:r})=>{const s=e.dot(t),i=Ii(s.mul(.5).add(.5),0);if(r.material.gradientMap){const e=Ol("gradientMap","texture").context({getUV:()=>i});return Oi(e.r)}{const e=i.fwidth().mul(.5);return pa(Oi(.7),Oi(1),ya(Bi(.7).sub(e.x),Bi(.7).add(e.x),i.x))}}));class hg extends Eh{direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i){const n=cg({normal:hl,lightDirection:e,builder:i}).mul(t);r.directDiffuse.addAssign(n.mul(Fh({diffuseColor:dn.rgb})))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:r}){r.indirectDiffuse.addAssign(t.mul(Fh({diffuseColor:dn}))),r.indirectDiffuse.mulAssign(e)}}const pg=new re;class gg extends nh{static get type(){return"MeshToonNodeMaterial"}constructor(e){super(),this.isMeshToonNodeMaterial=!0,this.lights=!0,this.setDefaultValues(pg),this.setValues(e)}setupLightingModel(){return new hg}}class mg extends Ls{static get type(){return"MatcapUVNode"}constructor(){super("vec2")}setup(){const e=Oi(ul.z,0,ul.x.negate()).normalize(),t=ul.cross(e);return Ii(e.dot(yl),t.dot(yl)).mul(.495).add(.5)}}const fg=Si(mg),yg=new se;class bg extends nh{static get type(){return"MeshMatcapNodeMaterial"}constructor(e){super(),this.isMeshMatcapNodeMaterial=!0,this.setDefaultValues(yg),this.setValues(e)}setupVariants(e){const t=fg;let r;r=e.material.matcap?Ol("matcap","texture").context({getUV:()=>t}):Oi(pa(.2,.8,t.y)),dn.rgb.mulAssign(r.rgb)}}class xg extends Ls{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:r}=this;if("vec2"===this.getNodeType(e)){const e=t.cos(),s=t.sin();return qi(e,s,s.negate(),e).mul(r)}{const e=t,s=Xi($i(1,0,0,0),$i(0,Uo(e.x),Bo(e.x).negate(),0),$i(0,Bo(e.x),Uo(e.x),0),$i(0,0,0,1)),i=Xi($i(Uo(e.y),0,Bo(e.y),0),$i(0,1,0,0),$i(Bo(e.y).negate(),0,Uo(e.y),0),$i(0,0,0,1)),n=Xi($i(Uo(e.z),Bo(e.z).negate(),0,0),$i(Bo(e.z),Uo(e.z),0,0),$i(0,0,1,0),$i(0,0,0,1));return s.mul(i).mul(n).mul($i(r,1)).xyz}}}const Tg=Ni(xg),_g=new ie;class vg extends nh{static get type(){return"SpriteNodeMaterial"}constructor(e){super(),this.isSpriteNodeMaterial=!0,this._useSizeAttenuation=!0,this.positionNode=null,this.rotationNode=null,this.scaleNode=null,this.setDefaultValues(_g),this.setValues(e)}setupPositionView(e){const{object:t,camera:r}=e,s=this.sizeAttenuation,{positionNode:i,rotationNode:n,scaleNode:o}=this,a=Zu.mul(Oi(i||0));let u=Ii(ju[0].xyz.length(),ju[1].xyz.length());if(null!==o&&(u=u.mul(Bi(o))),!1===s)if(r.isPerspectiveCamera)u=u.mul(a.z.negate());else{const e=Bi(2).div(Uu.element(1).element(1));u=u.mul(e.mul(2))}let l=rl.xy;if(t.center&&!0===t.center.isVector2){const e=((e,t,r)=>Ti(new Xa(e,t,r)))("center","vec2",t);l=l.sub(e.sub(.5))}l=l.mul(u);const d=Bi(n||Cd),c=Tg(l,d);return $i(a.xy.add(c),a.zw)}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)}}const Ng=new ne;class Sg extends vg{static get type(){return"PointsNodeMaterial"}constructor(e){super(),this.sizeNode=null,this.isPointsNodeMaterial=!0,this.setDefaultValues(Ng),this.setValues(e)}setupPositionView(){const{positionNode:e}=this;return Zu.mul(Oi(e||sl)).xyz}setupVertex(e){const t=super.setupVertex(e);if(!0!==e.material.isNodeMaterial)return t;const{rotationNode:r,scaleNode:s,sizeNode:i}=this,n=rl.xy.toVar(),o=Bc.z.div(Bc.w);if(r&&r.isNode){const e=Bi(r);n.assign(Tg(n,e))}let a=null!==i?Ii(i):Hd;return!0===this.sizeAttenuation&&(a=a.mul(a.div(al.z.negate()))),s&&s.isNode&&(a=a.mul(Ii(s))),n.mulAssign(a.mul(2)),n.assign(n.div(Bc.z)),n.y.assign(n.y.mul(o)),n.assign(n.mul(t.w)),t.addAssign($i(n,0,0)),t}get alphaToCoverage(){return this._useAlphaToCoverage}set alphaToCoverage(e){this._useAlphaToCoverage!==e&&(this._useAlphaToCoverage=e,this.needsUpdate=!0)}}class Ag extends Eh{constructor(){super(),this.shadowNode=Bi(1).toVar("shadowMask")}direct({shadowMask:e}){this.shadowNode.mulAssign(e)}finish(e){dn.a.mulAssign(this.shadowNode.oneMinus()),e.outgoingLight.rgb.assign(dn.rgb)}}const Rg=new oe;class Cg extends nh{static get type(){return"ShadowNodeMaterial"}constructor(e){super(),this.isShadowNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Rg),this.setValues(e)}setupLightingModel(){return new Ag}}const Eg=Ai((({texture:e,uv:t})=>{const r=1e-4,s=Oi().toVar();return Ei(t.x.lessThan(r),(()=>{s.assign(Oi(1,0,0))})).ElseIf(t.y.lessThan(r),(()=>{s.assign(Oi(0,1,0))})).ElseIf(t.z.lessThan(r),(()=>{s.assign(Oi(0,0,1))})).ElseIf(t.x.greaterThan(.9999),(()=>{s.assign(Oi(-1,0,0))})).ElseIf(t.y.greaterThan(.9999),(()=>{s.assign(Oi(0,-1,0))})).ElseIf(t.z.greaterThan(.9999),(()=>{s.assign(Oi(0,0,-1))})).Else((()=>{const r=.01,i=e.sample(t.add(Oi(-.01,0,0))).r.sub(e.sample(t.add(Oi(r,0,0))).r),n=e.sample(t.add(Oi(0,-.01,0))).r.sub(e.sample(t.add(Oi(0,r,0))).r),o=e.sample(t.add(Oi(0,0,-.01))).r.sub(e.sample(t.add(Oi(0,0,r))).r);s.assign(Oi(i,n,o))})),s.normalize()}));class wg extends Cu{static get type(){return"Texture3DNode"}constructor(e,t=null,r=null){super(e,t,r),this.isTexture3DNode=!0}getInputType(){return"texture3D"}getDefaultUV(){return Oi(.5,.5,.5)}setUpdateMatrix(){}setupUV(e,t){const r=this.value;return!e.isFlipY()||!0!==r.isRenderTargetTexture&&!0!==r.isFramebufferTexture||(t=this.sampler?t.flipY():t.setY(Ui(Su(this,this.levelNode).y).sub(t.y).sub(1))),t}generateUV(e,t){return t.build(e,"vec3")}normal(e){return Eg({texture:this,uv:e})}}const Mg=Ni(wg);class Bg extends nh{static get type(){return"VolumeNodeMaterial"}constructor(t){super(),this.isVolumeNodeMaterial=!0,this.base=new e(16777215),this.map=null,this.steps=100,this.testNode=null,this.setValues(t)}setup(e){const t=Mg(this.map,null,0),r=Ai((({orig:e,dir:t})=>{const r=Oi(-.5),s=Oi(.5),i=t.reciprocal(),n=r.sub(e).mul(i),o=s.sub(e).mul(i),a=Qo(n,o),u=Zo(n,o),l=Zo(a.x,Zo(a.y,a.z)),d=Qo(u.x,Qo(u.y,u.z));return Ii(l,d)}));this.fragmentNode=Ai((()=>{const e=La(Oi(Qu.mul($i(Lu,1)))),s=La(rl.sub(e)).normalize(),i=Ii(r({orig:e,dir:s})).toVar();i.x.greaterThan(i.y).discard(),i.assign(Ii(Zo(i.x,0),i.y));const n=Oi(e.add(i.x.mul(s))).toVar(),o=Oi(s.abs().reciprocal()).toVar(),a=Bi(Qo(o.x,Qo(o.y,o.z))).toVar("delta");a.divAssign(Ol("steps","float"));const u=$i(Ol("base","color"),0).toVar();return pc({type:"float",start:i.x,end:i.y,update:"+= delta"},(()=>{const e=un("float","d").assign(t.sample(n.add(.5)).r);null!==this.testNode?this.testNode({map:t,mapValue:e,probe:n,finalColor:u}).append():(u.a.assign(1),gc()),n.addAssign(s.mul(a))})),u.a.equal(0).discard(),$i(u)}))(),super.setup(e)}}class Ug{constructor(e,t){this.nodes=e,this.info=t,this._context=self,this._animationLoop=null,this._requestId=null}start(){const e=(t,r)=>{this._requestId=this._context.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,r)};e()}stop(){this._context.cancelAnimationFrame(this._requestId),this._requestId=null}setAnimationLoop(e){this._animationLoop=e}setContext(e){this._context=e}dispose(){this.stop()}}class Fg{constructor(){this.weakMap=new WeakMap}get(e){let t=this.weakMap;for(let r=0;r{this.dispose()},this.material.addEventListener("dispose",this.onMaterialDispose)}updateClipping(e){this.clippingContext=e}get clippingNeedsUpdate(){return null!==this.clippingContext&&this.clippingContext.cacheKey!==this.clippingContextCacheKey&&(this.clippingContextCacheKey=this.clippingContext.cacheKey,!0)}get hardwareClippingPlanes(){return!0===this.material.hardwareClipping?this.clippingContext.unionClippingCount: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)}getIndirect(){return this._geometries.getIndirect(this)}getChainArray(){return[this.object,this.material,this.context,this.lightsNode]}setGeometry(e){this.geometry=e,this.attributes=null}getAttributes(){if(null!==this.attributes)return this.attributes;const e=this.getNodeBuilderState().nodeAttributes,t=this.geometry,r=[],s=new Set;for(const i of e){const e=i.node&&i.node.attribute?i.node.attribute:t.getAttribute(i.name);if(void 0===e)continue;r.push(e);const n=e.isInterleavedBufferAttribute?e.data:e;s.add(n)}return this.attributes=r,this.vertexBuffers=Array.from(s.values()),r}getVertexBuffers(){return null===this.vertexBuffers&&this.getAttributes(),this.vertexBuffers}getDrawParameters(){const{object:e,material:t,geometry:r,group:s,drawRange:i}=this,n=this.drawParams||(this.drawParams={vertexCount:0,firstVertex:0,instanceCount:0,firstInstance:0}),o=this.getIndex(),a=null!==o,u=r.isInstancedBufferGeometry?r.instanceCount:e.count>1?e.count:1;if(0===u)return null;if(n.instanceCount=u,!0===e.isBatchedMesh)return n;let l=1;!0!==t.wireframe||e.isPoints||e.isLineSegments||e.isLine||e.isLineLoop||(l=2);let d=i.start*l,c=(i.start+i.count)*l;null!==s&&(d=Math.max(d,s.start*l),c=Math.min(c,(s.start+s.count)*l));const h=r.attributes.position;let p=1/0;a?p=o.count:null!=h&&(p=h.count),d=Math.max(d,0),c=Math.min(c,p);const g=c-d;return g<0||g===1/0?null:(n.vertexCount=g,n.firstVertex=d,n)}getGeometryCacheKey(){const{geometry:e}=this;let t="";for(const r of Object.keys(e.attributes).sort()){const s=e.attributes[r];t+=r+",",s.data&&(t+=s.data.stride+","),s.offset&&(t+=s.offset+","),s.itemSize&&(t+=s.itemSize+","),s.normalized&&(t+="n,")}for(const r of Object.keys(e.morphAttributes).sort()){const s=e.morphAttributes[r];t+="morph-"+r+",";for(let e=0,r=s.length;e1&&(r+=e.uuid+","),r+=e.receiveShadow+",",ls(r)}get needsGeometryUpdate(){return this.geometry.id!==this.object.geometry.id}get needsUpdate(){return this.initialNodesCacheKey!==this.getDynamicCacheKey()||this.clippingNeedsUpdate}getDynamicCacheKey(){let e=0;return!0!==this.material.isShadowPassMaterial&&(e=this._nodes.getCacheKey(this.scene,this.lightsNode)),this.object.receiveShadow&&(e+=1),e}getCacheKey(){return this.getMaterialCacheKey()+this.getDynamicCacheKey()}dispose(){this.material.removeEventListener("dispose",this.onMaterialDispose),this.onDispose()}}const Dg=[];class Lg{constructor(e,t,r,s,i,n){this.renderer=e,this.nodes=t,this.geometries=r,this.pipelines=s,this.bindings=i,this.info=n,this.chainMaps={}}get(e,t,r,s,i,n,o,a){const u=this.getChainMap(a);Dg[0]=e,Dg[1]=t,Dg[2]=n,Dg[3]=i;let l=u.get(Dg);return void 0===l?(l=this.createRenderObject(this.nodes,this.geometries,this.renderer,e,t,r,s,i,n,o,a),u.set(Dg,l)):(l.updateClipping(o),l.needsGeometryUpdate&&l.setGeometry(e.geometry),(l.version!==t.version||l.needsUpdate)&&(l.initialCacheKey!==l.getCacheKey()?(l.dispose(),l=this.get(e,t,r,s,i,n,o,a)):l.version=t.version)),Dg.length=0,l}getChainMap(e="default"){return this.chainMaps[e]||(this.chainMaps[e]=new Fg)}dispose(){this.chainMaps={}}createRenderObject(e,t,r,s,i,n,o,a,u,l,d){const c=this.getChainMap(d),h=new Ig(e,t,r,s,i,n,o,a,u,l);return h.onDispose=()=>{this.pipelines.delete(h),this.bindings.delete(h),this.nodes.delete(h),c.delete(h.getChainArray())},h}}class Vg{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=null;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 Og=1,Gg=2,kg=3,zg=4,$g=16;class Hg extends Vg{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 r=this.get(e);if(void 0===r.version)t===Og?this.backend.createAttribute(e):t===Gg?this.backend.createIndexAttribute(e):t===kg?this.backend.createStorageAttribute(e):t===zg&&this.backend.createIndirectStorageAttribute(e),r.version=this._getBufferAttribute(e).version;else{const t=this._getBufferAttribute(e);(r.version=0;--t)if(e[t]>=65535)return!0;return!1}(t)?ae:ue)(t,1);return i.version=Wg(e),i}class qg extends Vg{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 r=()=>{this.info.memory.geometries--;const s=t.index,i=e.getAttributes();null!==s&&this.attributes.delete(s);for(const e of i)this.attributes.delete(e);const n=this.wireframes.get(t);void 0!==n&&this.attributes.delete(n),t.removeEventListener("dispose",r)};t.addEventListener("dispose",r)}updateAttributes(e){const t=e.getAttributes();for(const e of t)e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute?this.updateAttribute(e,kg):this.updateAttribute(e,Og);const r=this.getIndex(e);null!==r&&this.updateAttribute(r,Gg);const s=e.geometry.indirect;null!==s&&this.updateAttribute(s,zg)}updateAttribute(e,t){const r=this.info.render.calls;e.isInterleavedBufferAttribute?void 0===this.attributeCall.get(e)?(this.attributes.update(e,t),this.attributeCall.set(e,r)):this.attributeCall.get(e.data)!==r&&(this.attributes.update(e,t),this.attributeCall.set(e.data,r),this.attributeCall.set(e,r)):this.attributeCall.get(e)!==r&&(this.attributes.update(e,t),this.attributeCall.set(e,r))}getIndirect(e){return e.geometry.indirect}getIndex(e){const{geometry:t,material:r}=e;let s=t.index;if(!0===r.wireframe){const e=this.wireframes;let r=e.get(t);void 0===r?(r=jg(t),e.set(t,r)):r.version!==Wg(t)&&(this.attributes.delete(r),r=jg(t),e.set(t,r)),s=r}return s}}class Kg{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,r){this.render.drawCalls++,e.isMesh||e.isSprite?this.render.triangles+=r*(t/3):e.isPoints?this.render.points+=r*t:e.isLineSegments?this.render.lines+=r*(t/2):e.isLine?this.render.lines+=r*(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 Xg{constructor(e){this.cacheKey=e,this.usedTimes=0}}class Yg extends Xg{constructor(e,t,r){super(e),this.vertexProgram=t,this.fragmentProgram=r}}class Qg extends Xg{constructor(e,t){super(e),this.computeProgram=t,this.isComputePipeline=!0}}let Zg=0;class Jg{constructor(e,t,r,s=null,i=null){this.id=Zg++,this.code=e,this.stage=t,this.name=r,this.transforms=s,this.attributes=i,this.usedTimes=0}}class em extends Vg{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:r}=this,s=this.get(e);if(this._needsComputeUpdate(e)){const i=s.pipeline;i&&(i.usedTimes--,i.computeProgram.usedTimes--);const n=this.nodes.getForCompute(e);let o=this.programs.compute.get(n.computeShader);void 0===o&&(i&&0===i.computeProgram.usedTimes&&this._releaseProgram(i.computeProgram),o=new Jg(n.computeShader,"compute",e.name,n.transforms,n.nodeAttributes),this.programs.compute.set(n.computeShader,o),r.createProgram(o));const a=this._getComputeCacheKey(e,o);let u=this.caches.get(a);void 0===u&&(i&&0===i.usedTimes&&this._releasePipeline(i),u=this._getComputePipeline(e,o,a,t)),u.usedTimes++,o.usedTimes++,s.version=e.version,s.pipeline=u}return s.pipeline}getForRender(e,t=null){const{backend:r}=this,s=this.get(e);if(this._needsRenderUpdate(e)){const i=s.pipeline;i&&(i.usedTimes--,i.vertexProgram.usedTimes--,i.fragmentProgram.usedTimes--);const n=e.getNodeBuilderState(),o=e.material?e.material.name:"";let a=this.programs.vertex.get(n.vertexShader);void 0===a&&(i&&0===i.vertexProgram.usedTimes&&this._releaseProgram(i.vertexProgram),a=new Jg(n.vertexShader,"vertex",o),this.programs.vertex.set(n.vertexShader,a),r.createProgram(a));let u=this.programs.fragment.get(n.fragmentShader);void 0===u&&(i&&0===i.fragmentProgram.usedTimes&&this._releaseProgram(i.fragmentProgram),u=new Jg(n.fragmentShader,"fragment",o),this.programs.fragment.set(n.fragmentShader,u),r.createProgram(u));const l=this._getRenderCacheKey(e,a,u);let d=this.caches.get(l);void 0===d?(i&&0===i.usedTimes&&this._releasePipeline(i),d=this._getRenderPipeline(e,a,u,l,t)):e.pipeline=d,d.usedTimes++,a.usedTimes++,u.usedTimes++,s.pipeline=d}return s.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,r,s){r=r||this._getComputeCacheKey(e,t);let i=this.caches.get(r);return void 0===i&&(i=new Qg(r,t),this.caches.set(r,i),this.backend.createComputePipeline(i,s)),i}_getRenderPipeline(e,t,r,s,i){s=s||this._getRenderCacheKey(e,t,r);let n=this.caches.get(s);return void 0===n&&(n=new Yg(s,t,r),this.caches.set(s,n),e.pipeline=n,this.backend.createRenderPipeline(e,i)),n}_getComputeCacheKey(e,t){return e.id+","+t.id}_getRenderCacheKey(e,t,r){return t.id+","+r.id+","+this.backend.getRenderCacheKey(e)}_releasePipeline(e){this.caches.delete(e.cacheKey)}_releaseProgram(e){const t=e.code,r=e.stage;this.programs[r].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 tm extends Vg{constructor(e,t,r,s,i,n){super(),this.backend=e,this.textures=r,this.pipelines=i,this.attributes=s,this.nodes=t,this.info=n,this.pipelines.bindings=this}getForRender(e){const t=e.getBindings();for(const e of t){const r=this.get(e);void 0===r.bindGroup&&(this._init(e),this.backend.createBindings(e,t,0),r.bindGroup=e)}return t}getForCompute(e){const t=this.nodes.getForCompute(e).bindings;for(const e of t){const r=this.get(e);void 0===r.bindGroup&&(this._init(e),this.backend.createBindings(e,t,0),r.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,r=e.isIndirectStorageBufferAttribute?zg:kg;this.attributes.update(e,r)}}_update(e,t){const{backend:r}=this;let s=!1,i=!0,n=0,o=0;for(const t of e.bindings){if(t.isNodeUniformsGroup){if(!1===this.nodes.updateGroup(t))continue}if(t.isUniformBuffer){t.update()&&r.updateBinding(t)}else if(t.isSampler)t.update();else if(t.isSampledTexture){const e=this.textures.get(t.texture);t.needsBindingsUpdate(e.generation)&&(s=!0);const a=t.update(),u=t.texture;a&&this.textures.updateTexture(u);const l=r.get(u);if(void 0!==l.externalTexture||e.isDefaultTexture?i=!1:(n=10*n+u.id,o+=u.version),!0===r.isWebGPUBackend&&void 0===l.texture&&void 0===l.externalTexture&&(console.error("Bindings._update: binding should be available:",t,a,u,t.textureNode.value,s),this.textures.updateTexture(u),s=!0),!0===u.isStorageTexture){const e=this.get(u);!0===t.store?e.needsMipmap=!0:this.textures.needsMipmaps(u)&&!0===e.needsMipmap&&(this.backend.generateMipmaps(u),e.needsMipmap=!1)}}}!0===s&&this.backend.updateBindings(e,t,i?n:0,o)}}function rm(e,t){return e.groupOrder!==t.groupOrder?e.groupOrder-t.groupOrder:e.renderOrder!==t.renderOrder?e.renderOrder-t.renderOrder:e.material.id!==t.material.id?e.material.id-t.material.id:e.z!==t.z?e.z-t.z:e.id-t.id}function sm(e,t){return e.groupOrder!==t.groupOrder?e.groupOrder-t.groupOrder:e.renderOrder!==t.renderOrder?e.renderOrder-t.renderOrder:e.z!==t.z?t.z-e.z:e.id-t.id}function im(e){return(e.transmission>0||e.transmissionNode)&&e.side===le&&!1===e.forceSinglePass}class nm{constructor(e,t,r){this.renderItems=[],this.renderItemsIndex=0,this.opaque=[],this.transparentDoublePass=[],this.transparent=[],this.bundles=[],this.lightsNode=e.getNode(t,r),this.lightsArray=[],this.scene=t,this.camera=r,this.occlusionQueryCount=0}begin(){return this.renderItemsIndex=0,this.opaque.length=0,this.transparentDoublePass.length=0,this.transparent.length=0,this.bundles.length=0,this.lightsArray.length=0,this.occlusionQueryCount=0,this}getNextRenderItem(e,t,r,s,i,n,o){let a=this.renderItems[this.renderItemsIndex];return void 0===a?(a={id:e.id,object:e,geometry:t,material:r,groupOrder:s,renderOrder:e.renderOrder,z:i,group:n,clippingContext:o},this.renderItems[this.renderItemsIndex]=a):(a.id=e.id,a.object=e,a.geometry=t,a.material=r,a.groupOrder=s,a.renderOrder=e.renderOrder,a.z=i,a.group=n,a.clippingContext=o),this.renderItemsIndex++,a}push(e,t,r,s,i,n,o){const a=this.getNextRenderItem(e,t,r,s,i,n,o);!0===e.occlusionTest&&this.occlusionQueryCount++,!0===r.transparent||r.transmission>0?(im(r)&&this.transparentDoublePass.push(a),this.transparent.push(a)):this.opaque.push(a)}unshift(e,t,r,s,i,n,o){const a=this.getNextRenderItem(e,t,r,s,i,n,o);!0===r.transparent||r.transmission>0?(im(r)&&this.transparentDoublePass.unshift(a),this.transparent.unshift(a)):this.opaque.unshift(a)}pushBundle(e){this.bundles.push(e)}pushLight(e){this.lightsArray.push(e)}sort(e,t){this.opaque.length>1&&this.opaque.sort(e||rm),this.transparentDoublePass.length>1&&this.transparentDoublePass.sort(t||sm),this.transparent.length>1&&this.transparent.sort(t||sm)}finish(){this.lightsNode.setLights(this.lightsArray);for(let e=this.renderItemsIndex,t=this.renderItems.length;e>t,u=o.height>>t;let l=e.depthTexture||i[t];const d=!0===e.depthBuffer||!0===e.stencilBuffer;let c=!1;void 0===l&&d&&(l=new B,l.format=e.stencilBuffer?ce:he,l.type=e.stencilBuffer?pe:b,l.image.width=a,l.image.height=u,i[t]=l),r.width===o.width&&o.height===r.height||(c=!0,l&&(l.needsUpdate=!0,l.image.width=a,l.image.height=u)),r.width=o.width,r.height=o.height,r.textures=n,r.depthTexture=l||null,r.depth=e.depthBuffer,r.stencil=e.stencilBuffer,r.renderTarget=e,r.sampleCount!==s&&(c=!0,l&&(l.needsUpdate=!0),r.sampleCount=s);const h={sampleCount:s};for(let e=0;e{e.removeEventListener("dispose",t);for(let e=0;e0){const s=e.image;if(void 0===s)console.warn("THREE.Renderer: Texture marked for update but image is undefined.");else if(!1===s.complete)console.warn("THREE.Renderer: Texture marked for update but image is incomplete.");else{if(e.images){const r=[];for(const t of e.images)r.push(t);t.images=r}else t.image=s;void 0!==r.isDefaultTexture&&!0!==r.isDefaultTexture||(i.createTexture(e,t),r.isDefaultTexture=!1,r.generation=e.version),!0===e.source.dataReady&&i.updateTexture(e,t),t.needsMipmaps&&0===e.mipmaps.length&&i.generateMipmaps(e)}}else i.createDefaultTexture(e),r.isDefaultTexture=!0,r.generation=e.version}if(!0!==r.initialized){r.initialized=!0,r.generation=e.version,this.info.memory.textures++;const t=()=>{e.removeEventListener("dispose",t),this._destroyTexture(e),this.info.memory.textures--};e.addEventListener("dispose",t)}r.version=e.version}getSize(e,t=mm){let r=e.images?e.images[0]:e.image;return r?(void 0!==r.image&&(r=r.image),t.width=r.width||1,t.height=r.height||1,t.depth=e.isCubeTexture?6:r.depth||1):t.width=t.height=t.depth=1,t}getMipLevels(e,t,r){let s;return s=e.isCompressedTexture?e.mipmaps?e.mipmaps.length:1:Math.floor(Math.log2(Math.max(t,r)))+1,s}needsMipmaps(e){return this.isEnvironmentTexture(e)||!0===e.isCompressedTexture||e.generateMipmaps}isEnvironmentTexture(e){const t=e.mapping;return t===W||t===j||t===_||t===v}_destroyTexture(e){this.backend.destroySampler(e),this.backend.destroyTexture(e),this.delete(e)}}class ym extends e{constructor(e,t,r,s=1){super(e,t,r),this.a=s}set(e,t,r,s=1){return this.a=s,super.set(e,t,r)}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)}}class bm extends an{static get type(){return"ParameterNode"}constructor(e,t=null){super(e,t),this.isParameterNode=!0}getHash(){return this.uuid}generate(){return this.name}}class xm extends Ps{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 r=new xi(t);return this._currentCond=Ra(e,r),this.add(this._currentCond)}ElseIf(e,t){const r=new xi(t),s=Ra(e,r);return this._currentCond.elseNode=s,this._currentCond=s,this}Else(e){return this._currentCond.elseNode=new xi(e),this}build(e,...t){const r=Ci();Ri(this);for(const t of this.nodes)t.build(e,"void");return Ri(r),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 Tm=Ni(xm);class _m extends Ps{static get type(){return"OutputStructNode"}constructor(...e){super(),this.members=e,this.isOutputStructNode=!0}setup(e){super.setup(e);const t=this.members,r=[];for(let s=0;s{const t=e.toUint().mul(747796405).add(2891336453),r=t.shiftRight(t.shiftRight(28).add(4)).bitXor(t).mul(277803737);return r.shiftRight(22).bitXor(r).toFloat().mul(1/2**32)})),Cm=(e,t)=>oa(Wn(4,e.mul(Hn(1,e))),t),Em=Ai((([e])=>e.fract().sub(.5).abs())).setLayout({name:"tri",type:"float",inputs:[{name:"x",type:"float"}]}),wm=Ai((([e])=>Oi(Em(e.z.add(Em(e.y.mul(1)))),Em(e.z.add(Em(e.x.mul(1)))),Em(e.y.add(Em(e.x.mul(1))))))).setLayout({name:"tri3",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),Mm=Ai((([e,t,r])=>{const s=Oi(e).toVar(),i=Bi(1.4).toVar(),n=Bi(0).toVar(),o=Oi(s).toVar();return pc({start:Bi(0),end:Bi(3),type:"float",condition:"<="},(()=>{const e=Oi(wm(o.mul(2))).toVar();s.addAssign(e.add(r.mul(Bi(.1).mul(t)))),o.mulAssign(1.8),i.mulAssign(1.5),s.mulAssign(1.2);const a=Bi(Em(s.z.add(Em(s.x.add(Em(s.y)))))).toVar();n.addAssign(a.div(i)),o.addAssign(.14)})),n})).setLayout({name:"triNoise3D",type:"float",inputs:[{name:"position",type:"vec3"},{name:"speed",type:"float"},{name:"time",type:"float"}]});class Bm extends Ps{static get type(){return"FunctionOverloadingNode"}constructor(e=[],...t){super(),this.functionNodes=e,this.parametersNodes=t,this._candidateFnCall=null,this.global=!0}getNodeType(){return this.functionNodes[0].shaderNode.layout.type}setup(e){const t=this.parametersNodes;let r=this._candidateFnCall;if(null===r){let s=null,i=-1;for(const r of this.functionNodes){const n=r.shaderNode.layout;if(null===n)throw new Error("FunctionOverloadingNode: FunctionNode must be a layout.");const o=n.inputs;if(t.length===o.length){let n=0;for(let r=0;ri&&(s=r,i=n)}}this._candidateFnCall=r=s(...t)}return r}}const Um=Ni(Bm),Fm=e=>(...t)=>Um(e,...t),Pm=on(0).setGroup(rn).onRenderUpdate((e=>e.time)),Im=on(0).setGroup(rn).onRenderUpdate((e=>e.deltaTime)),Dm=on(0,"uint").setGroup(rn).onRenderUpdate((e=>e.frameId)),Lm=Ai((([e,t,r=Ii(.5)])=>Tg(e.sub(r),t).add(r))),Vm=Ai((([e,t,r=Ii(.5)])=>{const s=e.sub(r),i=s.dot(s),n=i.mul(i).mul(t);return e.add(s.mul(n))})),Om=Ai((({position:e=null,horizontal:t=!0,vertical:r=!1})=>{let s;null!==e?(s=ju.toVar(),s[3][0]=e.x,s[3][1]=e.y,s[3][2]=e.z):s=ju;const i=Pu.mul(s);return yi(t)&&(i[0][0]=ju[0].length(),i[0][1]=0,i[0][2]=0),yi(r)&&(i[1][0]=0,i[1][1]=ju[1].length(),i[1][2]=0),i[2][0]=0,i[2][1]=0,i[2][2]=1,Uu.mul(i).mul(sl)})),Gm=Ai((([e=null])=>{const t=Zc();return Zc(Hc(e)).sub(t).lessThan(0).select(Ec,e)}));class km extends Ps{static get type(){return"SpriteSheetUVNode"}constructor(e,t=vu(),r=Bi(0)){super("vec2"),this.countNode=e,this.uvNode=t,this.frameNode=r}setup(){const{frameNode:e,uvNode:t,countNode:r}=this,{width:s,height:i}=r,n=e.mod(s.mul(i)).floor(),o=n.mod(s),a=i.sub(n.add(1).div(s).ceil()),u=r.reciprocal(),l=Ii(o,a);return t.add(l).mul(u)}}const zm=Ni(km);class $m extends Ps{static get type(){return"TriplanarTexturesNode"}constructor(e,t=null,r=null,s=Bi(1),i=sl,n=pl){super("vec4"),this.textureXNode=e,this.textureYNode=t,this.textureZNode=r,this.scaleNode=s,this.positionNode=i,this.normalNode=n}setup(){const{textureXNode:e,textureYNode:t,textureZNode:r,scaleNode:s,positionNode:i,normalNode:n}=this;let o=n.abs().normalize();o=o.div(o.dot(Oi(1)));const a=i.yz.mul(s),u=i.zx.mul(s),l=i.xy.mul(s),d=e.value,c=null!==t?t.value:d,h=null!==r?r.value:d,p=Eu(d,a).mul(o.x),g=Eu(c,u).mul(o.y),m=Eu(h,l).mul(o.z);return $n(p,g,m)}}const Hm=Ni($m),Wm=new fe,jm=new r,qm=new r,Km=new r,Xm=new n,Ym=new r(0,0,-1),Qm=new s,Zm=new r,Jm=new r,ef=new s,tf=new t,rf=new me,sf=Ec.flipX();rf.depthTexture=new B(1,1);let nf=!1;class of extends Cu{static get type(){return"ReflectorNode"}constructor(e={}){super(e.defaultTexture||rf.texture,sf),this._reflectorBaseNode=e.reflector||new af(this,e),this._depthNode=null,this.setUpdateMatrix(!1)}get reflector(){return this._reflectorBaseNode}get target(){return this._reflectorBaseNode.target}getDepthNode(){if(null===this._depthNode){if(!0!==this._reflectorBaseNode.depth)throw new Error("THREE.ReflectorNode: Depth node can only be requested when the reflector is created with { depth: true }. ");this._depthNode=Ti(new of({defaultTexture:rf.depthTexture,reflector:this._reflectorBaseNode}))}return this._depthNode}setup(e){return e.object.isQuadMesh||this._reflectorBaseNode.build(e),super.setup(e)}clone(){const e=new this.constructor(this.reflectorNode);return e._reflectorBaseNode=this._reflectorBaseNode,e}}class af extends Ps{static get type(){return"ReflectorBaseNode"}constructor(e,t={}){super();const{target:r=new ye,resolution:s=1,generateMipmaps:i=!1,bounces:n=!0,depth:o=!1}=t;this.textureNode=e,this.target=r,this.resolution=s,this.generateMipmaps=i,this.bounces=n,this.depth=o,this.updateBeforeType=n?Rs.RENDER:Rs.FRAME,this.virtualCameras=new WeakMap,this.renderTargets=new WeakMap}_updateResolution(e,t){const r=this.resolution;t.getDrawingBufferSize(tf),e.setSize(Math.round(tf.width*r),Math.round(tf.height*r))}setup(e){return this._updateResolution(rf,e.renderer),super.setup(e)}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 me(0,0,{type:be}),!0===this.generateMipmaps&&(t.texture.minFilter=xe,t.texture.generateMipmaps=!0),!0===this.depth&&(t.depthTexture=new B),this.renderTargets.set(e,t)),t}updateBefore(e){if(!1===this.bounces&&nf)return!1;nf=!0;const{scene:t,camera:r,renderer:s,material:i}=e,{target:n}=this,o=this.getVirtualCamera(r),a=this.getRenderTarget(o);if(s.getDrawingBufferSize(tf),this._updateResolution(a,s),qm.setFromMatrixPosition(n.matrixWorld),Km.setFromMatrixPosition(r.matrixWorld),Xm.extractRotation(n.matrixWorld),jm.set(0,0,1),jm.applyMatrix4(Xm),Zm.subVectors(qm,Km),Zm.dot(jm)>0)return;Zm.reflect(jm).negate(),Zm.add(qm),Xm.extractRotation(r.matrixWorld),Ym.set(0,0,-1),Ym.applyMatrix4(Xm),Ym.add(Km),Jm.subVectors(qm,Ym),Jm.reflect(jm).negate(),Jm.add(qm),o.coordinateSystem=r.coordinateSystem,o.position.copy(Zm),o.up.set(0,1,0),o.up.applyMatrix4(Xm),o.up.reflect(jm),o.lookAt(Jm),o.near=r.near,o.far=r.far,o.updateMatrixWorld(),o.projectionMatrix.copy(r.projectionMatrix),Wm.setFromNormalAndCoplanarPoint(jm,qm),Wm.applyMatrix4(o.matrixWorldInverse),Qm.set(Wm.normal.x,Wm.normal.y,Wm.normal.z,Wm.constant);const u=o.projectionMatrix;ef.x=(Math.sign(Qm.x)+u.elements[8])/u.elements[0],ef.y=(Math.sign(Qm.y)+u.elements[9])/u.elements[5],ef.z=-1,ef.w=(1+u.elements[10])/u.elements[14],Qm.multiplyScalar(1/Qm.dot(ef));u.elements[2]=Qm.x,u.elements[6]=Qm.y,u.elements[10]=s.coordinateSystem===l?Qm.z-0:Qm.z+1-0,u.elements[14]=Qm.w,this.textureNode.value=a.texture,!0===this.depth&&(this.textureNode.getDepthNode().value=a.depthTexture),i.visible=!1;const d=s.getRenderTarget(),c=s.getMRT(),h=s.autoClear;s.setMRT(null),s.setRenderTarget(a),s.autoClear=!0,s.render(t,o),s.setMRT(c),s.setRenderTarget(d),s.autoClear=h,i.visible=!0,nf=!1}}const uf=new Te(-1,1,1,-1,0,1);class lf extends _e{constructor(e=!1){super();const t=!1===e?[0,-1,0,1,2,1]:[0,2,0,0,2,0];this.setAttribute("position",new ve([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new ve(t,2))}}const df=new lf;class cf extends G{constructor(e=null){super(df,e),this.camera=uf,this.isQuadMesh=!0}async renderAsync(e){return e.renderAsync(this,uf)}render(e){e.render(this,uf)}}const hf=new t;class pf extends Cu{static get type(){return"RTTNode"}constructor(e,t=null,r=null,s={type:be}){const i=new me(t,r,s);super(i.texture,vu()),this.node=e,this.width=t,this.height=r,this.pixelRatio=1,this.renderTarget=i,this.textureNeedsUpdate=!0,this.autoUpdate=!0,this._rttNode=null,this._quadMesh=new cf(new nh),this.updateBeforeType=Rs.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 r=e*this.pixelRatio,s=t*this.pixelRatio;this.renderTarget.setSize(r,s),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(hf);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 Cu(this.value,this.uvNode,this.levelNode);return e.sampler=this.sampler,e.referenceNode=this,e}}const gf=(e,...t)=>Ti(new pf(Ti(e),...t)),mf=Ai((([e,t,r],s)=>{let i;s.renderer.coordinateSystem===l?(e=Ii(e.x,e.y.oneMinus()).mul(2).sub(1),i=$i(Oi(e,t),1)):i=$i(Oi(e.x,e.y.oneMinus(),t).mul(2).sub(1),1);const n=$i(r.mul(i));return n.xyz.div(n.w)})),ff=Ai((([e,t])=>{const r=t.mul($i(e,1)),s=r.xy.div(r.w).mul(.5).add(.5).toVar();return Ii(s.x,s.y.oneMinus())})),yf=Ai((([e,t,r])=>{const s=Su(wu(t)),i=Di(e.mul(s)).toVar(),n=wu(t,i).toVar(),o=wu(t,i.sub(Di(2,0))).toVar(),a=wu(t,i.sub(Di(1,0))).toVar(),u=wu(t,i.add(Di(1,0))).toVar(),l=wu(t,i.add(Di(2,0))).toVar(),d=wu(t,i.add(Di(0,2))).toVar(),c=wu(t,i.add(Di(0,1))).toVar(),h=wu(t,i.sub(Di(0,1))).toVar(),p=wu(t,i.sub(Di(0,2))).toVar(),g=Lo(Hn(Bi(2).mul(a).sub(o),n)).toVar(),m=Lo(Hn(Bi(2).mul(u).sub(l),n)).toVar(),f=Lo(Hn(Bi(2).mul(c).sub(d),n)).toVar(),y=Lo(Hn(Bi(2).mul(h).sub(p),n)).toVar(),b=mf(e,n,r).toVar(),x=g.lessThan(m).select(b.sub(mf(e.sub(Ii(Bi(1).div(s.x),0)),a,r)),b.negate().add(mf(e.add(Ii(Bi(1).div(s.x),0)),u,r))),T=f.lessThan(y).select(b.sub(mf(e.add(Ii(0,Bi(1).div(s.y))),c,r)),b.negate().add(mf(e.sub(Ii(0,Bi(1).div(s.y))),h,r)));return wo(na(x,T))}));class bf extends R{constructor(e,t,r=Float32Array){super(ArrayBuffer.isView(e)?e:new r(e*t),t),this.isStorageInstancedBufferAttribute=!0}}class xf extends Ne{constructor(e,t,r=Float32Array){super(ArrayBuffer.isView(e)?e:new r(e*t),t),this.isStorageBufferAttribute=!0}}class Tf extends Is{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.isPBO&&e.setupPBO(this.node),super.setup(e)}generate(e,t){let r;const s=e.context.assign;if(r=!1===e.isAvailable("storageBuffer")?!0!==this.node.isPBO||!0===s||!this.node.value.isInstancedBufferAttribute&&"compute"===e.shaderStage?this.node.build(e):e.generatePBO(this):super.generate(e),!0!==s){const s=this.getNodeType(e);r=e.format(r,s,t)}return r}}const _f=Ni(Tf);class vf extends wl{static get type(){return"StorageBufferNode"}constructor(e,t=null,r=0){null===t&&(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute)&&(t=fs(e.itemSize),r=e.count),super(e,t,r),this.isStorageBufferNode=!0,this.access=Es.READ_WRITE,this.isAtomic=!1,this.isPBO=!1,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 this.value.isIndirectStorageBufferAttribute?"indirectStorageBuffer":"storageBuffer"}element(e){return _f(this,e)}setPBO(e){return this.isPBO=e,this}getPBO(){return this.isPBO}setAccess(e){return this.access=e,this}toReadOnly(){return this.setAccess(Es.READ_ONLY)}setAtomic(e){return this.isAtomic=e,this}toAtomic(){return this.setAtomic(!0)}getAttributeData(){return null===this._attribute&&(this._attribute=ru(this.value),this._varying=La(this._attribute)),{attribute:this._attribute,varying:this._varying}}getNodeType(e){if(e.isAvailable("storageBuffer")||e.isAvailable("indirectStorageBuffer"))return super.getNodeType(e);const{attribute:t}=this.getAttributeData();return t.getNodeType(e)}generate(e){if(e.isAvailable("storageBuffer")||e.isAvailable("indirectStorageBuffer"))return super.generate(e);const{attribute:t,varying:r}=this.getAttributeData(),s=r.build(e);return e.registerTransform(s,t),s}}const Nf=(e,t=null,r=0)=>Ti(new vf(e,t,r));class Sf extends Tu{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 r;return r=!0===e.hasGeometryAttribute(t)?super.generate(e):e.generateConst(this.nodeType,new s(1,1,1,1)),r}serialize(e){super.serialize(e),e.index=this.index}deserialize(e){super.deserialize(e),this.index=e.index}}class Af extends Ps{static get type(){return"PointUVNode"}constructor(){super("vec2"),this.isPointUVNode=!0}generate(){return"vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )"}}const Rf=Si(Af),Cf=new Ae,Ef=new n;class wf extends Ps{static get type(){return"SceneNode"}constructor(e=wf.BACKGROUND_BLURRINESS,t=null){super(),this.scope=e,this.scene=t}setup(e){const t=this.scope,r=null!==this.scene?this.scene:e.scene;let s;return t===wf.BACKGROUND_BLURRINESS?s=Dl("backgroundBlurriness","float",r):t===wf.BACKGROUND_INTENSITY?s=Dl("backgroundIntensity","float",r):t===wf.BACKGROUND_ROTATION?s=on("mat4").label("backgroundRotation").setGroup(rn).onRenderUpdate((()=>{const e=r.background;return null!==e&&e.isTexture&&e.mapping!==Se?(Cf.copy(r.backgroundRotation),Cf.x*=-1,Cf.y*=-1,Cf.z*=-1,Ef.makeRotationFromEuler(Cf)):Ef.identity(),Ef})):console.error("THREE.SceneNode: Unknown scope:",t),s}}wf.BACKGROUND_BLURRINESS="backgroundBlurriness",wf.BACKGROUND_INTENSITY="backgroundIntensity",wf.BACKGROUND_ROTATION="backgroundRotation";const Mf=Si(wf,wf.BACKGROUND_BLURRINESS),Bf=Si(wf,wf.BACKGROUND_INTENSITY),Uf=Si(wf,wf.BACKGROUND_ROTATION);class Ff extends Cu{static get type(){return"StorageTextureNode"}constructor(e,t,r=null){super(e,t),this.storeNode=r,this.isStorageTextureNode=!0,this.access=Es.WRITE_ONLY}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 r;return r=null!==this.storeNode?this.generateStore(e):super.generate(e,t),r}toReadWrite(){return this.setAccess(Es.READ_WRITE)}toReadOnly(){return this.setAccess(Es.READ_ONLY)}toWriteOnly(){return this.setAccess(Es.WRITE_ONLY)}generateStore(e){const t=e.getNodeProperties(this),{uvNode:r,storeNode:s}=t,i=super.generate(e,"property"),n=r.build(e,"uvec2"),o=s.build(e,"vec4"),a=e.generateTextureStore(e,i,n,o);e.addLineFlowCode(a,this)}}const Pf=Ni(Ff);class If extends Il{static get type(){return"UserDataNode"}constructor(e,t,r=null){super(e,t,r),this.userData=r}updateReference(e){return this.reference=null!==this.userData?this.userData:e.object.userData,this.reference}}const Df=new WeakMap;class Lf extends Ls{static get type(){return"VelocityNode"}constructor(){super("vec2"),this.projectionMatrix=null,this.updateType=Rs.OBJECT,this.updateAfterType=Rs.OBJECT,this.previousModelWorldMatrix=on(new n),this.previousProjectionMatrix=on(new n).setGroup(rn),this.previousCameraViewMatrix=on(new n)}setProjectionMatrix(e){this.projectionMatrix=e}update({frameId:e,camera:t,object:r}){const s=Of(r);this.previousModelWorldMatrix.value.copy(s);const i=Vf(t);i.frameId!==e&&(i.frameId=e,void 0===i.previousProjectionMatrix?(i.previousProjectionMatrix=new n,i.previousCameraViewMatrix=new n,i.currentProjectionMatrix=new n,i.currentCameraViewMatrix=new n,i.previousProjectionMatrix.copy(this.projectionMatrix||t.projectionMatrix),i.previousCameraViewMatrix.copy(t.matrixWorldInverse)):(i.previousProjectionMatrix.copy(i.currentProjectionMatrix),i.previousCameraViewMatrix.copy(i.currentCameraViewMatrix)),i.currentProjectionMatrix.copy(this.projectionMatrix||t.projectionMatrix),i.currentCameraViewMatrix.copy(t.matrixWorldInverse),this.previousProjectionMatrix.value.copy(i.previousProjectionMatrix),this.previousCameraViewMatrix.value.copy(i.previousCameraViewMatrix))}updateAfter({object:e}){Of(e).copy(e.matrixWorld)}setup(){const e=null===this.projectionMatrix?Uu:on(this.projectionMatrix),t=this.previousCameraViewMatrix.mul(this.previousModelWorldMatrix),r=e.mul(Zu).mul(sl),s=this.previousProjectionMatrix.mul(t).mul(il),i=r.xy.div(r.w),n=s.xy.div(s.w);return Hn(i,n)}}function Vf(e){let t=Df.get(e);return void 0===t&&(t={},Df.set(e,t)),t}function Of(e,t=0){const r=Vf(e);let s=r[t];return void 0===s&&(r[t]=s=new n),s}const Gf=Si(Lf),kf=Ai((([e,t])=>Qo(1,e.oneMinus().div(t)).oneMinus())).setLayout({name:"blendBurn",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),zf=Ai((([e,t])=>Qo(e.div(t.oneMinus()),1))).setLayout({name:"blendDodge",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),$f=Ai((([e,t])=>e.oneMinus().mul(t.oneMinus()).oneMinus())).setLayout({name:"blendScreen",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Hf=Ai((([e,t])=>pa(e.mul(2).mul(t),e.oneMinus().mul(2).mul(t.oneMinus()).oneMinus(),ea(.5,e)))).setLayout({name:"blendOverlay",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Wf=Ai((([e,t])=>{const r=t.a.add(e.a.mul(t.a.oneMinus()));return $i(t.rgb.mul(t.a).add(e.rgb.mul(e.a).mul(t.a.oneMinus())).div(r),r)})).setLayout({name:"blendColor",type:"vec4",inputs:[{name:"base",type:"vec4"},{name:"blend",type:"vec4"}]}),jf=Ai((([e])=>Yf(e.rgb))),qf=Ai((([e,t=Bi(1)])=>t.mix(Yf(e.rgb),e.rgb))),Kf=Ai((([e,t=Bi(1)])=>{const r=$n(e.r,e.g,e.b).div(3),s=e.r.max(e.g.max(e.b)),i=s.sub(r).mul(t).mul(-3);return pa(e.rgb,s,i)})),Xf=Ai((([e,t=Bi(1)])=>{const r=Oi(.57735,.57735,.57735),s=t.cos();return Oi(e.rgb.mul(s).add(r.cross(e.rgb).mul(t.sin()).add(r.mul(ia(r,e.rgb).mul(s.oneMinus())))))})),Yf=(e,t=Oi(d.getLuminanceCoefficients(new r)))=>ia(e,t),Qf=Ai((([e,t=Oi(1),s=Oi(0),i=Oi(1),n=Bi(1),o=Oi(d.getLuminanceCoefficients(new r,Re))])=>{const a=e.rgb.dot(Oi(o)),u=Zo(e.rgb.mul(t).add(s),0).toVar(),l=u.pow(i).toVar();return Ei(u.r.greaterThan(0),(()=>{u.r.assign(l.r)})),Ei(u.g.greaterThan(0),(()=>{u.g.assign(l.g)})),Ei(u.b.greaterThan(0),(()=>{u.b.assign(l.b)})),u.assign(a.add(u.sub(a).mul(n))),$i(u.rgb,e.a)}));class Zf extends Ls{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 Jf=Ni(Zf),ey=new t;class ty extends Cu{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 ry extends ty{static get type(){return"PassMultipleTextureNode"}constructor(e,t,r=!1){super(e,null),this.textureName=t,this.previousTexture=r}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 sy extends Ls{static get type(){return"PassNode"}constructor(e,t,r,s={}){super("vec4"),this.scope=e,this.scene=t,this.camera=r,this.options=s,this._pixelRatio=1,this._width=1,this._height=1;const i=new B;i.isRenderTargetTexture=!0,i.name="depth";const n=new me(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:be,...s});n.texture.name="output",n.depthTexture=i,this.renderTarget=n,this._textures={output:n.texture,depth:i},this._textureNodes={},this._linearDepthNodes={},this._viewZNodes={},this._previousTextures={},this._previousTextureNodes={},this._cameraNear=on(0),this._cameraFar=on(0),this._mrt=null,this.isPassNode=!0,this.updateBeforeType=Rs.FRAME}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.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(),this._previousTextures[e]=t),t}toggleTexture(e){const t=this._previousTextures[e];if(void 0!==t){const r=this._textures[e],s=this.renderTarget.textures.indexOf(r);this.renderTarget.textures[s]=t,this._textures[e]=t,this._previousTextures[e]=r,this._textureNodes[e].updateTexture(),this._previousTextureNodes[e].updateTexture()}}getTextureNode(e="output"){let t=this._textureNodes[e];return void 0===t&&(t=Ti(new ry(this,e)),t.updateTexture(),this._textureNodes[e]=t),t}getPreviousTextureNode(e="output"){let t=this._previousTextureNodes[e];return void 0===t&&(void 0===this._textureNodes[e]&&this.getTextureNode(e),t=Ti(new ry(this,e,!0)),t.updateTexture(),this._previousTextureNodes[e]=t),t}getViewZNode(e="depth"){let t=this._viewZNodes[e];if(void 0===t){const r=this._cameraNear,s=this._cameraFar;this._viewZNodes[e]=t=Kc(this.getTextureNode(e),r,s)}return t}getLinearDepthNode(e="depth"){let t=this._linearDepthNodes[e];if(void 0===t){const r=this._cameraNear,s=this._cameraFar,i=this.getViewZNode(e);this._linearDepthNodes[e]=t=jc(i,r,s)}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.scope===sy.COLOR?this.getTextureNode():this.getLinearDepthNode()}updateBefore(e){const{renderer:t}=e,{scene:r,camera:s}=this;this._pixelRatio=t.getPixelRatio();const i=t.getSize(ey);this.setSize(i.width,i.height);const n=t.getRenderTarget(),o=t.getMRT();this._cameraNear.value=s.near,this._cameraFar.value=s.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(this.renderTarget),t.setMRT(this._mrt),t.render(r,s),t.setRenderTarget(n),t.setMRT(o)}setSize(e,t){this._width=e,this._height=t;const r=this._width*this._pixelRatio,s=this._height*this._pixelRatio;this.renderTarget.setSize(r,s)}setPixelRatio(e){this._pixelRatio=e,this.setSize(this._width,this._height)}dispose(){this.renderTarget.dispose()}}sy.COLOR="color",sy.DEPTH="depth";class iy extends sy{static get type(){return"ToonOutlinePassNode"}constructor(e,t,r,s,i){super(sy.COLOR,e,t),this.colorNode=r,this.thicknessNode=s,this.alphaNode=i,this._materialCache=new WeakMap}updateBefore(e){const{renderer:t}=e,r=t.getRenderObjectFunction();t.setRenderObjectFunction(((e,r,s,i,n,o,a,u)=>{if((n.isMeshToonMaterial||n.isMeshToonNodeMaterial)&&!1===n.wireframe){const l=this._getOutlineMaterial(n);t.renderObject(e,r,s,i,l,o,a,u)}t.renderObject(e,r,s,i,n,o,a,u)})),super.updateBefore(e),t.setRenderObjectFunction(r)}_createMaterial(){const e=new nh;e.isMeshToonOutlineMaterial=!0,e.name="Toon_Outline",e.side=T;const t=pl.negate(),r=Uu.mul(Zu),s=Bi(1),i=r.mul($i(sl,1)),n=r.mul($i(sl.add(t),1)),o=wo(i.sub(n));return e.vertexNode=i.add(o.mul(this.thicknessNode).mul(i.w).mul(s)),e.colorNode=$i(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 ny=Ai((([e,t])=>e.mul(t).clamp())).setLayout({name:"linearToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),oy=Ai((([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"}]}),ay=Ai((([e,t])=>{const r=(e=(e=e.mul(t)).sub(.004).max(0)).mul(e.mul(6.2).add(.5)),s=e.mul(e.mul(6.2).add(1.7)).add(.06);return r.div(s).pow(2.2)})).setLayout({name:"cineonToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),uy=Ai((([e])=>{const t=e.mul(e.add(.0245786)).sub(90537e-9),r=e.mul(e.add(.432951).mul(.983729)).add(.238081);return t.div(r)})),ly=Ai((([e,t])=>{const r=Ki(.59719,.35458,.04823,.076,.90834,.01566,.0284,.13383,.83777),s=Ki(1.60475,-.53108,-.07367,-.10208,1.10813,-.00605,-.00327,-.07276,1.07602);return e=e.mul(t).div(.6),e=r.mul(e),e=uy(e),(e=s.mul(e)).clamp()})).setLayout({name:"acesFilmicToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),dy=Ki(Oi(1.6605,-.1246,-.0182),Oi(-.5876,1.1329,-.1006),Oi(-.0728,-.0083,1.1187)),cy=Ki(Oi(.6274,.0691,.0164),Oi(.3293,.9195,.088),Oi(.0433,.0113,.8956)),hy=Ai((([e])=>{const t=Oi(e).toVar(),r=Oi(t.mul(t)).toVar(),s=Oi(r.mul(r)).toVar();return Bi(15.5).mul(s.mul(r)).sub(Wn(40.14,s.mul(t))).add(Wn(31.96,s).sub(Wn(6.868,r.mul(t))).add(Wn(.4298,r).add(Wn(.1191,t).sub(.00232))))})),py=Ai((([e,t])=>{const r=Oi(e).toVar(),s=Ki(Oi(.856627153315983,.137318972929847,.11189821299995),Oi(.0951212405381588,.761241990602591,.0767994186031903),Oi(.0482516061458583,.101439036467562,.811302368396859)),i=Ki(Oi(1.1271005818144368,-.1413297634984383,-.14132976349843826),Oi(-.11060664309660323,1.157823702216272,-.11060664309660294),Oi(-.016493938717834573,-.016493938717834257,1.2519364065950405)),n=Bi(-12.47393),o=Bi(4.026069);return r.mulAssign(t),r.assign(cy.mul(r)),r.assign(s.mul(r)),r.assign(Zo(r,1e-10)),r.assign(So(r)),r.assign(r.sub(n).div(o.sub(n))),r.assign(ga(r,0,1)),r.assign(hy(r)),r.assign(i.mul(r)),r.assign(oa(Zo(Oi(0),r),Oi(2.2))),r.assign(dy.mul(r)),r.assign(ga(r,0,1)),r})).setLayout({name:"agxToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),gy=Ai((([e,t])=>{const r=Bi(.76),s=Bi(.15);e=e.mul(t);const i=Qo(e.r,Qo(e.g,e.b)),n=Ra(i.lessThan(.08),i.sub(Wn(6.25,i.mul(i))),.04);e.subAssign(n);const o=Zo(e.r,Zo(e.g,e.b));Ei(o.lessThan(r),(()=>e));const a=Hn(1,r),u=Hn(1,a.mul(a).div(o.add(a.sub(r))));e.mulAssign(u.div(o));const l=Hn(1,jn(1,s.mul(o.sub(u)).add(1)));return pa(e,Oi(u),l)})).setLayout({name:"neutralToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]});class my extends Ps{static get type(){return"CodeNode"}constructor(e="",t=[],r=""){super("code"),this.isCodeNode=!0,this.code=e,this.includes=t,this.language=r}isGlobal(){return!0}setIncludes(e){return this.includes=e,this}getIncludes(){return this.includes}generate(e){const t=this.getIncludes(e);for(const r of t)r.build(e);const r=e.getCodeFromNode(this,this.getNodeType(e));return r.code=this.code,r.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 fy=Ni(my);class yy extends my{static get type(){return"FunctionNode"}constructor(e="",t=[],r=""){super(e,t,r)}getNodeType(e){return this.getNodeFunction(e).type}getInputs(e){return this.getNodeFunction(e).inputs}getNodeFunction(e){const t=e.getDataFromNode(this);let r=t.nodeFunction;return void 0===r&&(r=e.parser.parseFunction(this.code),t.nodeFunction=r),r}generate(e,t){super.generate(e);const r=this.getNodeFunction(e),s=r.name,i=r.type,n=e.getCodeFromNode(this,i);""!==s&&(n.name=s);const o=e.getPropertyName(n),a=this.getNodeFunction(e).getCode(o);return n.code=a+"\n","property"===t?o:e.format(`${o}()`,i,t)}}const by=(e,t=[],r="")=>{for(let e=0;es.call(...e);return i.functionNode=s,i};class xy extends Ps{static get type(){return"ScriptableValueNode"}constructor(e=null){super(),this._value=e,this._cache=null,this.inputType=null,this.outputType=null,this.events=new o,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:Bi()}serialize(e){super.serialize(e),null!==this.value?"ArrayBuffer"===this.inputType?e.value=vs(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?Ns(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 Ty=Ni(xy);class _y extends Map{get(e,t=null,...r){if(this.has(e))return super.get(e);if(null!==t){const s=t(...r);return this.set(e,s),s}}}class vy{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 Ny=new _y;class Sy extends Ps{static get type(){return"ScriptableNode"}constructor(e=null,t={}){super(),this.codeNode=e,this.parameters=t,this._local=new _y,this._output=Ty(),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 r=this._outputs;return void 0===r[e]?r[e]=Ty(t):r[e].value=t,this}getOutput(e){return this._outputs[e]}getParameter(e){return this.parameters[e]}setParameter(e,t){const r=this.parameters;return t&&t.isScriptableNode?(this.deleteParameter(e),r[e]=t,r[e].getDefaultOutput().events.addEventListener("refresh",this.onRefresh)):t&&t.isScriptableValueNode?(this.deleteParameter(e),r[e]=t,r[e].events.addEventListener("refresh",this.onRefresh)):void 0===r[e]?(r[e]=Ty(t),r[e].events.addEventListener("refresh",this.onRefresh)):r[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 r=this.getObject()[e];if("function"==typeof r)return r(...t)}async callAsync(e,...t){const r=this.getObject()[e];if("function"==typeof r)return"AsyncFunction"===r.constructor.name?await r(...t):r(...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 vy(this),t=Ny.get("THREE"),r=Ny.get("TSL"),s=this.getMethod(),i=[e,this._local,Ny,()=>this.refresh(),(e,t)=>this.setOutput(e,t),t,r];this._object=s(...i);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:Bi()}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+" };",r="var "+e+"; var output = {};\n"+this.codeNode.code+t;return this._method=new Function(...["parameters","local","global","refresh","setOutput","THREE","TSL"],r),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=[ls(this.source),this.getDefaultOutputNode().getCacheKey(e)];for(const r in this.parameters)t.push(this.parameters[r].getCacheKey(e));return ds(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 Ay=Ni(Sy);function Ry(e){let t;const r=e.context.getViewZ;return void 0!==r&&(t=r(this)),(t||al.z).negate()}const Cy=Ai((([e,t],r)=>{const s=Ry(r);return ya(e,t,s)})),Ey=Ai((([e],t)=>{const r=Ry(t);return e.mul(e,r,r).negate().exp().oneMinus()})),wy=Ai((([e,t])=>$i(t.toFloat().mix(En.rgb,e.toVec3()),En.a)));let My=null,By=null;class Uy extends Ps{static get type(){return"RangeNode"}constructor(e=Bi(),t=Bi()){super(),this.minNode=e,this.maxNode=t}getVectorLength(e){const t=e.getTypeLength(xs(this.minNode.value)),r=e.getTypeLength(xs(this.maxNode.value));return t>r?t:r}getNodeType(e){return e.object.count>1?e.getTypeFromLength(this.getVectorLength(e)):"float"}setup(e){const t=e.object;let r=null;if(t.count>1){const i=this.minNode.value,n=this.maxNode.value,o=e.getTypeLength(xs(i)),u=e.getTypeLength(xs(n));My=My||new s,By=By||new s,My.setScalar(0),By.setScalar(0),1===o?My.setScalar(i):i.isColor?My.set(i.r,i.g,i.b,1):My.set(i.x,i.y,i.z||0,i.w||0),1===u?By.setScalar(n):n.isColor?By.set(n.r,n.g,n.b,1):By.set(n.x,n.y,n.z||0,n.w||0);const l=4,d=l*t.count,c=new Float32Array(d);for(let e=0;eTi(new Py(e,t)),Dy=Iy("numWorkgroups","uvec3"),Ly=Iy("workgroupId","uvec3"),Vy=Iy("globalId","uvec3"),Oy=Iy("localId","uvec3"),Gy=Iy("subgroupSize","uint");const ky=Ni(class extends Ps{constructor(e){super(),this.scope=e}generate(e){const{scope:t}=this,{renderer:r}=e;!0===r.backend.isWebGLBackend?e.addFlowCode(`\t// ${t}Barrier \n`):e.addLineFlowCode(`${t}Barrier()`,this)}});class zy extends Is{constructor(e,t){super(e,t),this.isWorkgroupInfoElementNode=!0}generate(e,t){let r;const s=e.context.assign;if(r=super.generate(e),!0!==s){const s=this.getNodeType(e);r=e.format(r,s,t)}return r}}class $y extends Ps{constructor(e,t,r=0){super(t),this.bufferType=t,this.bufferCount=r,this.isWorkgroupInfoNode=!0,this.elementType=t,this.scope=e}label(e){return this.name=e,this}setScope(e){return this.scope=e,this}getElementType(){return this.elementType}getInputType(){return`${this.scope}Array`}element(e){return Ti(new zy(this,e))}generate(e){return e.getScopedArray(this.name||`${this.scope}Array_${this.id}`,this.scope.toLowerCase(),this.bufferType,this.bufferCount)}}class Hy extends Ls{static get type(){return"AtomicFunctionNode"}constructor(e,t,r,s=null){super("uint"),this.method=e,this.pointerNode=t,this.valueNode=r,this.storeNode=s}getInputType(e){return this.pointerNode.getNodeType(e)}getNodeType(e){return this.getInputType(e)}generate(e){const t=this.method,r=this.getNodeType(e),s=this.getInputType(e),i=this.pointerNode,n=this.valueNode,o=[];o.push(`&${i.build(e,s)}`),o.push(n.build(e,s));const a=`${e.getMethod(t,r)}( ${o.join(", ")} )`;if(null!==this.storeNode){const t=this.storeNode.build(e,s);e.addLineFlowCode(`${t} = ${a}`,this)}else e.addLineFlowCode(a,this)}}Hy.ATOMIC_LOAD="atomicLoad",Hy.ATOMIC_STORE="atomicStore",Hy.ATOMIC_ADD="atomicAdd",Hy.ATOMIC_SUB="atomicSub",Hy.ATOMIC_MAX="atomicMax",Hy.ATOMIC_MIN="atomicMin",Hy.ATOMIC_AND="atomicAnd",Hy.ATOMIC_OR="atomicOr",Hy.ATOMIC_XOR="atomicXor";const Wy=Ni(Hy),jy=(e,t,r,s=null)=>{const i=Wy(e,t,r,s);return i.append(),i};let qy;function Ky(e){qy=qy||new WeakMap;let t=qy.get(e);return void 0===t&&qy.set(e,t={}),t}function Xy(e){const t=Ky(e);return t.shadowMatrix||(t.shadowMatrix=on("mat4").setGroup(rn).onRenderUpdate((()=>(!0!==e.castShadow&&e.shadow.updateMatrices(e),e.shadow.matrix))))}function Yy(e){const t=Ky(e);if(void 0===t.projectionUV){const r=Xy(e).mul(nl);t.projectionUV=r.xyz.div(r.w)}return t.projectionUV}function Qy(e){const t=Ky(e);return t.position||(t.position=on(new r).setGroup(rn).onRenderUpdate(((t,r)=>r.value.setFromMatrixPosition(e.matrixWorld))))}function Zy(e){const t=Ky(e);return t.targetPosition||(t.targetPosition=on(new r).setGroup(rn).onRenderUpdate(((t,r)=>r.value.setFromMatrixPosition(e.target.matrixWorld))))}function Jy(e){const t=Ky(e);return t.viewPosition||(t.viewPosition=on(new r).setGroup(rn).onRenderUpdate((({camera:t},s)=>{s.value=s.value||new r,s.value.setFromMatrixPosition(e.matrixWorld),s.value.applyMatrix4(t.matrixWorldInverse)})))}const eb=e=>Pu.transformDirection(Qy(e).sub(Zy(e))),tb=(e,t)=>{for(const r of t)if(r.isAnalyticLightNode&&r.light.id===e)return r;return null},rb=new WeakMap;class sb extends Ps{static get type(){return"LightsNode"}constructor(){super("vec3"),this.totalDiffuseNode=Oi().toVar("totalDiffuse"),this.totalSpecularNode=Oi().toVar("totalSpecular"),this.outgoingLightNode=Oi().toVar("outgoingLight"),this._lights=[],this._lightNodes=null,this._lightNodesHash=null,this.global=!0}customCacheKey(){const e=[],t=this._lights;for(let r=0;re.sort(((e,t)=>e.id-t.id)))(this._lights),i=e.renderer.library;for(const e of s)if(e.isNode)t.push(Ti(e));else{let s=null;if(null!==r&&(s=tb(e.id,r)),null===s){const r=i.getLightNodeClass(e.constructor);if(null===r){console.warn(`LightsNode.setupNodeLights: Light node not found for ${e.constructor.name}`);continue}let s=null;rb.has(e)?s=rb.get(e):(s=Ti(new r(e)),rb.set(e,s)),t.push(s)}}this._lightNodes=t}setupLights(e,t){for(const r of t)r.build(e)}setup(e){null===this._lightNodes&&this.setupLightsNode(e);const t=e.context,r=t.lightingModel;let s=this.outgoingLightNode;if(r){const{_lightNodes:i,totalDiffuseNode:n,totalSpecularNode:o}=this;t.outgoingLight=s;const a=e.addStack();e.getDataFromNode(this).nodes=a.nodes,r.start(t,a,e),this.setupLights(e,i),r.indirect(t,a,e);const{backdrop:u,backdropAlpha:l}=t,{directDiffuse:d,directSpecular:c,indirectDiffuse:h,indirectSpecular:p}=t.reflectedLight;let g=d.add(h);null!==u&&(g=Oi(null!==l?l.mix(g,u):u),t.material.transparent=!0),n.assign(g),o.assign(c.add(p)),s.assign(n.add(o)),r.finish(t,a,e),s=s.bypass(e.removeStack())}return s}setLights(e){return this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this}getLights(){return this._lights}get hasLights(){return this._lights.length>0}}class ib extends Ps{static get type(){return"ShadowBaseNode"}constructor(e){super(),this.light=e,this.updateBeforeType=Rs.RENDER,this.isShadowBaseNode=!0}setupShadowPosition({material:e}){nb.assign(e.shadowPositionNode||nl)}dispose(){this.updateBeforeType=Rs.NONE}}const nb=Oi().toVar("shadowPositionWorld");function ob(t,r={}){return r.toneMapping=t.toneMapping,r.toneMappingExposure=t.toneMappingExposure,r.outputColorSpace=t.outputColorSpace,r.renderTarget=t.getRenderTarget(),r.activeCubeFace=t.getActiveCubeFace(),r.activeMipmapLevel=t.getActiveMipmapLevel(),r.renderObjectFunction=t.getRenderObjectFunction(),r.pixelRatio=t.getPixelRatio(),r.mrt=t.getMRT(),r.clearColor=t.getClearColor(r.clearColor||new e),r.clearAlpha=t.getClearAlpha(),r.autoClear=t.autoClear,r.scissorTest=t.getScissorTest(),r}function ab(e,t){return t=ob(e,t),e.setMRT(null),e.setRenderObjectFunction(null),e.setClearColor(0,1),e.autoClear=!0,t}function ub(e,t){e.toneMapping=t.toneMapping,e.toneMappingExposure=t.toneMappingExposure,e.outputColorSpace=t.outputColorSpace,e.setRenderTarget(t.renderTarget,t.activeCubeFace,t.activeMipmapLevel),e.setRenderObjectFunction(t.renderObjectFunction),e.setPixelRatio(t.pixelRatio),e.setMRT(t.mrt),e.setClearColor(t.clearColor,t.clearAlpha),e.autoClear=t.autoClear,e.setScissorTest(t.scissorTest)}function lb(e,t={}){return t.background=e.background,t.backgroundNode=e.backgroundNode,t.overrideMaterial=e.overrideMaterial,t}function db(e,t){return t=lb(e,t),e.background=null,e.backgroundNode=null,e.overrideMaterial=null,t}function cb(e,t){e.background=t.background,e.backgroundNode=t.backgroundNode,e.overrideMaterial=t.overrideMaterial}function hb(e,t,r){return r=db(t,r=ab(e,r))}function pb(e,t,r){ub(e,r),cb(t,r)}var gb=Object.freeze({__proto__:null,resetRendererAndSceneState:hb,resetRendererState:ab,resetSceneState:db,restoreRendererAndSceneState:pb,restoreRendererState:ub,restoreSceneState:cb,saveRendererAndSceneState:function(e,t,r={}){return r=lb(t,r=ob(e,r))},saveRendererState:ob,saveSceneState:lb});const mb=new WeakMap,fb=Ai((([e,t,r])=>{let s=nl.sub(e).length();return s=s.sub(t).div(r.sub(t)),s=s.saturate(),s})),yb=e=>{let t=mb.get(e);if(void 0===t){const r=e.isPointLight?(e=>{const t=e.shadow.camera,r=Dl("near","float",t).setGroup(rn),s=Dl("far","float",t).setGroup(rn),i=ku(e);return fb(i,r,s)})(e):null;t=new nh,t.colorNode=$i(0,0,0,1),t.depthNode=r,t.isShadowPassMaterial=!0,t.name="ShadowMaterial",t.fog=!1,mb.set(e,t)}return t},bb=Ai((({depthTexture:e,shadowCoord:t})=>Eu(e,t.xy).compare(t.z))),xb=Ai((({depthTexture:e,shadowCoord:t,shadow:r})=>{const s=(t,r)=>Eu(e,t).compare(r),i=Dl("mapSize","vec2",r).setGroup(rn),n=Dl("radius","float",r).setGroup(rn),o=Ii(1).div(i),a=o.x.negate().mul(n),u=o.y.negate().mul(n),l=o.x.mul(n),d=o.y.mul(n),c=a.div(2),h=u.div(2),p=l.div(2),g=d.div(2);return $n(s(t.xy.add(Ii(a,u)),t.z),s(t.xy.add(Ii(0,u)),t.z),s(t.xy.add(Ii(l,u)),t.z),s(t.xy.add(Ii(c,h)),t.z),s(t.xy.add(Ii(0,h)),t.z),s(t.xy.add(Ii(p,h)),t.z),s(t.xy.add(Ii(a,0)),t.z),s(t.xy.add(Ii(c,0)),t.z),s(t.xy,t.z),s(t.xy.add(Ii(p,0)),t.z),s(t.xy.add(Ii(l,0)),t.z),s(t.xy.add(Ii(c,g)),t.z),s(t.xy.add(Ii(0,g)),t.z),s(t.xy.add(Ii(p,g)),t.z),s(t.xy.add(Ii(a,d)),t.z),s(t.xy.add(Ii(0,d)),t.z),s(t.xy.add(Ii(l,d)),t.z)).mul(1/17)})),Tb=Ai((({depthTexture:e,shadowCoord:t,shadow:r})=>{const s=(t,r)=>Eu(e,t).compare(r),i=Dl("mapSize","vec2",r).setGroup(rn),n=Ii(1).div(i),o=n.x,a=n.y,u=t.xy,l=Mo(u.mul(i).add(.5));return u.subAssign(l.mul(n)),$n(s(u,t.z),s(u.add(Ii(o,0)),t.z),s(u.add(Ii(0,a)),t.z),s(u.add(n),t.z),pa(s(u.add(Ii(o.negate(),0)),t.z),s(u.add(Ii(o.mul(2),0)),t.z),l.x),pa(s(u.add(Ii(o.negate(),a)),t.z),s(u.add(Ii(o.mul(2),a)),t.z),l.x),pa(s(u.add(Ii(0,a.negate())),t.z),s(u.add(Ii(0,a.mul(2))),t.z),l.y),pa(s(u.add(Ii(o,a.negate())),t.z),s(u.add(Ii(o,a.mul(2))),t.z),l.y),pa(pa(s(u.add(Ii(o.negate(),a.negate())),t.z),s(u.add(Ii(o.mul(2),a.negate())),t.z),l.x),pa(s(u.add(Ii(o.negate(),a.mul(2))),t.z),s(u.add(Ii(o.mul(2),a.mul(2))),t.z),l.x),l.y)).mul(1/9)})),_b=Ai((({depthTexture:e,shadowCoord:t})=>{const r=Bi(1).toVar(),s=Eu(e).sample(t.xy).rg,i=ea(t.z,s.x);return Ei(i.notEqual(Bi(1)),(()=>{const e=t.z.sub(s.x),n=Zo(0,s.y.mul(s.y));let o=n.div(n.add(e.mul(e)));o=ga(Hn(o,.3).div(.95-.3)),r.assign(ga(Zo(i,o)))})),r})),vb=Ai((({samples:e,radius:t,size:r,shadowPass:s})=>{const i=Bi(0).toVar(),n=Bi(0).toVar(),o=e.lessThanEqual(Bi(1)).select(Bi(0),Bi(2).div(e.sub(1))),a=e.lessThanEqual(Bi(1)).select(Bi(0),Bi(-1));pc({start:Ui(0),end:Ui(e),type:"int",condition:"<"},(({i:e})=>{const u=a.add(Bi(e).mul(o)),l=s.sample($n(Mc.xy,Ii(0,u).mul(t)).div(r)).x;i.addAssign(l),n.addAssign(l.mul(l))})),i.divAssign(e),n.divAssign(e);const u=Ao(n.sub(i.mul(i)));return Ii(i,u)})),Nb=Ai((({samples:e,radius:t,size:r,shadowPass:s})=>{const i=Bi(0).toVar(),n=Bi(0).toVar(),o=e.lessThanEqual(Bi(1)).select(Bi(0),Bi(2).div(e.sub(1))),a=e.lessThanEqual(Bi(1)).select(Bi(0),Bi(-1));pc({start:Ui(0),end:Ui(e),type:"int",condition:"<"},(({i:e})=>{const u=a.add(Bi(e).mul(o)),l=s.sample($n(Mc.xy,Ii(u,0).mul(t)).div(r));i.addAssign(l.x),n.addAssign($n(l.y.mul(l.y),l.x.mul(l.x)))})),i.divAssign(e),n.divAssign(e);const u=Ao(n.sub(i.mul(i)));return Ii(i,u)})),Sb=[bb,xb,Tb,_b];let Ab;const Rb=new cf;class Cb extends ib{static get type(){return"ShadowNode"}constructor(e,t=null){super(e),this.shadow=t||e.shadow,this.shadowMap=null,this.vsmShadowMapVertical=null,this.vsmShadowMapHorizontal=null,this.vsmMaterialVertical=null,this.vsmMaterialHorizontal=null,this._node=null,this.isShadowNode=!0}setupShadowFilter(e,{filterFn:t,depthTexture:r,shadowCoord:s,shadow:i}){const n=s.x.greaterThanEqual(0).and(s.x.lessThanEqual(1)).and(s.y.greaterThanEqual(0)).and(s.y.lessThanEqual(1)).and(s.z.lessThanEqual(1)),o=t({depthTexture:r,shadowCoord:s,shadow:i});return n.select(o,Bi(1))}setupShadowCoord(e,t){const{shadow:r}=this,{renderer:s}=e,i=Dl("bias","float",r).setGroup(rn);let n,o=t;if(r.camera.isOrthographicCamera||!0!==s.logarithmicDepthBuffer)o=o.xyz.div(o.w),n=o.z,s.coordinateSystem===l&&(n=n.mul(2).sub(1));else{const e=o.w;o=o.xy.div(e);const t=Dl("near","float",r.camera).setGroup(rn),s=Dl("far","float",r.camera).setGroup(rn);n=Xc(e.negate(),t,s)}return o=Oi(o.x,o.y.oneMinus(),n.add(i)),o}getShadowFilterFn(e){return Sb[e]}setupShadow(e){const{renderer:t}=e,{light:r,shadow:s}=this,i=t.shadowMap.type,n=new B(s.mapSize.width,s.mapSize.height);n.compareFunction=Ce;const o=e.createRenderTarget(s.mapSize.width,s.mapSize.height);if(o.depthTexture=n,s.camera.updateProjectionMatrix(),i===Ee){n.compareFunction=null,this.vsmShadowMapVertical=e.createRenderTarget(s.mapSize.width,s.mapSize.height,{format:we,type:be}),this.vsmShadowMapHorizontal=e.createRenderTarget(s.mapSize.width,s.mapSize.height,{format:we,type:be});const t=Eu(n),r=Eu(this.vsmShadowMapVertical.texture),i=Dl("blurSamples","float",s).setGroup(rn),o=Dl("radius","float",s).setGroup(rn),a=Dl("mapSize","vec2",s).setGroup(rn);let u=this.vsmMaterialVertical||(this.vsmMaterialVertical=new nh);u.fragmentNode=vb({samples:i,radius:o,size:a,shadowPass:t}).context(e.getSharedContext()),u.name="VSMVertical",u=this.vsmMaterialHorizontal||(this.vsmMaterialHorizontal=new nh),u.fragmentNode=Nb({samples:i,radius:o,size:a,shadowPass:r}).context(e.getSharedContext()),u.name="VSMHorizontal"}const a=Dl("intensity","float",s).setGroup(rn),u=Dl("normalBias","float",s).setGroup(rn),l=Xy(r).mul(nb.add(bl.mul(u))),d=this.setupShadowCoord(e,l),c=s.filterNode||this.getShadowFilterFn(t.shadowMap.type)||null;if(null===c)throw new Error("THREE.WebGPURenderer: Shadow map type not supported yet.");const h=i===Ee?this.vsmShadowMapHorizontal.texture:n,p=this.setupShadowFilter(e,{filterFn:c,shadowTexture:o.texture,depthTexture:h,shadowCoord:d,shadow:s}),g=Eu(o.texture,d),m=pa(1,p.rgb.mix(g,1),a.mul(g.a)).toVar();return this.shadowMap=o,this.shadow.map=o,m}setup(e){if(!1!==e.renderer.shadowMap.enabled)return Ai((()=>{let t=this._node;return this.setupShadowPosition(e),null===t&&(this._node=t=this.setupShadow(e)),e.material.shadowNode&&console.warn('THREE.NodeMaterial: ".shadowNode" is deprecated. Use ".castShadowNode" instead.'),e.material.receivedShadowNode&&(t=e.material.receivedShadowNode(t)),t}))()}renderShadow(e){const{shadow:t,shadowMap:r,light:s}=this,{renderer:i,scene:n}=e;t.updateMatrices(s),r.setSize(t.mapSize.width,t.mapSize.height),i.render(n,t.camera)}updateShadow(e){const{shadowMap:t,light:r,shadow:s}=this,{renderer:i,scene:n,camera:o}=e,a=i.shadowMap.type,u=t.depthTexture.version;this._depthVersionCached=u,s.camera.layers.mask=o.layers.mask;const l=i.getRenderObjectFunction(),d=i.getMRT(),c=!!d&&d.has("velocity");Ab=hb(i,n,Ab),n.overrideMaterial=yb(r),i.setRenderObjectFunction(((e,t,r,n,u,l,...d)=>{(!0===e.castShadow||e.receiveShadow&&a===Ee)&&(c&&(_s(e).useVelocity=!0),e.onBeforeShadow(i,e,o,s.camera,n,t.overrideMaterial,l),i.renderObject(e,t,r,n,u,l,...d),e.onAfterShadow(i,e,o,s.camera,n,t.overrideMaterial,l))})),i.setRenderTarget(t),this.renderShadow(e),i.setRenderObjectFunction(l),!0!==r.isPointLight&&a===Ee&&this.vsmPass(i),pb(i,n,Ab)}vsmPass(e){const{shadow:t}=this;this.vsmShadowMapVertical.setSize(t.mapSize.width,t.mapSize.height),this.vsmShadowMapHorizontal.setSize(t.mapSize.width,t.mapSize.height),e.setRenderTarget(this.vsmShadowMapVertical),Rb.material=this.vsmMaterialVertical,Rb.render(e),e.setRenderTarget(this.vsmShadowMapHorizontal),Rb.material=this.vsmMaterialHorizontal,Rb.render(e)}dispose(){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),super.dispose()}updateBefore(e){const{shadow:t}=this;(t.needsUpdate||t.autoUpdate)&&(this.updateShadow(e),this.shadowMap.depthTexture.version===this._depthVersionCached&&(t.needsUpdate=!1))}}const Eb=(e,t)=>Ti(new Cb(e,t));class wb extends Tc{static get type(){return"AnalyticLightNode"}constructor(t=null){super(),this.light=t,this.color=new e,this.colorNode=t&&t.colorNode||on(this.color).setGroup(rn),this.baseColorNode=null,this.shadowNode=null,this.shadowColorNode=null,this.isAnalyticLightNode=!0,this.updateType=Rs.FRAME}customCacheKey(){return cs(this.light.id,this.light.castShadow?1:0)}getHash(){return this.light.uuid}setupShadowNode(){return Eb(this.light)}setupShadow(e){const{renderer:t}=e;if(!1===t.shadowMap.enabled)return;let r=this.shadowColorNode;if(null===r){const t=this.light.shadow.shadowNode;let s;s=void 0!==t?Ti(t):this.setupShadowNode(e),this.shadowNode=s,this.shadowColorNode=r=this.colorNode.mul(s),this.baseColorNode=this.colorNode}this.colorNode=r}setup(e){this.colorNode=this.baseColorNode||this.colorNode,this.light.castShadow?e.object.receiveShadow&&this.setupShadow(e):null!==this.shadowNode&&(this.shadowNode.dispose(),this.shadowNode=null,this.shadowColorNode=null)}update(){const{light:e}=this;this.color.copy(e.color).multiplyScalar(e.intensity)}}const Mb=Ai((e=>{const{lightDistance:t,cutoffDistance:r,decayExponent:s}=e,i=t.pow(s).max(.01).reciprocal();return r.greaterThan(0).select(i.mul(t.div(r).pow4().oneMinus().clamp().pow2()),i)})),Bb=new e,Ub=Ai((([e,t])=>{const r=e.toVar(),s=Lo(r),i=jn(1,Zo(s.x,Zo(s.y,s.z)));s.mulAssign(i),r.mulAssign(i.mul(t.mul(2).oneMinus()));const n=Ii(r.xy).toVar(),o=t.mul(1.5).oneMinus();return Ei(s.z.greaterThanEqual(o),(()=>{Ei(r.z.greaterThan(0),(()=>{n.x.assign(Hn(4,r.x))}))})).ElseIf(s.x.greaterThanEqual(o),(()=>{const e=Vo(r.x);n.x.assign(r.z.mul(e).add(e.mul(2)))})).ElseIf(s.y.greaterThanEqual(o),(()=>{const e=Vo(r.y);n.x.assign(r.x.add(e.mul(2)).add(2)),n.y.assign(r.z.mul(e).sub(2))})),Ii(.125,.25).mul(n).add(Ii(.375,.75)).flipY()})).setLayout({name:"cubeToUV",type:"vec2",inputs:[{name:"pos",type:"vec3"},{name:"texelSizeY",type:"float"}]}),Fb=Ai((({depthTexture:e,bd3D:t,dp:r,texelSize:s})=>Eu(e,Ub(t,s.y)).compare(r))),Pb=Ai((({depthTexture:e,bd3D:t,dp:r,texelSize:s,shadow:i})=>{const n=Dl("radius","float",i).setGroup(rn),o=Ii(-1,1).mul(n).mul(s.y);return Eu(e,Ub(t.add(o.xyy),s.y)).compare(r).add(Eu(e,Ub(t.add(o.yyy),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.xyx),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.yyx),s.y)).compare(r)).add(Eu(e,Ub(t,s.y)).compare(r)).add(Eu(e,Ub(t.add(o.xxy),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.yxy),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.xxx),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.yxx),s.y)).compare(r)).mul(1/9)})),Ib=Ai((({filterFn:e,depthTexture:t,shadowCoord:r,shadow:s})=>{const i=r.xyz.toVar(),n=i.length(),o=on("float").setGroup(rn).onRenderUpdate((()=>s.camera.near)),a=on("float").setGroup(rn).onRenderUpdate((()=>s.camera.far)),u=Dl("bias","float",s).setGroup(rn),l=on(s.mapSize).setGroup(rn),d=Bi(1).toVar();return Ei(n.sub(a).lessThanEqual(0).and(n.sub(o).greaterThanEqual(0)),(()=>{const r=n.sub(o).div(a.sub(o)).toVar();r.addAssign(u);const c=i.normalize(),h=Ii(1).div(l.mul(Ii(4,2)));d.assign(e({depthTexture:t,bd3D:c,dp:r,texelSize:h,shadow:s}))})),d})),Db=new s,Lb=new t,Vb=new t;class Ob extends Cb{static get type(){return"PointShadowNode"}constructor(e,t=null){super(e,t)}getShadowFilterFn(e){return e===Me?Fb:Pb}setupShadowCoord(e,t){return t}setupShadowFilter(e,{filterFn:t,shadowTexture:r,depthTexture:s,shadowCoord:i,shadow:n}){return Ib({filterFn:t,shadowTexture:r,depthTexture:s,shadowCoord:i,shadow:n})}renderShadow(e){const{shadow:t,shadowMap:r,light:s}=this,{renderer:i,scene:n}=e,o=t.getFrameExtents();Vb.copy(t.mapSize),Vb.multiply(o),r.setSize(Vb.width,Vb.height),Lb.copy(t.mapSize);const a=i.autoClear,u=i.getClearColor(Bb),l=i.getClearAlpha();i.autoClear=!1,i.setClearColor(t.clearColor,t.clearAlpha),i.clear();const d=t.getViewportCount();for(let e=0;e{const n=i.context.lightingModel,o=t.sub(al),a=o.normalize(),u=o.length(),l=Mb({lightDistance:u,cutoffDistance:r,decayExponent:s}),d=e.mul(l),c=i.context.reflectedLight;n.direct({lightDirection:a,lightColor:d,reflectedLight:c},i.stack,i)}));class kb extends wb{static get type(){return"PointLightNode"}constructor(e=null){super(e),this.cutoffDistanceNode=on(0).setGroup(rn),this.decayExponentNode=on(2).setGroup(rn)}update(e){const{light:t}=this;super.update(e),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}setupShadowNode(){return((e,t)=>Ti(new Ob(e,t)))(this.light)}setup(e){super.setup(e),Gb({color:this.colorNode,lightViewPosition:Jy(this.light),cutoffDistance:this.cutoffDistanceNode,decayExponent:this.decayExponentNode}).append()}}const zb=Ai((([e=t()])=>{const t=e.mul(2),r=t.x.floor(),s=t.y.floor();return r.add(s).mod(2).sign()})),$b=Ai((([e=vu()],{renderer:t,material:r})=>{const s=Bi(1).toVar(),i=ha(e.mul(2).sub(1));if(r.alphaToCoverage&&t.samples>1){const e=Bi(i.fwidth()).toVar();s.assign(ya(e.oneMinus(),e.add(1),i).oneMinus())}else i.greaterThan(1).discard();return s})),Hb=Ai((([e,t,r])=>{const s=Bi(r).toVar(),i=Bi(t).toVar(),n=Pi(e).toVar();return Ra(n,i,s)})).setLayout({name:"mx_select",type:"float",inputs:[{name:"b",type:"bool"},{name:"t",type:"float"},{name:"f",type:"float"}]}),Wb=Ai((([e,t])=>{const r=Pi(t).toVar(),s=Bi(e).toVar();return Ra(r,s.negate(),s)})).setLayout({name:"mx_negate_if",type:"float",inputs:[{name:"val",type:"float"},{name:"b",type:"bool"}]}),jb=Ai((([e])=>{const t=Bi(e).toVar();return Ui(Co(t))})).setLayout({name:"mx_floor",type:"int",inputs:[{name:"x",type:"float"}]}),qb=Ai((([e,t])=>{const r=Bi(e).toVar();return t.assign(jb(r)),r.sub(Bi(t))})),Kb=Fm([Ai((([e,t,r,s,i,n])=>{const o=Bi(n).toVar(),a=Bi(i).toVar(),u=Bi(s).toVar(),l=Bi(r).toVar(),d=Bi(t).toVar(),c=Bi(e).toVar(),h=Bi(Hn(1,a)).toVar();return Hn(1,o).mul(c.mul(h).add(d.mul(a))).add(o.mul(l.mul(h).add(u.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"}]}),Ai((([e,t,r,s,i,n])=>{const o=Bi(n).toVar(),a=Bi(i).toVar(),u=Oi(s).toVar(),l=Oi(r).toVar(),d=Oi(t).toVar(),c=Oi(e).toVar(),h=Bi(Hn(1,a)).toVar();return Hn(1,o).mul(c.mul(h).add(d.mul(a))).add(o.mul(l.mul(h).add(u.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"}]})]),Xb=Fm([Ai((([e,t,r,s,i,n,o,a,u,l,d])=>{const c=Bi(d).toVar(),h=Bi(l).toVar(),p=Bi(u).toVar(),g=Bi(a).toVar(),m=Bi(o).toVar(),f=Bi(n).toVar(),y=Bi(i).toVar(),b=Bi(s).toVar(),x=Bi(r).toVar(),T=Bi(t).toVar(),_=Bi(e).toVar(),v=Bi(Hn(1,p)).toVar(),N=Bi(Hn(1,h)).toVar();return Bi(Hn(1,c)).toVar().mul(N.mul(_.mul(v).add(T.mul(p))).add(h.mul(x.mul(v).add(b.mul(p))))).add(c.mul(N.mul(y.mul(v).add(f.mul(p))).add(h.mul(m.mul(v).add(g.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"}]}),Ai((([e,t,r,s,i,n,o,a,u,l,d])=>{const c=Bi(d).toVar(),h=Bi(l).toVar(),p=Bi(u).toVar(),g=Oi(a).toVar(),m=Oi(o).toVar(),f=Oi(n).toVar(),y=Oi(i).toVar(),b=Oi(s).toVar(),x=Oi(r).toVar(),T=Oi(t).toVar(),_=Oi(e).toVar(),v=Bi(Hn(1,p)).toVar(),N=Bi(Hn(1,h)).toVar();return Bi(Hn(1,c)).toVar().mul(N.mul(_.mul(v).add(T.mul(p))).add(h.mul(x.mul(v).add(b.mul(p))))).add(c.mul(N.mul(y.mul(v).add(f.mul(p))).add(h.mul(m.mul(v).add(g.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"}]})]),Yb=Ai((([e,t,r])=>{const s=Bi(r).toVar(),i=Bi(t).toVar(),n=Fi(e).toVar(),o=Fi(n.bitAnd(Fi(7))).toVar(),a=Bi(Hb(o.lessThan(Fi(4)),i,s)).toVar(),u=Bi(Wn(2,Hb(o.lessThan(Fi(4)),s,i))).toVar();return Wb(a,Pi(o.bitAnd(Fi(1)))).add(Wb(u,Pi(o.bitAnd(Fi(2)))))})).setLayout({name:"mx_gradient_float_0",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"}]}),Qb=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Bi(t).toVar(),a=Fi(e).toVar(),u=Fi(a.bitAnd(Fi(15))).toVar(),l=Bi(Hb(u.lessThan(Fi(8)),o,n)).toVar(),d=Bi(Hb(u.lessThan(Fi(4)),n,Hb(u.equal(Fi(12)).or(u.equal(Fi(14))),o,i))).toVar();return Wb(l,Pi(u.bitAnd(Fi(1)))).add(Wb(d,Pi(u.bitAnd(Fi(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"}]}),Zb=Fm([Yb,Qb]),Jb=Ai((([e,t,r])=>{const s=Bi(r).toVar(),i=Bi(t).toVar(),n=ki(e).toVar();return Oi(Zb(n.x,i,s),Zb(n.y,i,s),Zb(n.z,i,s))})).setLayout({name:"mx_gradient_vec3_0",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"}]}),ex=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Bi(t).toVar(),a=ki(e).toVar();return Oi(Zb(a.x,o,n,i),Zb(a.y,o,n,i),Zb(a.z,o,n,i))})).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"}]}),tx=Fm([Jb,ex]),rx=Ai((([e])=>{const t=Bi(e).toVar();return Wn(.6616,t)})).setLayout({name:"mx_gradient_scale2d_0",type:"float",inputs:[{name:"v",type:"float"}]}),sx=Ai((([e])=>{const t=Bi(e).toVar();return Wn(.982,t)})).setLayout({name:"mx_gradient_scale3d_0",type:"float",inputs:[{name:"v",type:"float"}]}),ix=Fm([rx,Ai((([e])=>{const t=Oi(e).toVar();return Wn(.6616,t)})).setLayout({name:"mx_gradient_scale2d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),nx=Fm([sx,Ai((([e])=>{const t=Oi(e).toVar();return Wn(.982,t)})).setLayout({name:"mx_gradient_scale3d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),ox=Ai((([e,t])=>{const r=Ui(t).toVar(),s=Fi(e).toVar();return s.shiftLeft(r).bitOr(s.shiftRight(Ui(32).sub(r)))})).setLayout({name:"mx_rotl32",type:"uint",inputs:[{name:"x",type:"uint"},{name:"k",type:"int"}]}),ax=Ai((([e,t,r])=>{e.subAssign(r),e.bitXorAssign(ox(r,Ui(4))),r.addAssign(t),t.subAssign(e),t.bitXorAssign(ox(e,Ui(6))),e.addAssign(r),r.subAssign(t),r.bitXorAssign(ox(t,Ui(8))),t.addAssign(e),e.subAssign(r),e.bitXorAssign(ox(r,Ui(16))),r.addAssign(t),t.subAssign(e),t.bitXorAssign(ox(e,Ui(19))),e.addAssign(r),r.subAssign(t),r.bitXorAssign(ox(t,Ui(4))),t.addAssign(e)})),ux=Ai((([e,t,r])=>{const s=Fi(r).toVar(),i=Fi(t).toVar(),n=Fi(e).toVar();return s.bitXorAssign(i),s.subAssign(ox(i,Ui(14))),n.bitXorAssign(s),n.subAssign(ox(s,Ui(11))),i.bitXorAssign(n),i.subAssign(ox(n,Ui(25))),s.bitXorAssign(i),s.subAssign(ox(i,Ui(16))),n.bitXorAssign(s),n.subAssign(ox(s,Ui(4))),i.bitXorAssign(n),i.subAssign(ox(n,Ui(14))),s.bitXorAssign(i),s.subAssign(ox(i,Ui(24))),s})).setLayout({name:"mx_bjfinal",type:"uint",inputs:[{name:"a",type:"uint"},{name:"b",type:"uint"},{name:"c",type:"uint"}]}),lx=Ai((([e])=>{const t=Fi(e).toVar();return Bi(t).div(Bi(Fi(Ui(4294967295))))})).setLayout({name:"mx_bits_to_01",type:"float",inputs:[{name:"bits",type:"uint"}]}),dx=Ai((([e])=>{const t=Bi(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"}]}),cx=Fm([Ai((([e])=>{const t=Ui(e).toVar(),r=Fi(Fi(1)).toVar(),s=Fi(Fi(Ui(3735928559)).add(r.shiftLeft(Fi(2))).add(Fi(13))).toVar();return ux(s.add(Fi(t)),s,s)})).setLayout({name:"mx_hash_int_0",type:"uint",inputs:[{name:"x",type:"int"}]}),Ai((([e,t])=>{const r=Ui(t).toVar(),s=Ui(e).toVar(),i=Fi(Fi(2)).toVar(),n=Fi().toVar(),o=Fi().toVar(),a=Fi().toVar();return n.assign(o.assign(a.assign(Fi(Ui(3735928559)).add(i.shiftLeft(Fi(2))).add(Fi(13))))),n.addAssign(Fi(s)),o.addAssign(Fi(r)),ux(n,o,a)})).setLayout({name:"mx_hash_int_1",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Ui(t).toVar(),n=Ui(e).toVar(),o=Fi(Fi(3)).toVar(),a=Fi().toVar(),u=Fi().toVar(),l=Fi().toVar();return a.assign(u.assign(l.assign(Fi(Ui(3735928559)).add(o.shiftLeft(Fi(2))).add(Fi(13))))),a.addAssign(Fi(n)),u.addAssign(Fi(i)),l.addAssign(Fi(s)),ux(a,u,l)})).setLayout({name:"mx_hash_int_2",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]}),Ai((([e,t,r,s])=>{const i=Ui(s).toVar(),n=Ui(r).toVar(),o=Ui(t).toVar(),a=Ui(e).toVar(),u=Fi(Fi(4)).toVar(),l=Fi().toVar(),d=Fi().toVar(),c=Fi().toVar();return l.assign(d.assign(c.assign(Fi(Ui(3735928559)).add(u.shiftLeft(Fi(2))).add(Fi(13))))),l.addAssign(Fi(a)),d.addAssign(Fi(o)),c.addAssign(Fi(n)),ax(l,d,c),l.addAssign(Fi(i)),ux(l,d,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"}]}),Ai((([e,t,r,s,i])=>{const n=Ui(i).toVar(),o=Ui(s).toVar(),a=Ui(r).toVar(),u=Ui(t).toVar(),l=Ui(e).toVar(),d=Fi(Fi(5)).toVar(),c=Fi().toVar(),h=Fi().toVar(),p=Fi().toVar();return c.assign(h.assign(p.assign(Fi(Ui(3735928559)).add(d.shiftLeft(Fi(2))).add(Fi(13))))),c.addAssign(Fi(l)),h.addAssign(Fi(u)),p.addAssign(Fi(a)),ax(c,h,p),c.addAssign(Fi(o)),h.addAssign(Fi(n)),ux(c,h,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"}]})]),hx=Fm([Ai((([e,t])=>{const r=Ui(t).toVar(),s=Ui(e).toVar(),i=Fi(cx(s,r)).toVar(),n=ki().toVar();return n.x.assign(i.bitAnd(Ui(255))),n.y.assign(i.shiftRight(Ui(8)).bitAnd(Ui(255))),n.z.assign(i.shiftRight(Ui(16)).bitAnd(Ui(255))),n})).setLayout({name:"mx_hash_vec3_0",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Ui(t).toVar(),n=Ui(e).toVar(),o=Fi(cx(n,i,s)).toVar(),a=ki().toVar();return a.x.assign(o.bitAnd(Ui(255))),a.y.assign(o.shiftRight(Ui(8)).bitAnd(Ui(255))),a.z.assign(o.shiftRight(Ui(16)).bitAnd(Ui(255))),a})).setLayout({name:"mx_hash_vec3_1",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]})]),px=Fm([Ai((([e])=>{const t=Ii(e).toVar(),r=Ui().toVar(),s=Ui().toVar(),i=Bi(qb(t.x,r)).toVar(),n=Bi(qb(t.y,s)).toVar(),o=Bi(dx(i)).toVar(),a=Bi(dx(n)).toVar(),u=Bi(Kb(Zb(cx(r,s),i,n),Zb(cx(r.add(Ui(1)),s),i.sub(1),n),Zb(cx(r,s.add(Ui(1))),i,n.sub(1)),Zb(cx(r.add(Ui(1)),s.add(Ui(1))),i.sub(1),n.sub(1)),o,a)).toVar();return ix(u)})).setLayout({name:"mx_perlin_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"}]}),Ai((([e])=>{const t=Oi(e).toVar(),r=Ui().toVar(),s=Ui().toVar(),i=Ui().toVar(),n=Bi(qb(t.x,r)).toVar(),o=Bi(qb(t.y,s)).toVar(),a=Bi(qb(t.z,i)).toVar(),u=Bi(dx(n)).toVar(),l=Bi(dx(o)).toVar(),d=Bi(dx(a)).toVar(),c=Bi(Xb(Zb(cx(r,s,i),n,o,a),Zb(cx(r.add(Ui(1)),s,i),n.sub(1),o,a),Zb(cx(r,s.add(Ui(1)),i),n,o.sub(1),a),Zb(cx(r.add(Ui(1)),s.add(Ui(1)),i),n.sub(1),o.sub(1),a),Zb(cx(r,s,i.add(Ui(1))),n,o,a.sub(1)),Zb(cx(r.add(Ui(1)),s,i.add(Ui(1))),n.sub(1),o,a.sub(1)),Zb(cx(r,s.add(Ui(1)),i.add(Ui(1))),n,o.sub(1),a.sub(1)),Zb(cx(r.add(Ui(1)),s.add(Ui(1)),i.add(Ui(1))),n.sub(1),o.sub(1),a.sub(1)),u,l,d)).toVar();return nx(c)})).setLayout({name:"mx_perlin_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"}]})]),gx=Fm([Ai((([e])=>{const t=Ii(e).toVar(),r=Ui().toVar(),s=Ui().toVar(),i=Bi(qb(t.x,r)).toVar(),n=Bi(qb(t.y,s)).toVar(),o=Bi(dx(i)).toVar(),a=Bi(dx(n)).toVar(),u=Oi(Kb(tx(hx(r,s),i,n),tx(hx(r.add(Ui(1)),s),i.sub(1),n),tx(hx(r,s.add(Ui(1))),i,n.sub(1)),tx(hx(r.add(Ui(1)),s.add(Ui(1))),i.sub(1),n.sub(1)),o,a)).toVar();return ix(u)})).setLayout({name:"mx_perlin_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),Ai((([e])=>{const t=Oi(e).toVar(),r=Ui().toVar(),s=Ui().toVar(),i=Ui().toVar(),n=Bi(qb(t.x,r)).toVar(),o=Bi(qb(t.y,s)).toVar(),a=Bi(qb(t.z,i)).toVar(),u=Bi(dx(n)).toVar(),l=Bi(dx(o)).toVar(),d=Bi(dx(a)).toVar(),c=Oi(Xb(tx(hx(r,s,i),n,o,a),tx(hx(r.add(Ui(1)),s,i),n.sub(1),o,a),tx(hx(r,s.add(Ui(1)),i),n,o.sub(1),a),tx(hx(r.add(Ui(1)),s.add(Ui(1)),i),n.sub(1),o.sub(1),a),tx(hx(r,s,i.add(Ui(1))),n,o,a.sub(1)),tx(hx(r.add(Ui(1)),s,i.add(Ui(1))),n.sub(1),o,a.sub(1)),tx(hx(r,s.add(Ui(1)),i.add(Ui(1))),n,o.sub(1),a.sub(1)),tx(hx(r.add(Ui(1)),s.add(Ui(1)),i.add(Ui(1))),n.sub(1),o.sub(1),a.sub(1)),u,l,d)).toVar();return nx(c)})).setLayout({name:"mx_perlin_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"}]})]),mx=Fm([Ai((([e])=>{const t=Bi(e).toVar(),r=Ui(jb(t)).toVar();return lx(cx(r))})).setLayout({name:"mx_cell_noise_float_0",type:"float",inputs:[{name:"p",type:"float"}]}),Ai((([e])=>{const t=Ii(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar();return lx(cx(r,s))})).setLayout({name:"mx_cell_noise_float_1",type:"float",inputs:[{name:"p",type:"vec2"}]}),Ai((([e])=>{const t=Oi(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar(),i=Ui(jb(t.z)).toVar();return lx(cx(r,s,i))})).setLayout({name:"mx_cell_noise_float_2",type:"float",inputs:[{name:"p",type:"vec3"}]}),Ai((([e])=>{const t=$i(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar(),i=Ui(jb(t.z)).toVar(),n=Ui(jb(t.w)).toVar();return lx(cx(r,s,i,n))})).setLayout({name:"mx_cell_noise_float_3",type:"float",inputs:[{name:"p",type:"vec4"}]})]),fx=Fm([Ai((([e])=>{const t=Bi(e).toVar(),r=Ui(jb(t)).toVar();return Oi(lx(cx(r,Ui(0))),lx(cx(r,Ui(1))),lx(cx(r,Ui(2))))})).setLayout({name:"mx_cell_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"float"}]}),Ai((([e])=>{const t=Ii(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar();return Oi(lx(cx(r,s,Ui(0))),lx(cx(r,s,Ui(1))),lx(cx(r,s,Ui(2))))})).setLayout({name:"mx_cell_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),Ai((([e])=>{const t=Oi(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar(),i=Ui(jb(t.z)).toVar();return Oi(lx(cx(r,s,i,Ui(0))),lx(cx(r,s,i,Ui(1))),lx(cx(r,s,i,Ui(2))))})).setLayout({name:"mx_cell_noise_vec3_2",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),Ai((([e])=>{const t=$i(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar(),i=Ui(jb(t.z)).toVar(),n=Ui(jb(t.w)).toVar();return Oi(lx(cx(r,s,i,n,Ui(0))),lx(cx(r,s,i,n,Ui(1))),lx(cx(r,s,i,n,Ui(2))))})).setLayout({name:"mx_cell_noise_vec3_3",type:"vec3",inputs:[{name:"p",type:"vec4"}]})]),yx=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Ui(t).toVar(),a=Oi(e).toVar(),u=Bi(0).toVar(),l=Bi(1).toVar();return pc(o,(()=>{u.addAssign(l.mul(px(a))),l.mulAssign(i),a.mulAssign(n)})),u})).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"}]}),bx=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Ui(t).toVar(),a=Oi(e).toVar(),u=Oi(0).toVar(),l=Bi(1).toVar();return pc(o,(()=>{u.addAssign(l.mul(gx(a))),l.mulAssign(i),a.mulAssign(n)})),u})).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"}]}),xx=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Ui(t).toVar(),a=Oi(e).toVar();return Ii(yx(a,o,n,i),yx(a.add(Oi(Ui(19),Ui(193),Ui(17))),o,n,i))})).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"}]}),Tx=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Ui(t).toVar(),a=Oi(e).toVar(),u=Oi(bx(a,o,n,i)).toVar(),l=Bi(yx(a.add(Oi(Ui(19),Ui(193),Ui(17))),o,n,i)).toVar();return $i(u,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"}]}),_x=Fm([Ai((([e,t,r,s,i,n,o])=>{const a=Ui(o).toVar(),u=Bi(n).toVar(),l=Ui(i).toVar(),d=Ui(s).toVar(),c=Ui(r).toVar(),h=Ui(t).toVar(),p=Ii(e).toVar(),g=Oi(fx(Ii(h.add(d),c.add(l)))).toVar(),m=Ii(g.x,g.y).toVar();m.subAssign(.5),m.mulAssign(u),m.addAssign(.5);const f=Ii(Ii(Bi(h),Bi(c)).add(m)).toVar(),y=Ii(f.sub(p)).toVar();return Ei(a.equal(Ui(2)),(()=>Lo(y.x).add(Lo(y.y)))),Ei(a.equal(Ui(3)),(()=>Zo(Lo(y.x),Lo(y.y)))),ia(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"}]}),Ai((([e,t,r,s,i,n,o,a,u])=>{const l=Ui(u).toVar(),d=Bi(a).toVar(),c=Ui(o).toVar(),h=Ui(n).toVar(),p=Ui(i).toVar(),g=Ui(s).toVar(),m=Ui(r).toVar(),f=Ui(t).toVar(),y=Oi(e).toVar(),b=Oi(fx(Oi(f.add(p),m.add(h),g.add(c)))).toVar();b.subAssign(.5),b.mulAssign(d),b.addAssign(.5);const x=Oi(Oi(Bi(f),Bi(m),Bi(g)).add(b)).toVar(),T=Oi(x.sub(y)).toVar();return Ei(l.equal(Ui(2)),(()=>Lo(T.x).add(Lo(T.y)).add(Lo(T.z)))),Ei(l.equal(Ui(3)),(()=>Zo(Zo(Lo(T.x),Lo(T.y)),Lo(T.z)))),ia(T,T)})).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"}]})]),vx=Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Ii(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ii(qb(n.x,o),qb(n.y,a)).toVar(),l=Bi(1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{const r=Bi(_x(u,e,t,o,a,i,s)).toVar();l.assign(Qo(l,r))}))})),Ei(s.equal(Ui(0)),(()=>{l.assign(Ao(l))})),l})).setLayout({name:"mx_worley_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),Nx=Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Ii(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ii(qb(n.x,o),qb(n.y,a)).toVar(),l=Ii(1e6,1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{const r=Bi(_x(u,e,t,o,a,i,s)).toVar();Ei(r.lessThan(l.x),(()=>{l.y.assign(l.x),l.x.assign(r)})).ElseIf(r.lessThan(l.y),(()=>{l.y.assign(r)}))}))})),Ei(s.equal(Ui(0)),(()=>{l.assign(Ao(l))})),l})).setLayout({name:"mx_worley_noise_vec2_0",type:"vec2",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),Sx=Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Ii(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ii(qb(n.x,o),qb(n.y,a)).toVar(),l=Oi(1e6,1e6,1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{const r=Bi(_x(u,e,t,o,a,i,s)).toVar();Ei(r.lessThan(l.x),(()=>{l.z.assign(l.y),l.y.assign(l.x),l.x.assign(r)})).ElseIf(r.lessThan(l.y),(()=>{l.z.assign(l.y),l.y.assign(r)})).ElseIf(r.lessThan(l.z),(()=>{l.z.assign(r)}))}))})),Ei(s.equal(Ui(0)),(()=>{l.assign(Ao(l))})),l})).setLayout({name:"mx_worley_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),Ax=Fm([vx,Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Oi(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ui().toVar(),l=Oi(qb(n.x,o),qb(n.y,a),qb(n.z,u)).toVar(),d=Bi(1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{pc({start:-1,end:Ui(1),name:"z",condition:"<="},(({z:r})=>{const n=Bi(_x(l,e,t,r,o,a,u,i,s)).toVar();d.assign(Qo(d,n))}))}))})),Ei(s.equal(Ui(0)),(()=>{d.assign(Ao(d))})),d})).setLayout({name:"mx_worley_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),Rx=Fm([Nx,Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Oi(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ui().toVar(),l=Oi(qb(n.x,o),qb(n.y,a),qb(n.z,u)).toVar(),d=Ii(1e6,1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{pc({start:-1,end:Ui(1),name:"z",condition:"<="},(({z:r})=>{const n=Bi(_x(l,e,t,r,o,a,u,i,s)).toVar();Ei(n.lessThan(d.x),(()=>{d.y.assign(d.x),d.x.assign(n)})).ElseIf(n.lessThan(d.y),(()=>{d.y.assign(n)}))}))}))})),Ei(s.equal(Ui(0)),(()=>{d.assign(Ao(d))})),d})).setLayout({name:"mx_worley_noise_vec2_1",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),Cx=Fm([Sx,Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Oi(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ui().toVar(),l=Oi(qb(n.x,o),qb(n.y,a),qb(n.z,u)).toVar(),d=Oi(1e6,1e6,1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{pc({start:-1,end:Ui(1),name:"z",condition:"<="},(({z:r})=>{const n=Bi(_x(l,e,t,r,o,a,u,i,s)).toVar();Ei(n.lessThan(d.x),(()=>{d.z.assign(d.y),d.y.assign(d.x),d.x.assign(n)})).ElseIf(n.lessThan(d.y),(()=>{d.z.assign(d.y),d.y.assign(n)})).ElseIf(n.lessThan(d.z),(()=>{d.z.assign(n)}))}))}))})),Ei(s.equal(Ui(0)),(()=>{d.assign(Ao(d))})),d})).setLayout({name:"mx_worley_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),Ex=Ai((([e])=>{const t=e.y,r=e.z,s=Oi().toVar();return Ei(t.lessThan(1e-4),(()=>{s.assign(Oi(r,r,r))})).Else((()=>{let i=e.x;i=i.sub(Co(i)).mul(6).toVar();const n=Ui(jo(i)),o=i.sub(Bi(n)),a=r.mul(t.oneMinus()),u=r.mul(t.mul(o).oneMinus()),l=r.mul(t.mul(o.oneMinus()).oneMinus());Ei(n.equal(Ui(0)),(()=>{s.assign(Oi(r,l,a))})).ElseIf(n.equal(Ui(1)),(()=>{s.assign(Oi(u,r,a))})).ElseIf(n.equal(Ui(2)),(()=>{s.assign(Oi(a,r,l))})).ElseIf(n.equal(Ui(3)),(()=>{s.assign(Oi(a,u,r))})).ElseIf(n.equal(Ui(4)),(()=>{s.assign(Oi(l,a,r))})).Else((()=>{s.assign(Oi(r,a,u))}))})),s})).setLayout({name:"mx_hsvtorgb",type:"vec3",inputs:[{name:"hsv",type:"vec3"}]}),wx=Ai((([e])=>{const t=Oi(e).toVar(),r=Bi(t.x).toVar(),s=Bi(t.y).toVar(),i=Bi(t.z).toVar(),n=Bi(Qo(r,Qo(s,i))).toVar(),o=Bi(Zo(r,Zo(s,i))).toVar(),a=Bi(o.sub(n)).toVar(),u=Bi().toVar(),l=Bi().toVar(),d=Bi().toVar();return d.assign(o),Ei(o.greaterThan(0),(()=>{l.assign(a.div(o))})).Else((()=>{l.assign(0)})),Ei(l.lessThanEqual(0),(()=>{u.assign(0)})).Else((()=>{Ei(r.greaterThanEqual(o),(()=>{u.assign(s.sub(i).div(a))})).ElseIf(s.greaterThanEqual(o),(()=>{u.assign($n(2,i.sub(r).div(a)))})).Else((()=>{u.assign($n(4,r.sub(s).div(a)))})),u.mulAssign(1/6),Ei(u.lessThan(0),(()=>{u.addAssign(1)}))})),Oi(u,l,d)})).setLayout({name:"mx_rgbtohsv",type:"vec3",inputs:[{name:"c",type:"vec3"}]}),Mx=Ai((([e])=>{const t=Oi(e).toVar(),r=zi(Qn(t,Oi(.04045))).toVar(),s=Oi(t.div(12.92)).toVar(),i=Oi(oa(Zo(t.add(Oi(.055)),Oi(0)).div(1.055),Oi(2.4))).toVar();return pa(s,i,r)})).setLayout({name:"mx_srgb_texture_to_lin_rec709",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),Bx=(e,t)=>{e=Bi(e),t=Bi(t);const r=Ii(t.dFdx(),t.dFdy()).length().mul(.7071067811865476);return ya(e.sub(r),e.add(r),t)},Ux=(e,t,r,s)=>pa(e,t,r[s].clamp()),Fx=(e,t,r,s,i)=>pa(e,t,Bx(r,s[i])),Px=Ai((([e,t,r])=>{const s=wo(e).toVar("nDir"),i=Hn(Bi(.5).mul(t.sub(r)),nl).div(s).toVar("rbmax"),n=Hn(Bi(-.5).mul(t.sub(r)),nl).div(s).toVar("rbmin"),o=Oi().toVar("rbminmax");o.x=s.x.greaterThan(Bi(0)).select(i.x,n.x),o.y=s.y.greaterThan(Bi(0)).select(i.y,n.y),o.z=s.z.greaterThan(Bi(0)).select(i.z,n.z);const a=Qo(Qo(o.x,o.y),o.z).toVar("correction");return nl.add(s.mul(a)).toVar("boxIntersection").sub(r)})),Ix=Ai((([e,t])=>{const r=e.x,s=e.y,i=e.z;let n=t.element(0).mul(.886227);return n=n.add(t.element(1).mul(1.023328).mul(s)),n=n.add(t.element(2).mul(1.023328).mul(i)),n=n.add(t.element(3).mul(1.023328).mul(r)),n=n.add(t.element(4).mul(.858086).mul(r).mul(s)),n=n.add(t.element(5).mul(.858086).mul(s).mul(i)),n=n.add(t.element(6).mul(i.mul(i).mul(.743125).sub(.247708))),n=n.add(t.element(7).mul(.858086).mul(r).mul(i)),n=n.add(t.element(8).mul(.429043).mul(Wn(r,r).sub(Wn(s,s)))),n}));var Dx=Object.freeze({__proto__:null,BRDF_GGX:Kh,BRDF_Lambert:Fh,BasicShadowFilter:bb,Break:gc,Const:Pa,Continue:()=>fu("continue").append(),DFGApprox:Xh,D_GGX:Wh,Discard:yu,EPSILON:po,F_Schlick:Uh,Fn:Ai,INFINITY:go,If:Ei,Loop:pc,NodeAccess:Es,NodeShaderStage:As,NodeType:Cs,NodeUpdateType:Rs,PCFShadowFilter:xb,PCFSoftShadowFilter:Tb,PI:mo,PI2:fo,Return:()=>fu("return").append(),Schlick_to_F0:Qh,ScriptableNodeResources:Ny,ShaderNode:xi,TBNViewMatrix:Jl,VSMShadowFilter:_b,V_GGX_SmithCorrelated:$h,Var:Fa,abs:Lo,acesFilmicToneMapping:ly,acos:Io,add:$n,addMethodChaining:qs,addNodeElement:function(e){console.warn("THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add",e)},agxToneMapping:py,all:yo,alphaT:_n,and:eo,anisotropy:vn,anisotropyB:Sn,anisotropyT:Nn,any:bo,append:wi,arrayBuffer:e=>Ti(new Hs(e,"ArrayBuffer")),asin:Po,assign:On,atan:Do,atan2:va,atomicAdd:(e,t,r=null)=>jy(Hy.ATOMIC_ADD,e,t,r),atomicAnd:(e,t,r=null)=>jy(Hy.ATOMIC_AND,e,t,r),atomicFunc:jy,atomicMax:(e,t,r=null)=>jy(Hy.ATOMIC_MAX,e,t,r),atomicMin:(e,t,r=null)=>jy(Hy.ATOMIC_MIN,e,t,r),atomicOr:(e,t,r=null)=>jy(Hy.ATOMIC_OR,e,t,r),atomicStore:(e,t,r=null)=>jy(Hy.ATOMIC_STORE,e,t,r),atomicSub:(e,t,r=null)=>jy(Hy.ATOMIC_SUB,e,t,r),atomicXor:(e,t,r=null)=>jy(Hy.ATOMIC_XOR,e,t,r),attenuationColor:Dn,attenuationDistance:In,attribute:_u,attributeArray:(e,t="float")=>{const r=bs(t),s=ys(t),i=new xf(e,r,s);return Nf(i,t,e)},backgroundBlurriness:Mf,backgroundIntensity:Bf,backgroundRotation:Uf,batch:uc,billboarding:Om,bitAnd:io,bitNot:no,bitOr:oo,bitXor:ao,bitangentGeometry:ql,bitangentLocal:Kl,bitangentView:Xl,bitangentWorld:Yl,bitcast:Xo,blendBurn:kf,blendColor:Wf,blendDodge:zf,blendOverlay:Hf,blendScreen:$f,blur:Xp,bool:Pi,buffer:Ml,bufferAttribute:ru,bumpMap:ud,burn:(...e)=>(console.warn('THREE.TSL: "burn" has been renamed. Use "blendBurn" instead.'),kf(e)),bvec2:Vi,bvec3:zi,bvec4:ji,bypass:cu,cache:lu,call:kn,cameraFar:Bu,cameraNear:Mu,cameraNormalMatrix:Du,cameraPosition:Lu,cameraProjectionMatrix:Uu,cameraProjectionMatrixInverse:Fu,cameraViewMatrix:Pu,cameraWorldMatrix:Iu,cbrt:ca,cdl:Qf,ceil:Eo,checker:zb,cineonToneMapping:ay,clamp:ga,clearcoat:gn,clearcoatRoughness:mn,code:fy,color:Mi,colorSpaceToWorking:qa,colorToDirection:e=>Ti(e).mul(2).sub(1),compute:au,cond:Ca,context:wa,convert:Qi,convertColorSpace:(e,t,r)=>Ti(new $a(Ti(e),t,r)),convertToTexture:(e,...t)=>e.isTextureNode?e:e.isPassNode?e.getTextureNode():gf(e,...t),cos:Uo,cross:na,cubeTexture:El,dFdx:zo,dFdy:$o,dashSize:wn,defaultBuildStages:Ms,defaultShaderStages:ws,defined:yi,degrees:To,deltaTime:Im,densityFog:function(e,t){return console.warn('THREE.TSL: "densityFog( color, density )" is deprecated. Use "fog( color, densityFogFactor( density ) )" instead.'),wy(e,Ey(t))},densityFogFactor:Ey,depth:Qc,depthPass:(e,t,r)=>Ti(new sy(sy.DEPTH,e,t,r)),difference:sa,diffuseColor:dn,directPointLight:Gb,directionToColor:mh,dispersion:Ln,distance:ra,div:jn,dodge:(...e)=>(console.warn('THREE.TSL: "dodge" has been renamed. Use "blendDodge" instead.'),zf(e)),dot:ia,drawIndex:rc,dynamicBufferAttribute:su,element:Yi,emissive:cn,equal:Kn,equals:Yo,equirectUV:xh,exp:_o,exp2:vo,expression:fu,faceDirection:cl,faceForward:ba,faceforward:Na,float:Bi,floor:Co,fog:wy,fract:Mo,frameGroup:tn,frameId:Dm,frontFacing:dl,fwidth:qo,gain:(e,t)=>e.lessThan(.5)?Cm(e.mul(2),t).div(2):Hn(1,Cm(Wn(Hn(1,e),2),t).div(2)),gapSize:Mn,getConstNodeType:bi,getCurrentStack:Ci,getDirection:Wp,getDistanceAttenuation:Mb,getGeometryRoughness:kh,getNormalFromDepth:yf,getParallaxCorrectNormal:Px,getRoughness:zh,getScreenPosition:ff,getShIrradianceAt:Ix,getTextureIndex:Nm,getViewPosition:mf,globalId:Vy,glsl:(e,t)=>fy(e,t,"glsl"),glslFn:(e,t)=>by(e,t,"glsl"),grayscale:jf,greaterThan:Qn,greaterThanEqual:Jn,hash:Rm,highpModelNormalViewMatrix:tl,highpModelViewMatrix:el,hue:Xf,instance:ic,instanceIndex:Zd,instancedArray:(e,t="float")=>{const r=bs(t),s=ys(t),i=new bf(e,r,s);return Nf(i,t,e)},instancedBufferAttribute:iu,instancedDynamicBufferAttribute:nu,instancedMesh:oc,int:Ui,inverseSqrt:Ro,inversesqrt:Sa,invocationLocalIndex:tc,invocationSubgroupIndex:ec,ior:Un,iridescence:bn,iridescenceIOR:xn,iridescenceThickness:Tn,ivec2:Di,ivec3:Gi,ivec4:Hi,js:(e,t)=>fy(e,t,"js"),label:Ma,length:Oo,lengthSq:ha,lessThan:Yn,lessThanEqual:Zn,lightPosition:Qy,lightProjectionUV:Yy,lightShadowMatrix:Xy,lightTargetDirection:eb,lightTargetPosition:Zy,lightViewPosition:Jy,lightingContext:Nc,lights:(e=[])=>Ti(new sb).setLights(e),linearDepth:Zc,linearToneMapping:ny,localId:Oy,log:No,log2:So,logarithmicDepthToViewZ:(e,t,r)=>{const s=e.mul(No(r.div(t)));return Bi(Math.E).pow(s).mul(t).negate()},loop:(...e)=>(console.warn("TSL.LoopNode: loop() has been renamed to Loop()."),pc(...e)),luminance:Yf,mat2:qi,mat3:Ki,mat4:Xi,matcapUV:fg,materialAO:qd,materialAlphaTest:cd,materialAnisotropy:Md,materialAnisotropyVector:Kd,materialAttenuationColor:Vd,materialAttenuationDistance:Ld,materialClearcoat:Sd,materialClearcoatNormal:Rd,materialClearcoatRoughness:Ad,materialColor:hd,materialDispersion:Wd,materialEmissive:gd,materialIOR:Dd,materialIridescence:Bd,materialIridescenceIOR:Ud,materialIridescenceThickness:Fd,materialLightMap:jd,materialLineDashOffset:$d,materialLineDashSize:Gd,materialLineGapSize:kd,materialLineScale:Od,materialLineWidth:zd,materialMetalness:vd,materialNormal:Nd,materialOpacity:md,materialPointSize:Hd,materialReference:Ol,materialReflectivity:Td,materialRefractionRatio:vl,materialRotation:Cd,materialRoughness:_d,materialSheen:Ed,materialSheenRoughness:wd,materialShininess:pd,materialSpecular:fd,materialSpecularColor:bd,materialSpecularIntensity:yd,materialSpecularStrength:xd,materialThickness:Id,materialTransmission:Pd,max:Zo,maxMipLevel:Ru,mediumpModelViewMatrix:Ju,metalness:pn,min:Qo,mix:pa,mixElement:Ta,mod:Jo,modInt:qn,modelDirection:Wu,modelNormalMatrix:Yu,modelPosition:qu,modelScale:Ku,modelViewMatrix:Zu,modelViewPosition:Xu,modelViewProjection:Xd,modelWorldMatrix:ju,modelWorldMatrixInverse:Qu,morphReference:xc,mrt:Am,mul:Wn,mx_aastep:Bx,mx_cell_noise_float:(e=vu())=>mx(e.convert("vec2|vec3")),mx_contrast:(e,t=1,r=.5)=>Bi(e).sub(r).mul(t).add(r),mx_fractal_noise_float:(e=vu(),t=3,r=2,s=.5,i=1)=>yx(e,Ui(t),r,s).mul(i),mx_fractal_noise_vec2:(e=vu(),t=3,r=2,s=.5,i=1)=>xx(e,Ui(t),r,s).mul(i),mx_fractal_noise_vec3:(e=vu(),t=3,r=2,s=.5,i=1)=>bx(e,Ui(t),r,s).mul(i),mx_fractal_noise_vec4:(e=vu(),t=3,r=2,s=.5,i=1)=>Tx(e,Ui(t),r,s).mul(i),mx_hsvtorgb:Ex,mx_noise_float:(e=vu(),t=1,r=0)=>px(e.convert("vec2|vec3")).mul(t).add(r),mx_noise_vec3:(e=vu(),t=1,r=0)=>gx(e.convert("vec2|vec3")).mul(t).add(r),mx_noise_vec4:(e=vu(),t=1,r=0)=>{e=e.convert("vec2|vec3");return $i(gx(e),px(e.add(Ii(19,73)))).mul(t).add(r)},mx_ramplr:(e,t,r=vu())=>Ux(e,t,r,"x"),mx_ramptb:(e,t,r=vu())=>Ux(e,t,r,"y"),mx_rgbtohsv:wx,mx_safepower:(e,t=1)=>(e=Bi(e)).abs().pow(t).mul(e.sign()),mx_splitlr:(e,t,r,s=vu())=>Fx(e,t,r,s,"x"),mx_splittb:(e,t,r,s=vu())=>Fx(e,t,r,s,"y"),mx_srgb_texture_to_lin_rec709:Mx,mx_transform_uv:(e=1,t=0,r=vu())=>r.mul(e).add(t),mx_worley_noise_float:(e=vu(),t=1)=>Ax(e.convert("vec2|vec3"),t,Ui(1)),mx_worley_noise_vec2:(e=vu(),t=1)=>Rx(e.convert("vec2|vec3"),t,Ui(1)),mx_worley_noise_vec3:(e=vu(),t=1)=>Cx(e.convert("vec2|vec3"),t,Ui(1)),negate:Go,neutralToneMapping:gy,nodeArray:vi,nodeImmutable:Si,nodeObject:Ti,nodeObjects:_i,nodeProxy:Ni,normalFlat:gl,normalGeometry:hl,normalLocal:pl,normalMap:id,normalView:ml,normalWorld:fl,normalize:wo,not:ro,notEqual:Xn,numWorkgroups:Dy,objectDirection:Ou,objectGroup:sn,objectPosition:ku,objectScale:zu,objectViewPosition:$u,objectWorldMatrix:Gu,oneMinus:ko,or:to,orthographicDepthToViewZ:(e,t,r)=>t.sub(r).mul(e).sub(t),oscSawtooth:(e=Pm)=>e.fract(),oscSine:(e=Pm)=>e.add(.75).mul(2*Math.PI).sin().mul(.5).add(.5),oscSquare:(e=Pm)=>e.fract().round(),oscTriangle:(e=Pm)=>e.add(.5).fract().mul(2).sub(1).abs(),output:En,outputStruct:vm,overlay:(...e)=>(console.warn('THREE.TSL: "overlay" has been renamed. Use "blendOverlay" instead.'),Hf(e)),overloadingFn:Fm,parabola:Cm,parallaxDirection:ed,parallaxUV:(e,t)=>e.sub(ed.mul(t)),parameter:(e,t)=>Ti(new bm(e,t)),pass:(e,t,r)=>Ti(new sy(sy.COLOR,e,t,r)),passTexture:(e,t)=>Ti(new ty(e,t)),pcurve:(e,t,r)=>oa(jn(oa(e,t),$n(oa(e,t),oa(Hn(1,e),r))),1/t),perspectiveDepthToViewZ:Kc,pmremTexture:eg,pointUV:Rf,pointWidth:Bn,positionGeometry:rl,positionLocal:sl,positionPrevious:il,positionView:al,positionViewDirection:ul,positionWorld:nl,positionWorldDirection:ol,posterize:Jf,pow:oa,pow2:aa,pow3:ua,pow4:la,property:un,radians:xo,rand:xa,range:Fy,rangeFog:function(e,t,r){return console.warn('THREE.TSL: "rangeFog( color, near, far )" is deprecated. Use "fog( color, rangeFogFactor( near, far ) )" instead.'),wy(e,Cy(t,r))},rangeFogFactor:Cy,reciprocal:Wo,reference:Dl,referenceBuffer:Ll,reflect:ta,reflectVector:Al,reflectView:Nl,reflector:e=>Ti(new of(e)),refract:fa,refractVector:Rl,refractView:Sl,reinhardToneMapping:oy,remainder:co,remap:pu,remapClamp:gu,renderGroup:rn,renderOutput:xu,rendererReference:Qa,rotate:Tg,rotateUV:Lm,roughness:hn,round:Ho,rtt:gf,sRGBTransferEOTF:Oa,sRGBTransferOETF:Ga,sampler:e=>(!0===e.isNode?e:Eu(e)).convert("sampler"),saturate:ma,saturation:qf,screen:(...e)=>(console.warn('THREE.TSL: "screen" has been renamed. Use "blendScreen" instead.'),$f(e)),screenCoordinate:Mc,screenSize:wc,screenUV:Ec,scriptable:Ay,scriptableValue:Ty,select:Ra,setCurrentStack:Ri,shaderStages:Bs,shadow:Eb,shadowPositionWorld:nb,shapeCircle:$b,sharedUniformGroup:en,sheen:fn,sheenRoughness:yn,shiftLeft:uo,shiftRight:lo,shininess:Cn,sign:Vo,sin:Bo,sinc:(e,t)=>Bo(mo.mul(t.mul(e).sub(1))).div(mo.mul(t.mul(e).sub(1))),skinning:e=>Ti(new dc(e)),skinningReference:cc,smoothstep:ya,smoothstepElement:_a,specularColor:An,specularF90:Rn,spherizeUV:Vm,split:(e,t)=>Ti(new Gs(Ti(e),t)),spritesheetUV:zm,sqrt:Ao,stack:Tm,step:ea,storage:Nf,storageBarrier:()=>ky("storage").append(),storageObject:(e,t,r)=>(console.warn('THREE.TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.'),Nf(e,t,r).setPBO(!0)),storageTexture:Pf,string:(e="")=>Ti(new Hs(e,"string")),sub:Hn,subgroupIndex:Jd,subgroupSize:Gy,tan:Fo,tangentGeometry:Gl,tangentLocal:kl,tangentView:zl,tangentWorld:$l,temp:Ia,texture:Eu,texture3D:Mg,textureBarrier:()=>ky("texture").append(),textureBicubic:mp,textureCubeUV:jp,textureLoad:wu,textureSize:Su,textureStore:(e,t,r)=>{const s=Pf(e,t,r);return null!==r&&s.append(),s},thickness:Pn,time:Pm,timerDelta:(e=1)=>(console.warn('TSL: timerDelta() is deprecated. Use "deltaTime" instead.'),Im.mul(e)),timerGlobal:(e=1)=>(console.warn('TSL: timerGlobal() is deprecated. Use "time" instead.'),Pm.mul(e)),timerLocal:(e=1)=>(console.warn('TSL: timerLocal() is deprecated. Use "time" instead.'),Pm.mul(e)),toOutputColorSpace:Ha,toWorkingColorSpace:Wa,toneMapping:Ja,toneMappingExposure:eu,toonOutlinePass:(t,r,s=new e(0,0,0),i=.003,n=1)=>Ti(new iy(t,r,Ti(s),Ti(i),Ti(n))),transformDirection:da,transformNormal:Tl,transformNormalToView:_l,transformedBentNormalView:td,transformedBitangentView:Ql,transformedBitangentWorld:Zl,transformedClearcoatNormalView:xl,transformedNormalView:yl,transformedNormalWorld:bl,transformedTangentView:Hl,transformedTangentWorld:Wl,transmission:Fn,transpose:Ko,triNoise3D:Mm,triplanarTexture:(...e)=>Hm(...e),triplanarTextures:Hm,trunc:jo,tslFn:(...e)=>(console.warn("TSL.ShaderNode: tslFn() has been renamed to Fn()."),Ai(...e)),uint:Fi,uniform:on,uniformArray:Fl,uniformGroup:Ji,uniforms:(e,t)=>(console.warn("TSL.UniformArrayNode: uniforms() has been renamed to uniformArray()."),Ti(new Ul(e,t))),userData:(e,t,r)=>Ti(new If(e,t,r)),uv:vu,uvec2:Li,uvec3:ki,uvec4:Wi,varying:La,varyingProperty:ln,vec2:Ii,vec3:Oi,vec4:$i,vectorComponents:Us,velocity:Gf,vertexColor:e=>Ti(new Sf(e)),vertexIndex:Qd,vertexStage:Va,vibrance:Kf,viewZToLogarithmicDepth:Xc,viewZToOrthographicDepth:jc,viewZToPerspectiveDepth:qc,viewport:Bc,viewportBottomLeft:Lc,viewportCoordinate:Fc,viewportDepthTexture:Hc,viewportLinearDepth:Jc,viewportMipTexture:kc,viewportResolution:Ic,viewportSafeUV:Gm,viewportSharedTexture:hh,viewportSize:Uc,viewportTexture:Gc,viewportTopLeft:Dc,viewportUV:Pc,wgsl:(e,t)=>fy(e,t,"wgsl"),wgslFn:(e,t)=>by(e,t,"wgsl"),workgroupArray:(e,t)=>Ti(new $y("Workgroup",e,t)),workgroupBarrier:()=>ky("workgroup").append(),workgroupId:Ly,workingToColorSpace:ja,xor:so});const Lx=new ym;class Vx extends Vg{constructor(e,t){super(),this.renderer=e,this.nodes=t}update(e,t,r){const s=this.renderer,i=this.nodes.getBackgroundNode(e)||e.background;let n=!1;if(null===i)s._clearColor.getRGB(Lx,Re),Lx.a=s._clearColor.a;else if(!0===i.isColor)i.getRGB(Lx,Re),Lx.a=1,n=!0;else if(!0===i.isNode){const r=this.get(e),n=i;Lx.copy(s._clearColor);let o=r.backgroundMesh;if(void 0===o){const e=wa($i(n).mul(Bf),{getUV:()=>Uf.mul(fl),getTextureLevel:()=>Mf});let t=Xd;t=t.setZ(t.w);const s=new nh;s.name="Background.material",s.side=T,s.depthTest=!1,s.depthWrite=!1,s.fog=!1,s.lights=!1,s.vertexNode=t,s.colorNode=e,r.backgroundMeshNode=e,r.backgroundMesh=o=new G(new Be(1,32,32),s),o.frustumCulled=!1,o.name="Background.mesh",o.onBeforeRender=function(e,t,r){this.matrixWorld.copyPosition(r.matrixWorld)}}const a=n.getCacheKey();r.backgroundCacheKey!==a&&(r.backgroundMeshNode.node=$i(n).mul(Bf),r.backgroundMeshNode.needsUpdate=!0,o.material.needsUpdate=!0,r.backgroundCacheKey=a),t.unshift(o,o.geometry,o.material,0,0,null,null)}else console.error("THREE.Renderer: Unsupported background configuration.",i);if(!0===s.autoClear||!0===n){const e=r.clearColorValue;e.r=Lx.r,e.g=Lx.g,e.b=Lx.b,e.a=Lx.a,!0!==s.backend.isWebGLBackend&&!0!==s.alpha||(e.r*=e.a,e.g*=e.a,e.b*=e.a),r.depthClearValue=s._clearDepth,r.stencilClearValue=s._clearStencil,r.clearColor=!0===s.autoClearColor,r.clearDepth=!0===s.autoClearDepth,r.clearStencil=!0===s.autoClearStencil}else r.clearColor=!1,r.clearDepth=!1,r.clearStencil=!1}}let Ox=0;class Gx{constructor(e="",t=[],r=0,s=[]){this.name=e,this.bindings=t,this.index=r,this.bindingsReference=s,this.id=Ox++}}class kx{constructor(e,t,r,s,i,n,o,a,u,l=[]){this.vertexShader=e,this.fragmentShader=t,this.computeShader=r,this.transforms=l,this.nodeAttributes=s,this.bindings=i,this.updateNodes=n,this.updateBeforeNodes=o,this.updateAfterNodes=a,this.monitor=u,this.usedTimes=0}createBindings(){const e=[];for(const t of this.bindings){if(!0!==t.bindings[0].groupNode.shared){const r=new Gx(t.name,[],t.index,t);e.push(r);for(const e of t.bindings)r.bindings.push(e.clone())}else e.push(t)}return e}}class zx{constructor(e,t,r=null){this.isNodeAttribute=!0,this.name=e,this.type=t,this.node=r}}class $x{constructor(e,t,r){this.isNodeUniform=!0,this.name=e,this.type=t,this.node=r.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 Hx{constructor(e,t,r=!1){this.isNodeVar=!0,this.name=e,this.type=t,this.readOnly=r}}class Wx extends Hx{constructor(e,t){super(e,t),this.needsInterpolation=!1,this.isNodeVarying=!0}}class jx{constructor(e,t,r=""){this.name=e,this.type=t,this.code=r,Object.defineProperty(this,"isNodeCode",{value:!0})}}let qx=0;class Kx{constructor(e=null){this.id=qx++,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 Xx extends Ps{static get type(){return"StructTypeNode"}constructor(e,t){super(),this.name=e,this.types=t,this.isStructTypeNode=!0}getMemberTypes(){return this.types}}class Yx{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 Qx extends Yx{constructor(e,t=0){super(e,t),this.isNumberUniform=!0,this.boundary=4,this.itemSize=1}}class Zx extends Yx{constructor(e,r=new t){super(e,r),this.isVector2Uniform=!0,this.boundary=8,this.itemSize=2}}class Jx extends Yx{constructor(e,t=new r){super(e,t),this.isVector3Uniform=!0,this.boundary=16,this.itemSize=3}}class eT extends Yx{constructor(e,t=new s){super(e,t),this.isVector4Uniform=!0,this.boundary=16,this.itemSize=4}}class tT extends Yx{constructor(t,r=new e){super(t,r),this.isColorUniform=!0,this.boundary=16,this.itemSize=3}}class rT extends Yx{constructor(e,t=new i){super(e,t),this.isMatrix3Uniform=!0,this.boundary=48,this.itemSize=12}}class sT extends Yx{constructor(e,t=new n){super(e,t),this.isMatrix4Uniform=!0,this.boundary=64,this.itemSize=16}}class iT extends Qx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class nT extends Zx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class oT extends Jx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class aT extends eT{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class uT extends tT{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class lT extends rT{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class dT extends sT{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}const cT=[.125,.215,.35,.446,.526,.582],hT=20,pT=new Te(-1,1,1,-1,0,1),gT=new Fe(90,1),mT=new e;let fT=null,yT=0,bT=0;const xT=(1+Math.sqrt(5))/2,TT=1/xT,_T=[new r(-xT,TT,0),new r(xT,TT,0),new r(-TT,0,xT),new r(TT,0,xT),new r(0,xT,-TT),new r(0,xT,TT),new r(-1,1,-1),new r(1,1,-1),new r(-1,1,1),new r(1,1,1)],vT=[3,1,5,0,4,2],NT=Wp(vu(),_u("faceIndex")).normalize(),ST=Oi(NT.x,NT.y,NT.z);class AT{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}get _hasInitialized(){return this._renderer.hasInitialized()}fromScene(e,t=0,r=.1,s=100,i=null){if(this._setSize(256),!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromScene() called before the backend is initialized. Try using .fromSceneAsync() instead.");const n=i||this._allocateTargets();return this.fromSceneAsync(e,t,r,s,n),n}fT=this._renderer.getRenderTarget(),yT=this._renderer.getActiveCubeFace(),bT=this._renderer.getActiveMipmapLevel();const n=i||this._allocateTargets();return n.depthBuffer=!0,this._sceneToCubeUV(e,r,s,n),t>0&&this._blur(n,0,0,t),this._applyPMREM(n),this._cleanup(n),n}async fromSceneAsync(e,t=0,r=.1,s=100,i=null){return!1===this._hasInitialized&&await this._renderer.init(),this.fromScene(e,t,r,s,i)}fromEquirectangular(e,t=null){if(!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromEquirectangular() called before the backend is initialized. Try using .fromEquirectangularAsync() instead."),this._setSizeFromTexture(e);const r=t||this._allocateTargets();return this.fromEquirectangularAsync(e,r),r}return this._fromTexture(e,t)}async fromEquirectangularAsync(e,t=null){return!1===this._hasInitialized&&await this._renderer.init(),this._fromTexture(e,t)}fromCubemap(e,t=null){if(!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromCubemap() called before the backend is initialized. Try using .fromCubemapAsync() instead."),this._setSizeFromTexture(e);const r=t||this._allocateTargets();return this.fromCubemapAsync(e,t),r}return this._fromTexture(e,t)}async fromCubemapAsync(e,t=null){return!1===this._hasInitialized&&await this._renderer.init(),this._fromTexture(e,t)}async compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=wT(),await this._compileMaterial(this._cubemapMaterial))}async compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=MT(),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())}_setSizeFromTexture(e){e.mapping===_||e.mapping===v?this._setSize(0===e.image.length?16:e.image[0].width||e.image[0].image.width):this._setSize(e.image.width/4)}_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?u=cT[a-e+4-1]:0===a&&(u=0),s.push(u);const l=1/(o-2),d=-l,c=1+l,h=[d,d,c,d,c,c,d,d,c,c,d,c],p=6,g=6,m=3,f=2,y=1,b=new Float32Array(m*g*p),x=new Float32Array(f*g*p),T=new Float32Array(y*g*p);for(let e=0;e2?0:-1,s=[t,r,0,t+2/3,r,0,t+2/3,r+1,0,t,r,0,t+2/3,r+1,0,t,r+1,0],i=vT[e];b.set(s,m*g*i),x.set(h,f*g*i);const n=[i,i,i,i,i,i];T.set(n,y*g*i)}const _=new _e;_.setAttribute("position",new Ne(b,m)),_.setAttribute("uv",new Ne(x,f)),_.setAttribute("faceIndex",new Ne(T,y)),t.push(_),i.push(new G(_,null)),n>4&&n--}return{lodPlanes:t,sizeLods:r,sigmas:s,lodMeshes:i}}(i)),this._blurMaterial=function(e,t,s){const i=Fl(new Array(hT).fill(0)),n=on(new r(0,1,0)),o=on(0),a=Bi(hT),u=on(0),l=on(1),d=Eu(null),c=on(0),h=Bi(1/t),p=Bi(1/s),g=Bi(e),m={n:a,latitudinal:u,weights:i,poleAxis:n,outputDirection:ST,dTheta:o,samples:l,envMap:d,mipInt:c,CUBEUV_TEXEL_WIDTH:h,CUBEUV_TEXEL_HEIGHT:p,CUBEUV_MAX_MIP:g},f=ET("blur");return f.uniforms=m,f.fragmentNode=Xp({...m,latitudinal:u.equal(1)}),f}(i,e,t)}return i}async _compileMaterial(e){const t=new G(this._lodPlanes[0],e);await this._renderer.compile(t,pT)}_sceneToCubeUV(e,t,r,s){const i=gT;i.near=t,i.far=r;const n=[1,1,1,1,-1,1],o=[1,-1,1,-1,1,-1],a=this._renderer,u=a.autoClear;a.getClearColor(mT),a.autoClear=!1;let l=this._backgroundBox;if(null===l){const e=new Y({name:"PMREM.Background",side:T,depthWrite:!1,depthTest:!1});l=new G(new O,e)}let d=!1;const c=e.background;c?c.isColor&&(l.material.color.copy(c),e.background=null,d=!0):(l.material.color.copy(mT),d=!0),a.setRenderTarget(s),a.clear(),d&&a.render(l,i);for(let t=0;t<6;t++){const r=t%3;0===r?(i.up.set(0,n[t],0),i.lookAt(o[t],0,0)):1===r?(i.up.set(0,0,n[t]),i.lookAt(0,o[t],0)):(i.up.set(0,n[t],0),i.lookAt(0,0,o[t]));const u=this._cubeSize;CT(s,r*u,t>2?u:0,u,u),a.render(e,i)}a.autoClear=u,e.background=c}_textureToCubeUV(e,t){const r=this._renderer,s=e.mapping===_||e.mapping===v;s?null===this._cubemapMaterial&&(this._cubemapMaterial=wT(e)):null===this._equirectMaterial&&(this._equirectMaterial=MT(e));const i=s?this._cubemapMaterial:this._equirectMaterial;i.fragmentNode.value=e;const n=this._lodMeshes[0];n.material=i;const o=this._cubeSize;CT(t,0,0,3*o,2*o),r.setRenderTarget(t),r.render(n,pT)}_applyPMREM(e){const t=this._renderer,r=t.autoClear;t.autoClear=!1;const s=this._lodPlanes.length;for(let t=1;thT&&console.warn(`sigmaRadians, ${i}, is too large and will clip, as it requested ${g} samples when the maximum is set to 20`);const m=[];let f=0;for(let e=0;ey-4?s-y+4:0),4*(this._cubeSize-b),3*b,2*b),a.setRenderTarget(t),a.render(l,pT)}}function RT(e,t,r){const s=new me(e,t,r);return s.texture.mapping=Ue,s.texture.name="PMREM.cubeUv",s.texture.isPMREMTexture=!0,s.scissorTest=!0,s}function CT(e,t,r,s,i){e.viewport.set(t,r,s,i),e.scissor.set(t,r,s,i)}function ET(e){const t=new nh;return t.depthTest=!1,t.depthWrite=!1,t.blending=D,t.name=`PMREM_${e}`,t}function wT(e){const t=ET("cubemap");return t.fragmentNode=El(e,ST),t}function MT(e){const t=ET("equirect");return t.fragmentNode=Eu(e,xh(ST),0),t}const BT=new WeakMap,UT=new Map([[Int8Array,"int"],[Int16Array,"int"],[Int32Array,"int"],[Uint8Array,"uint"],[Uint16Array,"uint"],[Uint32Array,"uint"],[Float32Array,"float"]]),FT=e=>/e/g.test(e)?String(e).replace(/\+/g,""):(e=Number(e))+(e%1?"":".0");class PT{constructor(e,t,r){this.object=e,this.material=e&&e.material||null,this.geometry=e&&e.geometry||null,this.renderer=t,this.parser=r,this.scene=null,this.camera=null,this.nodes=[],this.sequentialNodes=[],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=Tm(),this.stacks=[],this.tab="\t",this.currentFunctionNode=null,this.context={material:this.material},this.cache=new Kx,this.globalCache=this.cache,this.flowsData=new WeakMap,this.shaderStage=null,this.buildStage=null,this.useComparisonMethod=!1}getBindGroupsCache(){let e=BT.get(this.renderer);return void 0===e&&(e=new Fg,BT.set(this.renderer,e)),e}createRenderTarget(e,t,r){return new me(e,t,r)}createCubeRenderTarget(e,t){return new Th(e,t)}createPMREMGenerator(){return new AT(this.renderer)}includes(e){return this.nodes.includes(e)}getOutputStructName(){}_getBindGroup(e,t){const r=this.getBindGroupsCache(),s=[];let i,n=!0;for(const e of t)s.push(e),n=n&&!0!==e.groupNode.shared;return n?(i=r.get(s),void 0===i&&(i=new Gx(e,s,this.bindingsIndexes[e].group,s),r.set(s,i))):i=new Gx(e,s,this.bindingsIndexes[e].group,s),i}getBindGroupArray(e,t){const r=this.bindings[t];let s=r[e];return void 0===s&&(void 0===this.bindingsIndexes[e]&&(this.bindingsIndexes[e]={binding:0,group:Object.keys(this.bindingsIndexes).length}),r[e]=s=[]),s}getBindings(){let e=this.bindGroups;if(null===e){const t={},r=this.bindings;for(const e of Bs)for(const s in r[e]){const i=r[e][s];(t[s]||(t[s]=[])).push(...i)}e=[];for(const r in t){const s=t[r],i=this._getBindGroup(r,s);e.push(i)}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(n)}u`:"0u";if("bool"===i)return n?"true":"false";if("color"===i)return`${this.getType("vec3")}( ${FT(n.r)}, ${FT(n.g)}, ${FT(n.b)} )`;const o=this.getTypeLength(i),a=this.getComponentType(i),u=e=>this.generateConst(a,e);if(2===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)} )`;if(3===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)}, ${u(n.z)} )`;if(4===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)}, ${u(n.z)}, ${u(n.w)} )`;if(o>4&&n&&(n.isMatrix3||n.isMatrix4))return`${this.getType(i)}( ${n.elements.map(u).join(", ")} )`;if(o>4)return`${this.getType(i)}()`;throw new Error(`NodeBuilder: Type '${i}' 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 r=this.attributes;for(const t of r)if(t.name===e)return t;const s=new zx(e,t);return r.push(s),s}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===x)return"int";if(t===b)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 r=fs(e);return("float"===t?"":t[0])+r}getTypeFromArray(e){return UT.get(e.constructor)}getTypeFromAttribute(e){let t=e;e.isInterleavedBufferAttribute&&(t=e.data);const r=t.array,s=e.itemSize,i=e.normalized;let n;return e instanceof Le||!0===i||(n=this.getTypeFromArray(r)),this.getTypeFromLength(s,n)}getTypeLength(e){const t=this.getVectorType(e),r=/vec([2-4])/.exec(t);return null!==r?Number(r[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=Tm(this.stack),this.stacks.push(Ci()||this.stack),Ri(this.stack),this.stack}removeStack(){const e=this.stack;return this.stack=e.parent,Ri(this.stacks.pop()),e}getDataFromNode(e,t=this.shaderStage,r=null){let s=(r=null===r?e.isGlobal(this)?this.globalCache:this.cache:r).getData(e);return void 0===s&&(s={},r.setData(e,s)),void 0===s[t]&&(s[t]={}),s[t]}getNodeProperties(e,t="any"){const r=this.getDataFromNode(e,t);return r.properties||(r.properties={outputNode:null})}getBufferAttributeFromNode(e,t){const r=this.getDataFromNode(e);let s=r.bufferAttribute;if(void 0===s){const i=this.uniforms.index++;s=new zx("nodeAttribute"+i,t,e),this.bufferAttributes.push(s),r.bufferAttribute=s}return s}getStructTypeFromNode(e,t,r=this.shaderStage){const s=this.getDataFromNode(e,r);let i=s.structType;if(void 0===i){const e=this.structs.index++;i=new Xx("StructType"+e,t),this.structs[r].push(i),s.structType=i}return i}getUniformFromNode(e,t,r=this.shaderStage,s=null){const i=this.getDataFromNode(e,r,this.globalCache);let n=i.uniform;if(void 0===n){const o=this.uniforms.index++;n=new $x(s||"nodeUniform"+o,t,e),this.uniforms[r].push(n),i.uniform=n}return n}getVarFromNode(e,t=null,r=e.getNodeType(this),s=this.shaderStage,i=!1){const n=this.getDataFromNode(e,s);let o=n.variable;if(void 0===o){const e=i?"_const":"_var",a=this.vars[s]||(this.vars[s]=[]),u=this.vars[e]||(this.vars[e]=0);null===t&&(t=(i?"nodeConst":"nodeVar")+u,this.vars[e]++),o=new Hx(t,r,i),i||a.push(o),n.variable=o}return o}isDeterministic(e){return e.isMathNode?this.isDeterministic(e.aNode)&&(!e.bNode||this.isDeterministic(e.bNode))&&(!e.cNode||this.isDeterministic(e.cNode)):e.isOperatorNode?this.isDeterministic(e.aNode)&&(!e.bNode||this.isDeterministic(e.bNode)):!!e.isConstNode}getVaryingFromNode(e,t=null,r=e.getNodeType(this)){const s=this.getDataFromNode(e,"any");let i=s.varying;if(void 0===i){const e=this.varyings,n=e.length;null===t&&(t="nodeVarying"+n),i=new Wx(t,r),e.push(i),s.varying=i}return i}getCodeFromNode(e,t,r=this.shaderStage){const s=this.getDataFromNode(e);let i=s.code;if(void 0===i){const e=this.codes[r]||(this.codes[r]=[]),n=e.length;i=new jx("nodeCode"+n,t),e.push(i),s.code=i}return i}addFlowCodeHierarchy(e,t){const{flowCodes:r,flowCodeBlock:s}=this.getDataFromNode(e);let i=!0,n=t;for(;n;){if(!0===s.get(n)){i=!1;break}n=this.getDataFromNode(n).parentNodeBlock}if(i)for(const e of r)this.addLineFlowCode(e)}addLineFlowCodeBlock(e,t,r){const s=this.getDataFromNode(e),i=s.flowCodes||(s.flowCodes=[]),n=s.flowCodeBlock||(s.flowCodeBlock=new WeakMap);i.push(t),n.set(r,!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),r=this.flowChildNode(e,t);return this.flowsData.set(e,r),r}buildFunctionNode(e){const t=new yy,r=this.currentFunctionNode;return this.currentFunctionNode=t,t.code=this.buildFunctionCode(e),this.currentFunctionNode=r,t}flowShaderNode(e){const t=e.layout,r={[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)r[e.name]=new bm(e.type,e.name);e.layout=null;const s=e.call(r),i=this.flowStagesNode(s,t.type);return e.layout=t,i}flowStagesNode(e,t=null){const r=this.flow,s=this.vars,i=this.cache,n=this.buildStage,o=this.stack,a={code:""};this.flow=a,this.vars={},this.cache=new Kx,this.stack=Tm();for(const r of Ms)this.setBuildStage(r),a.result=e.build(this,t);return a.vars=this.getVars(this.shaderStage),this.flow=r,this.vars=s,this.cache=i,this.stack=o,this.setBuildStage(n),a}getFunctionOperator(){return null}flowChildNode(e,t=null){const r=this.flow,s={code:""};return this.flow=s,s.result=e.build(this,t),this.flow=r,s}flowNodeFromShaderStage(e,t,r=null,s=null){const i=this.shaderStage;this.setShaderStage(e);const n=this.flowChildNode(t,r);return null!==s&&(n.code+=`${this.tab+s} = ${n.result};\n`),this.flowCode[e]=this.flowCode[e]+n.code,this.setShaderStage(i),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 r=this.vars[e];if(void 0!==r)for(const e of r)t+=`${this.getVar(e.type,e.name)}; `;return t}getUniforms(){console.warn("Abstract function.")}getCodes(e){const t=this.codes[e];let r="";if(void 0!==t)for(const e of t)r+=e.code+"\n";return r}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:r}=this;if(null!==t){let e=r.library.fromMaterial(t);null===e&&(console.error(`NodeMaterial: Material "${t.type}" is not compatible.`),e=new nh),e.build(this)}else this.addFlow("compute",e);for(const e of Ms){this.setBuildStage(e),this.context.vertex&&this.context.vertex.isNode&&this.flowNodeFromShaderStage("vertex",this.context.vertex);for(const t of Bs){this.setShaderStage(t);const r=this.flowNodes[t];for(const t of r)"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 iT(e);if("vec2"===t||"ivec2"===t||"uvec2"===t)return new nT(e);if("vec3"===t||"ivec3"===t||"uvec3"===t)return new oT(e);if("vec4"===t||"ivec4"===t||"uvec4"===t)return new aT(e);if("color"===t)return new uT(e);if("mat3"===t)return new lT(e);if("mat4"===t)return new dT(e);throw new Error(`Uniform "${t}" not declared.`)}format(e,t,r){if((t=this.getVectorType(t))===(r=this.getVectorType(r))||null===r||this.isReference(r))return e;const s=this.getTypeLength(t),i=this.getTypeLength(r);return 16===s&&9===i?`${this.getType(r)}(${e}[0].xyz, ${e}[1].xyz, ${e}[2].xyz)`:9===s&&4===i?`${this.getType(r)}(${e}[0].xy, ${e}[1].xy)`:s>4||i>4||0===i?e:s===i?`${this.getType(r)}( ${e} )`:s>i?this.format(`${e}.${"xyz".slice(0,i)}`,this.getTypeFromLength(i,this.getComponentType(t)),r):4===i&&s>1?`${this.getType(r)}( ${this.format(e,t,"vec3")}, 1.0 )`:2===s?`${this.getType(r)}( ${this.format(e,t,"vec2")}, 0.0 )`:(1===s&&i>1&&t!==this.getComponentType(r)&&(e=`${this.getType(this.getComponentType(r))}( ${e} )`),`${this.getType(r)}( ${e} )`)}getSignature(){return`// Three.js r${Ve} - Node System\n`}createNodeMaterial(e="NodeMaterial"){throw new Error(`THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${e}() instead.`)}}class IT{constructor(){this.time=0,this.deltaTime=0,this.frameId=0,this.renderId=0,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 r=e.get(t);return void 0===r&&(r={renderMap:new WeakMap,frameMap:new WeakMap},e.set(t,r)),r}updateBeforeNode(e){const t=e.getUpdateBeforeType(),r=e.updateReference(this);if(t===Rs.FRAME){const{frameMap:t}=this._getMaps(this.updateBeforeMap,r);t.get(r)!==this.frameId&&!1!==e.updateBefore(this)&&t.set(r,this.frameId)}else if(t===Rs.RENDER){const{renderMap:t}=this._getMaps(this.updateBeforeMap,r);t.get(r)!==this.renderId&&!1!==e.updateBefore(this)&&t.set(r,this.renderId)}else t===Rs.OBJECT&&e.updateBefore(this)}updateAfterNode(e){const t=e.getUpdateAfterType(),r=e.updateReference(this);if(t===Rs.FRAME){const{frameMap:t}=this._getMaps(this.updateAfterMap,r);t.get(r)!==this.frameId&&!1!==e.updateAfter(this)&&t.set(r,this.frameId)}else if(t===Rs.RENDER){const{renderMap:t}=this._getMaps(this.updateAfterMap,r);t.get(r)!==this.renderId&&!1!==e.updateAfter(this)&&t.set(r,this.renderId)}else t===Rs.OBJECT&&e.updateAfter(this)}updateNode(e){const t=e.getUpdateType(),r=e.updateReference(this);if(t===Rs.FRAME){const{frameMap:t}=this._getMaps(this.updateMap,r);t.get(r)!==this.frameId&&!1!==e.update(this)&&t.set(r,this.frameId)}else if(t===Rs.RENDER){const{renderMap:t}=this._getMaps(this.updateMap,r);t.get(r)!==this.renderId&&!1!==e.update(this)&&t.set(r,this.renderId)}else t===Rs.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 DT{constructor(e,t,r=null,s="",i=!1){this.type=e,this.name=t,this.count=r,this.qualifier=s,this.isConst=i}}DT.isNodeFunctionInput=!0;class LT extends wb{static get type(){return"DirectionalLightNode"}constructor(e=null){super(e)}setup(e){super.setup(e);const t=e.context.lightingModel,r=this.colorNode,s=eb(this.light),i=e.context.reflectedLight;t.direct({lightDirection:s,lightColor:r,reflectedLight:i},e.stack,e)}}const VT=new n,OT=new n;let GT=null;class kT extends wb{static get type(){return"RectAreaLightNode"}constructor(e=null){super(e),this.halfHeight=on(new r).setGroup(rn),this.halfWidth=on(new r).setGroup(rn),this.updateType=Rs.RENDER}update(e){super.update(e);const{light:t}=this,r=e.camera.matrixWorldInverse;OT.identity(),VT.copy(t.matrixWorld),VT.premultiply(r),OT.extractRotation(VT),this.halfWidth.value.set(.5*t.width,0,0),this.halfHeight.value.set(0,.5*t.height,0),this.halfWidth.value.applyMatrix4(OT),this.halfHeight.value.applyMatrix4(OT)}setup(e){let t,r;super.setup(e),e.isAvailable("float32Filterable")?(t=Eu(GT.LTC_FLOAT_1),r=Eu(GT.LTC_FLOAT_2)):(t=Eu(GT.LTC_HALF_1),r=Eu(GT.LTC_HALF_2));const{colorNode:s,light:i}=this,n=e.context.lightingModel,o=Jy(i),a=e.context.reflectedLight;n.directRectArea({lightColor:s,lightPosition:o,halfWidth:this.halfWidth,halfHeight:this.halfHeight,reflectedLight:a,ltc_1:t,ltc_2:r},e.stack,e)}static setLTC(e){GT=e}}class zT extends wb{static get type(){return"SpotLightNode"}constructor(e=null){super(e),this.coneCosNode=on(0).setGroup(rn),this.penumbraCosNode=on(0).setGroup(rn),this.cutoffDistanceNode=on(0).setGroup(rn),this.decayExponentNode=on(0).setGroup(rn)}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:r}=this;return ya(t,r,e)}setup(e){super.setup(e);const t=e.context.lightingModel,{colorNode:r,cutoffDistanceNode:s,decayExponentNode:i,light:n}=this,o=Jy(n).sub(al),a=o.normalize(),u=a.dot(eb(n)),l=this.getSpotAttenuation(u),d=o.length(),c=Mb({lightDistance:d,cutoffDistance:s,decayExponent:i});let h=r.mul(l).mul(c);if(n.map){const e=Yy(n),t=Eu(n.map,e.xy).onRenderUpdate((()=>n.map));h=e.mul(2).sub(1).abs().lessThan(1).all().select(h.mul(t),h)}const p=e.context.reflectedLight;t.direct({lightDirection:a,lightColor:h,reflectedLight:p},e.stack,e)}}class $T extends zT{static get type(){return"IESSpotLightNode"}getSpotAttenuation(e){const t=this.light.iesMap;let r=null;if(t&&!0===t.isTexture){const s=e.acos().mul(1/Math.PI);r=Eu(t,Ii(s,0),0).r}else r=super.getSpotAttenuation(e);return r}}class HT extends wb{static get type(){return"AmbientLightNode"}constructor(e=null){super(e)}setup({context:e}){e.irradiance.addAssign(this.colorNode)}}class WT extends wb{static get type(){return"HemisphereLightNode"}constructor(t=null){super(t),this.lightPositionNode=Qy(t),this.lightDirectionNode=this.lightPositionNode.normalize(),this.groundColorNode=on(new e).setGroup(rn)}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:r,lightDirectionNode:s}=this,i=ml.dot(s).mul(.5).add(.5),n=pa(r,t,i);e.context.irradiance.addAssign(n)}}class jT extends wb{static get type(){return"LightProbeNode"}constructor(e=null){super(e);const t=[];for(let e=0;e<9;e++)t.push(new r);this.lightProbe=Fl(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=Ix(fl,this.lightProbe);e.context.irradiance.addAssign(t)}}class qT{parseFunction(){console.warn("Abstract function.")}}class KT{constructor(e,t,r="",s=""){this.type=e,this.inputs=t,this.name=r,this.precision=s}getCode(){console.warn("Abstract function.")}}KT.isNodeFunction=!0;const XT=/^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i,YT=/[a-z_0-9]+/gi,QT="#pragma main";class ZT extends KT{constructor(e){const{type:t,inputs:r,name:s,precision:i,inputsCode:n,blockCode:o,headerCode:a}=(e=>{const t=(e=e.trim()).indexOf(QT),r=-1!==t?e.slice(t+12):e,s=r.match(XT);if(null!==s&&5===s.length){const i=s[4],n=[];let o=null;for(;null!==(o=YT.exec(i));)n.push(o);const a=[];let u=0;for(;u0||e.backgroundBlurriness>0&&0===t.backgroundBlurriness;if(t.background!==r||s){const i=this.getCacheNode("background",r,(()=>{if(!0===r.isCubeTexture||r.mapping===W||r.mapping===j||r.mapping===Ue){if(e.backgroundBlurriness>0||r.mapping===Ue)return eg(r);{let e;return e=!0===r.isCubeTexture?El(r):Eu(r),Ah(e)}}if(!0===r.isTexture)return Eu(r,Ec.flipY()).setUpdateMatrix(!0);!0!==r.isColor&&console.error("WebGPUNodes: Unsupported background configuration.",r)}),s);t.backgroundNode=i,t.background=r,t.backgroundBlurriness=e.backgroundBlurriness}}else t.backgroundNode&&(delete t.backgroundNode,delete t.background)}getCacheNode(e,t,r,s=!1){const i=this.cacheLib[e]||(this.cacheLib[e]=new WeakMap);let n=i.get(t);return(void 0===n||s)&&(n=r(),i.set(t,n)),n}updateFog(e){const t=this.get(e),r=e.fog;if(r){if(t.fog!==r){const e=this.getCacheNode("fog",r,(()=>{if(r.isFogExp2){const e=Dl("color","color",r).setGroup(rn),t=Dl("density","float",r).setGroup(rn);return wy(e,Ey(t))}if(r.isFog){const e=Dl("color","color",r).setGroup(rn),t=Dl("near","float",r).setGroup(rn),s=Dl("far","float",r).setGroup(rn);return wy(e,Cy(t,s))}console.error("THREE.Renderer: Unsupported fog configuration.",r)}));t.fogNode=e,t.fog=r}}else delete t.fogNode,delete t.fog}updateEnvironment(e){const t=this.get(e),r=e.environment;if(r){if(t.environment!==r){const e=this.getCacheNode("environment",r,(()=>!0===r.isCubeTexture?El(r):!0===r.isTexture?Eu(r):void console.error("Nodes: Unsupported environment configuration.",r)));t.environmentNode=e,t.environment=r}}else t.environmentNode&&(delete t.environmentNode,delete t.environment)}getNodeFrame(e=this.renderer,t=null,r=null,s=null,i=null){const n=this.nodeFrame;return n.renderer=e,n.scene=t,n.object=r,n.camera=s,n.material=i,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 e_.get(e)!==this.getOutputCacheKey()}getOutputNode(e){const t=this.renderer,r=this.getOutputCacheKey(),s=Eu(e,Ec).renderOutput(t.toneMapping,t.currentColorSpace);return e_.set(e,r),s}updateBefore(e){const t=e.getNodeBuilderState();for(const r of t.updateBeforeNodes)this.getNodeFrameForRender(e).updateBeforeNode(r)}updateAfter(e){const t=e.getNodeBuilderState();for(const r of t.updateAfterNodes)this.getNodeFrameForRender(e).updateAfterNode(r)}updateForCompute(e){const t=this.getNodeFrame(),r=this.getForCompute(e);for(const e of r.updateNodes)t.updateNode(e)}updateForRender(e){const t=this.getNodeFrameForRender(e),r=e.getNodeBuilderState();for(const e of r.updateNodes)t.updateNode(e)}needsRefresh(e){const t=this.getNodeFrameForRender(e);return e.getMonitor().needsRefresh(e,t)}dispose(){super.dispose(),this.nodeFrame=new IT,this.nodeBuilderCache=new Map,this.cacheLib={}}}const i_=new fe;class n_{constructor(e=null){this.version=0,this.clipIntersection=null,this.cacheKey="",this.shadowPass=!1,this.viewNormalMatrix=new i,this.clippingGroupContexts=new WeakMap,this.intersectionPlanes=[],this.unionPlanes=[],this.parentVersion=null,null!==e&&(this.viewNormalMatrix=e.viewNormalMatrix,this.clippingGroupContexts=e.clippingGroupContexts,this.shadowPass=e.shadowPass,this.viewMatrix=e.viewMatrix)}projectPlanes(e,t,r){const s=e.length;for(let i=0;i{await this.compileAsync(e,t);const s=this._renderLists.get(e,t),i=this._renderContexts.get(e,t,this._renderTarget),n=e.overrideMaterial||r.material,o=this._objects.get(r,n,e,t,s.lightsNode,i,i.clippingContext),{fragmentShader:a,vertexShader:u}=o.getNodeBuilderState();return{fragmentShader:a,vertexShader:u}}}}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 r=this.backend;try{await r.init(this)}catch(e){if(null===this._getFallback)return void t(e);try{this.backend=r=this._getFallback(e),await r.init(this)}catch(e){return void t(e)}}this._nodes=new s_(this,r),this._animation=new Ug(this._nodes,this.info),this._attributes=new Hg(r),this._background=new Vx(this,this._nodes),this._geometries=new qg(this._attributes,this.info),this._textures=new fm(this,r,this.info),this._pipelines=new em(r,this._nodes),this._bindings=new tm(r,this._nodes,this._textures,this._attributes,this._pipelines,this.info),this._objects=new Lg(this,this._nodes,this._geometries,this._pipelines,this._bindings,this.info),this._renderLists=new am(this.lighting),this._bundles=new u_,this._renderContexts=new gm,this._animation.start(),this._initialized=!0,e()}))),this._initPromise}get coordinateSystem(){return this.backend.coordinateSystem}async compileAsync(e,t,r=null){if(!0===this._isDeviceLost)return;!1===this._initialized&&await this.init();const s=this._nodes.nodeFrame,i=s.renderId,n=this._currentRenderContext,o=this._currentRenderObjectFunction,a=this._compilationPromises,u=!0===e.isScene?e:p_;null===r&&(r=e);const l=this._renderTarget,d=this._renderContexts.get(r,t,l),c=this._activeMipmapLevel,h=[];this._currentRenderContext=d,this._currentRenderObjectFunction=this.renderObject,this._handleObjectFunction=this._createObjectPipeline,this._compilationPromises=h,s.renderId++,s.update(),d.depth=this.depth,d.stencil=this.stencil,d.clippingContext||(d.clippingContext=new n_),d.clippingContext.updateGlobal(u,t),u.onBeforeRender(this,e,t,l);const p=this._renderLists.get(e,t);if(p.begin(),this._projectObject(e,t,0,p,d.clippingContext),r!==e&&r.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);d.textures=e.textures,d.depthTexture=e.depthTexture}else d.textures=null,d.depthTexture=null;this._background.update(u,p,d);const g=p.opaque,m=p.transparent,f=p.transparentDoublePass,y=p.lightsNode;!0===this.opaque&&g.length>0&&this._renderObjects(g,t,u,y),!0===this.transparent&&m.length>0&&this._renderTransparents(m,f,t,u,y),s.renderId=i,this._currentRenderContext=n,this._currentRenderObjectFunction=o,this._compilationPromises=a,this._handleObjectFunction=this._renderObjectDirect,await Promise.all(h)}async renderAsync(e,t){!1===this._initialized&&await this.init();const r=this._renderScene(e,t);await this.backend.resolveTimestampAsync(r,"render")}async waitForGPU(){await this.backend.waitForGPU()}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}_onDeviceLost(e){let t=`THREE.WebGPURenderer: ${e.api} Device Lost:\n\nMessage: ${e.message}`;e.reason&&(t+=`\nReason: ${e.reason}`),console.error(t),this._isDeviceLost=!0}_renderBundle(e,t,r){const{bundleGroup:s,camera:i,renderList:n}=e,o=this._currentRenderContext,a=this._bundles.get(s,i),u=this.backend.get(a);void 0===u.renderContexts&&(u.renderContexts=new Set);const l=s.version!==u.version,d=!1===u.renderContexts.has(o)||l;if(u.renderContexts.add(o),d){this.backend.beginBundle(o),(void 0===u.renderObjects||l)&&(u.renderObjects=[]),this._currentRenderBundle=a;const e=n.opaque;!0===this.opaque&&e.length>0&&this._renderObjects(e,i,t,r),this._currentRenderBundle=null,this.backend.finishBundle(o,a),u.version=s.version}else{const{renderObjects:e}=u;for(let t=0,r=e.length;t>=c,p.viewportValue.height>>=c,p.viewportValue.minDepth=b,p.viewportValue.maxDepth=x,p.viewport=!1===p.viewportValue.equals(m_),p.scissorValue.copy(f).multiplyScalar(y).floor(),p.scissor=this._scissorTest&&!1===p.scissorValue.equals(m_),p.scissorValue.width>>=c,p.scissorValue.height>>=c,p.clippingContext||(p.clippingContext=new n_),p.clippingContext.updateGlobal(u,t),u.onBeforeRender(this,e,t,h),y_.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),f_.setFromProjectionMatrix(y_,g);const T=this._renderLists.get(e,t);if(T.begin(),this._projectObject(e,t,0,T,p.clippingContext),T.finish(),!0===this.sortObjects&&T.sort(this._opaqueSort,this._transparentSort),null!==h){this._textures.updateRenderTarget(h,c);const e=this._textures.get(h);p.textures=e.textures,p.depthTexture=e.depthTexture,p.width=e.width,p.height=e.height,p.renderTarget=h,p.depth=h.depthBuffer,p.stencil=h.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=d,p.activeMipmapLevel=c,p.occlusionQueryCount=T.occlusionQueryCount,this._background.update(u,T,p),this.backend.beginRender(p);const{bundles:_,lightsNode:v,transparentDoublePass:N,transparent:S,opaque:A}=T;if(_.length>0&&this._renderBundles(_,u,v),!0===this.opaque&&A.length>0&&this._renderObjects(A,t,u,v),!0===this.transparent&&S.length>0&&this._renderTransparents(S,N,t,u,v),this.backend.finishRender(p),i.renderId=n,this._currentRenderContext=o,this._currentRenderObjectFunction=a,null!==s){this.setRenderTarget(l,d,c);const e=this._quad;this._nodes.hasOutputChange(h.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(h.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}return u.onAfterRender(this,e,t,h),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._pixelRatio=e,this.setSize(this._width,this._height,!1))}setDrawingBufferSize(e,t,r){this._width=e,this._height=t,this._pixelRatio=r,this.domElement.width=Math.floor(e*r),this.domElement.height=Math.floor(t*r),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setSize(e,t,r=!0){this._width=e,this._height=t,this.domElement.width=Math.floor(e*this._pixelRatio),this.domElement.height=Math.floor(t*this._pixelRatio),!0===r&&(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,r,s){const i=this._scissor;e.isVector4?i.copy(e):i.set(e,t,r,s)}getScissorTest(){return this._scissorTest}setScissorTest(e){this._scissorTest=e,this.backend.setScissorTest(e)}getViewport(e){return e.copy(this._viewport)}setViewport(e,t,r,s,i=0,n=1){const o=this._viewport;e.isVector4?o.copy(e):o.set(e,t,r,s),o.minDepth=i,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,r=!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,r);const s=this._renderTarget||this._getFrameBufferTarget();let i=null;if(null!==s){this._textures.updateRenderTarget(s);const e=this._textures.get(s);i=this._renderContexts.getForClear(s),i.textures=e.textures,i.depthTexture=e.depthTexture,i.width=e.width,i.height=e.height,i.renderTarget=s,i.depth=s.depthBuffer,i.stencil=s.stencilBuffer}if(this.backend.clear(e,t,r,i),null!==s&&null===this._renderTarget){const e=this._quad;this._nodes.hasOutputChange(s.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(s.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,r=!0){!1===this._initialized&&await this.init(),this.clear(e,t,r)}async clearColorAsync(){this.clearAsync(!0,!1,!1)}async clearDepthAsync(){this.clearAsync(!1,!0,!1)}async clearStencilAsync(){this.clearAsync(!1,!1,!0)}get currentToneMapping(){return null!==this._renderTarget?h:this.toneMapping}get currentColorSpace(){return null!==this._renderTarget?Re:this.outputColorSpace}dispose(){this.info.dispose(),this.backend.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,r=0){this._renderTarget=e,this._activeCubeFace=t,this._activeMipmapLevel=r}getRenderTarget(){return this._renderTarget}setRenderObjectFunction(e){this._renderObjectFunction=e}getRenderObjectFunction(){return this._renderObjectFunction}compute(e){if(!0===this._isDeviceLost)return;if(!1===this._initialized)return console.warn("THREE.Renderer: .compute() called before the backend is initialized. Try using .computeAsync() instead."),this.computeAsync(e);const t=this._nodes.nodeFrame,r=t.renderId;this.info.calls++,this.info.compute.calls++,this.info.compute.frameCalls++,t.renderId=this.info.calls;const s=this.backend,i=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.");s.beginCompute(e);for(const t of a){if(!1===i.has(t)){const e=()=>{t.removeEventListener("dispose",e),i.delete(t),n.delete(t),o.delete(t)};t.addEventListener("dispose",e);const r=t.onInitFunction;null!==r&&r.call(t,{renderer:this})}o.updateForCompute(t),n.updateForCompute(t);const r=n.getForCompute(t),a=i.getForCompute(t,r);s.compute(e,t,r,a)}s.finishCompute(e),t.renderId=r}async computeAsync(e){!1===this._initialized&&await this.init(),this.compute(e),await this.backend.resolveTimestampAsync(e,"compute")}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)}hasInitialized(){return this._initialized}async initTextureAsync(e){!1===this._initialized&&await this.init(),this._textures.updateTexture(e)}initTexture(e){!1===this._initialized&&console.warn("THREE.Renderer: .initTexture() called before the backend is initialized. Try using .initTextureAsync() instead."),this._textures.updateTexture(e)}copyFramebufferToTexture(e,t=null){if(null!==t)if(t.isVector2)t=b_.set(t.x,t.y,e.image.width,e.image.height).floor();else{if(!t.isVector4)return void console.error("THREE.Renderer.copyFramebufferToTexture: Invalid rectangle.");t=b_.copy(t).floor()}else t=b_.set(0,0,e.image.width,e.image.height);let r,s=this._currentRenderContext;null!==s?r=s.renderTarget:(r=this._renderTarget||this._getFrameBufferTarget(),null!==r&&(this._textures.updateRenderTarget(r),s=this._textures.get(r))),this._textures.updateTexture(e,{renderTarget:r}),this.backend.copyFramebufferToTexture(e,s,t)}copyTextureToTexture(e,t,r=null,s=null,i=0){this._textures.updateTexture(e),this._textures.updateTexture(t),this.backend.copyTextureToTexture(e,t,r,s,i)}async readRenderTargetPixelsAsync(e,t,r,s,i,n=0,o=0){return this.backend.copyTextureToBuffer(e.textures[n],t,r,s,i,o)}_projectObject(e,t,r,s,i){if(!1===e.visible)return;if(e.layers.test(t.layers))if(e.isGroup)r=e.renderOrder,e.isClippingGroup&&e.enabled&&(i=i.getGroupContext(e));else if(e.isLOD)!0===e.autoUpdate&&e.update(t);else if(e.isLight)s.pushLight(e);else if(e.isSprite){if(!e.frustumCulled||f_.intersectsSprite(e)){!0===this.sortObjects&&b_.setFromMatrixPosition(e.matrixWorld).applyMatrix4(y_);const{geometry:t,material:n}=e;n.visible&&s.push(e,t,n,r,b_.z,null,i)}}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||f_.intersectsObject(e))){const{geometry:t,material:n}=e;if(!0===this.sortObjects&&(null===t.boundingSphere&&t.computeBoundingSphere(),b_.copy(t.boundingSphere.center).applyMatrix4(e.matrixWorld).applyMatrix4(y_)),Array.isArray(n)){const o=t.groups;for(let a=0,u=o.length;a0){for(const{material:e}of t)e.side=T;this._renderObjects(t,r,s,i,"backSide");for(const{material:e}of t)e.side=ke;this._renderObjects(e,r,s,i);for(const{material:e}of t)e.side=le}else this._renderObjects(e,r,s,i)}_renderObjects(e,t,r,s,i=null){for(let n=0,o=e.length;n0,e.isShadowPassMaterial&&(e.side=null===i.shadowSide?i.side:i.shadowSide,i.depthNode&&i.depthNode.isNode&&(c=e.depthNode,e.depthNode=i.depthNode),i.castShadowNode&&i.castShadowNode.isNode&&(d=e.colorNode,e.colorNode=i.castShadowNode)),i=e}!0===i.transparent&&i.side===le&&!1===i.forceSinglePass?(i.side=T,this._handleObjectFunction(e,i,t,r,o,n,a,"backSide"),i.side=ke,this._handleObjectFunction(e,i,t,r,o,n,a,u),i.side=le):this._handleObjectFunction(e,i,t,r,o,n,a,u),void 0!==l&&(t.overrideMaterial.positionNode=l),void 0!==c&&(t.overrideMaterial.depthNode=c),void 0!==d&&(t.overrideMaterial.colorNode=d),e.onAfterRender(this,t,r,s,i,n)}_renderObjectDirect(e,t,r,s,i,n,o,a){const u=this._objects.get(e,t,r,s,i,this._currentRenderContext,o,a);u.drawRange=e.geometry.drawRange,u.group=n;const l=this._nodes.needsRefresh(u);if(l&&(this._nodes.updateBefore(u),this._geometries.updateForRender(u),this._nodes.updateForRender(u),this._bindings.updateForRender(u)),this._pipelines.updateForRender(u),null!==this._currentRenderBundle){this.backend.get(this._currentRenderBundle).renderObjects.push(u),u.bundle=this._currentRenderBundle.bundleGroup}this.backend.draw(u,this.info),l&&this._nodes.updateAfter(u)}_createObjectPipeline(e,t,r,s,i,n,o,a){const u=this._objects.get(e,t,r,s,i,this._currentRenderContext,o,a);u.drawRange=e.geometry.drawRange,u.group=n,this._nodes.updateBefore(u),this._geometries.updateForRender(u),this._nodes.updateForRender(u),this._bindings.updateForRender(u),this._pipelines.getForRender(u,this._compilationPromises),this._nodes.updateAfter(u)}get compile(){return this.compileAsync}}class T_{constructor(e=""){this.name=e,this.visibility=0}setVisibility(e){this.visibility|=e}clone(){return Object.assign(new this.constructor,this)}}class __ extends T_{constructor(e,t=null){super(e),this.isBuffer=!0,this.bytesPerElement=Float32Array.BYTES_PER_ELEMENT,this._buffer=t}get byteLength(){return(e=this._buffer.byteLength)+($g-e%$g)%$g;var e}get buffer(){return this._buffer}update(){return!0}}class v_ extends __{constructor(e,t=null){super(e,t),this.isUniformBuffer=!0}}let N_=0;class S_ extends v_{constructor(e,t){super("UniformBuffer_"+N_++,e?e.value:null),this.nodeUniform=e,this.groupNode=t}get buffer(){return this.nodeUniform.value}}class A_ extends v_{constructor(e){super(e),this.isUniformsGroup=!0,this._values=null,this.uniforms=[]}addUniform(e){return this.uniforms.push(e),this}removeUniform(e){const t=this.uniforms.indexOf(e);return-1!==t&&this.uniforms.splice(t,1),this}get values(){return null===this._values&&(this._values=Array.from(this.buffer)),this._values}get buffer(){let e=this._buffer;if(null===e){const t=this.byteLength;e=new Float32Array(new ArrayBuffer(t)),this._buffer=e}return e}get byteLength(){let e=0;for(let t=0,r=this.uniforms.length;t0?s:"";t=`${e.name} {\n\t${r} ${i.name}[${n}];\n};\n`}else{t=`${this.getVectorType(i.type)} ${this.getPropertyName(i,e)};`,n=!0}const o=i.node.precision;if(null!==o&&(t=P_[o]+" "+t),n){t="\t"+t;const e=i.groupNode.name;(s[e]||(s[e]=[])).push(t)}else t="uniform "+t,r.push(t)}let i="";for(const t in s){const r=s[t];i+=this._getGLSLUniformStruct(e+"_"+t,r.join("\n"))+"\n"}return i+=r.join("\n"),i}getTypeFromAttribute(e){let t=super.getTypeFromAttribute(e);if(/^[iu]/.test(t)&&e.gpuType!==x){let r=e;e.isInterleavedBufferAttribute&&(r=e.data);const s=r.array;!1==(s instanceof Uint32Array||s instanceof Int32Array)&&(t=t.slice(1))}return t}getAttributes(e){let t="";if("vertex"===e||"compute"===e){const e=this.getAttributesArray();let r=0;for(const s of e)t+=`layout( location = ${r++} ) in ${s.type} ${s.name};\n`}return t}getStructMembers(e){const t=[],r=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,r=this.shaderStage){const s=this.extensions[r]||(this.extensions[r]=new Map);!1===s.has(e)&&s.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 r=this.extensions[e];if(void 0!==r)for(const{name:e,behavior:s}of r.values())t.push(`#extension ${e} : ${s}`);return t.join("\n")}getClipDistance(){return"gl_ClipDistance"}isAvailable(e){let t=I_[e];if(void 0===t){let r;switch(t=!1,e){case"float32Filterable":r="OES_texture_float_linear";break;case"clipDistance":r="WEBGL_clip_cull_distance"}if(void 0!==r){const e=this.renderer.backend.extensions;e.has(r)&&(e.get(r),t=!0)}I_[e]=t}return t}isFlipY(){return!0}enableHardwareClipping(e){this.enableExtension("GL_ANGLE_clip_cull_distance","require"),this.builtins.vertex.push(`out float gl_ClipDistance[ ${e} ]`)}registerTransform(e,t){this.transforms.push({varyingName:e,attributeNode:t})}getTransforms(){const e=this.transforms;let t="";for(let r=0;r0&&(r+="\n"),r+=`\t// flow -> ${n}\n\t`),r+=`${s.code}\n\t`,e===i&&"compute"!==t&&(r+="// result\n\t","vertex"===t?(r+="gl_Position = ",r+=`${s.result};`):"fragment"===t&&(e.outputNode.isOutputStructNode||(r+="fragColor = ",r+=`${s.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=r}null!==this.material?(this.vertexShader=this._getGLSLVertexCode(e.vertex),this.fragmentShader=this._getGLSLFragmentCode(e.fragment)):this.computeShader=this._getGLSLVertexCode(e.compute)}getUniformFromNode(e,t,r,s=null){const i=super.getUniformFromNode(e,t,r,s),n=this.getDataFromNode(e,r,this.globalCache);let o=n.uniformGPU;if(void 0===o){const s=e.groupNode,a=s.name,u=this.getBindGroupArray(a,r);if("texture"===t)o=new M_(i.name,i.node,s),u.push(o);else if("cubeTexture"===t)o=new B_(i.name,i.node,s),u.push(o);else if("texture3D"===t)o=new U_(i.name,i.node,s),u.push(o);else if("buffer"===t){e.name=`NodeBuffer_${e.id}`,i.name=`buffer${e.id}`;const t=new S_(e,s);t.name=e.name,u.push(t),o=t}else{const e=this.uniformGroups[r]||(this.uniformGroups[r]={});let n=e[a];void 0===n&&(n=new C_(r+"_"+a,s),e[a]=n,u.push(n)),o=this.getNodeUniform(i,t),n.addUniform(o)}n.uniformGPU=o}return i}}let V_=null,O_=null;class G_{constructor(e={}){this.parameters=Object.assign({},e),this.data=new WeakMap,this.renderer=null,this.domElement=null}async init(e){this.renderer=e}get coordinateSystem(){}beginRender(){}finishRender(){}beginCompute(){}finishCompute(){}draw(){}compute(){}createProgram(){}destroyProgram(){}createBindings(){}updateBindings(){}updateBinding(){}createRenderPipeline(){}createComputePipeline(){}needsRenderUpdate(){}getRenderCacheKey(){}createNodeBuilder(){}createSampler(){}destroySampler(){}createDefaultTexture(){}createTexture(){}updateTexture(){}generateMipmaps(){}destroyTexture(){}async copyTextureToBuffer(){}copyTextureToTexture(){}copyFramebufferToTexture(){}createAttribute(){}createIndexAttribute(){}createStorageAttribute(){}updateAttribute(){}destroyAttribute(){}getContext(){}updateSize(){}updateViewport(){}isOccluded(){}async resolveTimestampAsync(){}async waitForGPU(){}async getArrayBufferAsync(){}async hasFeatureAsync(){}hasFeature(){}getMaxAnisotropy(){}getDrawingBufferSize(){return V_=V_||new t,this.renderer.getDrawingBufferSize(V_)}setScissorTest(){}getClearColor(){const e=this.renderer;return O_=O_||new ym,e.getClearColor(O_),O_.getRGB(O_,this.renderer.currentColorSpace),O_}getDomElement(){let e=this.domElement;return null===e&&(e=void 0!==this.parameters.canvas?this.parameters.canvas:Je(),"setAttribute"in e&&e.setAttribute("data-engine",`three.js r${Ve} webgpu`),this.domElement=e),e}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)}dispose(){}}let k_=0;class z_{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 $_{constructor(e){this.backend=e}createAttribute(e,t){const r=this.backend,{gl:s}=r,i=e.array,n=e.usage||s.STATIC_DRAW,o=e.isInterleavedBufferAttribute?e.data:e,a=r.get(o);let u,l=a.bufferGPU;if(void 0===l&&(l=this._createBuffer(s,t,i,n),a.bufferGPU=l,a.bufferType=t,a.version=o.version),i instanceof Float32Array)u=s.FLOAT;else if(i instanceof Uint16Array)u=e.isFloat16BufferAttribute?s.HALF_FLOAT:s.UNSIGNED_SHORT;else if(i instanceof Int16Array)u=s.SHORT;else if(i instanceof Uint32Array)u=s.UNSIGNED_INT;else if(i instanceof Int32Array)u=s.INT;else if(i instanceof Int8Array)u=s.BYTE;else if(i instanceof Uint8Array)u=s.UNSIGNED_BYTE;else{if(!(i instanceof Uint8ClampedArray))throw new Error("THREE.WebGLBackend: Unsupported buffer data format: "+i);u=s.UNSIGNED_BYTE}let d={bufferGPU:l,bufferType:t,type:u,byteLength:i.byteLength,bytesPerElement:i.BYTES_PER_ELEMENT,version:e.version,pbo:e.pbo,isInteger:u===s.INT||u===s.UNSIGNED_INT||e.gpuType===x,id:k_++};if(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute){const e=this._createBuffer(s,t,i,n);d=new z_(d,e)}r.set(e,d)}updateAttribute(e){const t=this.backend,{gl:r}=t,s=e.array,i=e.isInterleavedBufferAttribute?e.data:e,n=t.get(i),o=n.bufferType,a=e.isInterleavedBufferAttribute?e.data.updateRanges:e.updateRanges;if(r.bindBuffer(o,n.bufferGPU),0===a.length)r.bufferSubData(o,0,s);else{for(let e=0,t=a.length;e1?this.enable(s.SAMPLE_ALPHA_TO_COVERAGE):this.disable(s.SAMPLE_ALPHA_TO_COVERAGE),r>0&&this.currentClippingPlanes!==r){const e=12288;for(let t=0;t<8;t++)t{!function i(){const n=e.clientWaitSync(t,e.SYNC_FLUSH_COMMANDS_BIT,0);if(n===e.WAIT_FAILED)return e.deleteSync(t),void s();n!==e.TIMEOUT_EXPIRED?(e.deleteSync(t),r()):requestAnimationFrame(i)}()}))}}let X_,Y_,Q_,Z_=!1;class J_{constructor(e){this.backend=e,this.gl=e.gl,this.extensions=e.extensions,this.defaultTextures={},!1===Z_&&(this._init(),Z_=!0)}_init(){const e=this.gl;X_={[cr]:e.REPEAT,[hr]:e.CLAMP_TO_EDGE,[pr]:e.MIRRORED_REPEAT},Y_={[gr]:e.NEAREST,[mr]:e.NEAREST_MIPMAP_NEAREST,[De]:e.NEAREST_MIPMAP_LINEAR,[z]:e.LINEAR,[Ie]:e.LINEAR_MIPMAP_NEAREST,[M]:e.LINEAR_MIPMAP_LINEAR},Q_={[fr]:e.NEVER,[yr]:e.ALWAYS,[Ce]:e.LESS,[br]:e.LEQUAL,[xr]:e.EQUAL,[Tr]:e.GEQUAL,[_r]:e.GREATER,[vr]:e.NOTEQUAL}}getGLTextureType(e){const{gl:t}=this;let r;return r=!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,r}getInternalFormat(e,t,r,s,i=!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&&(r===n.FLOAT&&(a=n.R32F),r===n.HALF_FLOAT&&(a=n.R16F),r===n.UNSIGNED_BYTE&&(a=n.R8),r===n.UNSIGNED_SHORT&&(a=n.R16),r===n.UNSIGNED_INT&&(a=n.R32UI),r===n.BYTE&&(a=n.R8I),r===n.SHORT&&(a=n.R16I),r===n.INT&&(a=n.R32I)),t===n.RED_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.R8UI),r===n.UNSIGNED_SHORT&&(a=n.R16UI),r===n.UNSIGNED_INT&&(a=n.R32UI),r===n.BYTE&&(a=n.R8I),r===n.SHORT&&(a=n.R16I),r===n.INT&&(a=n.R32I)),t===n.RG&&(r===n.FLOAT&&(a=n.RG32F),r===n.HALF_FLOAT&&(a=n.RG16F),r===n.UNSIGNED_BYTE&&(a=n.RG8),r===n.UNSIGNED_SHORT&&(a=n.RG16),r===n.UNSIGNED_INT&&(a=n.RG32UI),r===n.BYTE&&(a=n.RG8I),r===n.SHORT&&(a=n.RG16I),r===n.INT&&(a=n.RG32I)),t===n.RG_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RG8UI),r===n.UNSIGNED_SHORT&&(a=n.RG16UI),r===n.UNSIGNED_INT&&(a=n.RG32UI),r===n.BYTE&&(a=n.RG8I),r===n.SHORT&&(a=n.RG16I),r===n.INT&&(a=n.RG32I)),t===n.RGB&&(r===n.FLOAT&&(a=n.RGB32F),r===n.HALF_FLOAT&&(a=n.RGB16F),r===n.UNSIGNED_BYTE&&(a=n.RGB8),r===n.UNSIGNED_SHORT&&(a=n.RGB16),r===n.UNSIGNED_INT&&(a=n.RGB32UI),r===n.BYTE&&(a=n.RGB8I),r===n.SHORT&&(a=n.RGB16I),r===n.INT&&(a=n.RGB32I),r===n.UNSIGNED_BYTE&&(a=s===Oe&&!1===i?n.SRGB8:n.RGB8),r===n.UNSIGNED_SHORT_5_6_5&&(a=n.RGB565),r===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1),r===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGB4),r===n.UNSIGNED_INT_5_9_9_9_REV&&(a=n.RGB9_E5)),t===n.RGB_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RGB8UI),r===n.UNSIGNED_SHORT&&(a=n.RGB16UI),r===n.UNSIGNED_INT&&(a=n.RGB32UI),r===n.BYTE&&(a=n.RGB8I),r===n.SHORT&&(a=n.RGB16I),r===n.INT&&(a=n.RGB32I)),t===n.RGBA&&(r===n.FLOAT&&(a=n.RGBA32F),r===n.HALF_FLOAT&&(a=n.RGBA16F),r===n.UNSIGNED_BYTE&&(a=n.RGBA8),r===n.UNSIGNED_SHORT&&(a=n.RGBA16),r===n.UNSIGNED_INT&&(a=n.RGBA32UI),r===n.BYTE&&(a=n.RGBA8I),r===n.SHORT&&(a=n.RGBA16I),r===n.INT&&(a=n.RGBA32I),r===n.UNSIGNED_BYTE&&(a=s===Oe&&!1===i?n.SRGB8_ALPHA8:n.RGBA8),r===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGBA4),r===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1)),t===n.RGBA_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RGBA8UI),r===n.UNSIGNED_SHORT&&(a=n.RGBA16UI),r===n.UNSIGNED_INT&&(a=n.RGBA32UI),r===n.BYTE&&(a=n.RGBA8I),r===n.SHORT&&(a=n.RGBA16I),r===n.INT&&(a=n.RGBA32I)),t===n.DEPTH_COMPONENT&&(r===n.UNSIGNED_INT&&(a=n.DEPTH24_STENCIL8),r===n.FLOAT&&(a=n.DEPTH_COMPONENT32F)),t===n.DEPTH_STENCIL&&r===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:r,extensions:s,backend:i}=this;r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,t.flipY),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,t.premultiplyAlpha),r.pixelStorei(r.UNPACK_ALIGNMENT,t.unpackAlignment),r.pixelStorei(r.UNPACK_COLORSPACE_CONVERSION_WEBGL,r.NONE),r.texParameteri(e,r.TEXTURE_WRAP_S,X_[t.wrapS]),r.texParameteri(e,r.TEXTURE_WRAP_T,X_[t.wrapT]),e!==r.TEXTURE_3D&&e!==r.TEXTURE_2D_ARRAY||r.texParameteri(e,r.TEXTURE_WRAP_R,X_[t.wrapR]),r.texParameteri(e,r.TEXTURE_MAG_FILTER,Y_[t.magFilter]);const n=void 0!==t.mipmaps&&t.mipmaps.length>0,o=t.minFilter===z&&n?M:t.minFilter;if(r.texParameteri(e,r.TEXTURE_MIN_FILTER,Y_[o]),t.compareFunction&&(r.texParameteri(e,r.TEXTURE_COMPARE_MODE,r.COMPARE_REF_TO_TEXTURE),r.texParameteri(e,r.TEXTURE_COMPARE_FUNC,Q_[t.compareFunction])),!0===s.has("EXT_texture_filter_anisotropic")){if(t.magFilter===gr)return;if(t.minFilter!==De&&t.minFilter!==M)return;if(t.type===E&&!1===s.has("OES_texture_float_linear"))return;if(t.anisotropy>1){const n=s.get("EXT_texture_filter_anisotropic");r.texParameterf(e,n.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(t.anisotropy,i.getMaxAnisotropy()))}}}createDefaultTexture(e){const{gl:t,backend:r,defaultTextures:s}=this,i=this.getGLTextureType(e);let n=s[i];void 0===n&&(n=t.createTexture(),r.state.bindTexture(i,n),t.texParameteri(i,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(i,t.TEXTURE_MAG_FILTER,t.NEAREST),s[i]=n),r.set(e,{textureGPU:n,glTextureType:i,isDefault:!0})}createTexture(e,t){const{gl:r,backend:s}=this,{levels:i,width:n,height:o,depth:a}=t,u=s.utils.convert(e.format,e.colorSpace),l=s.utils.convert(e.type),d=this.getInternalFormat(e.internalFormat,u,l,e.colorSpace,e.isVideoTexture),c=r.createTexture(),h=this.getGLTextureType(e);s.state.bindTexture(h,c),this.setTextureParameters(h,e),e.isDataArrayTexture||e.isCompressedArrayTexture?r.texStorage3D(r.TEXTURE_2D_ARRAY,i,d,n,o,a):e.isData3DTexture?r.texStorage3D(r.TEXTURE_3D,i,d,n,o,a):e.isVideoTexture||r.texStorage2D(h,i,d,n,o),s.set(e,{textureGPU:c,glTextureType:h,glFormat:u,glType:l,glInternalFormat:d})}copyBufferToTexture(e,t){const{gl:r,backend:s}=this,{textureGPU:i,glTextureType:n,glFormat:o,glType:a}=s.get(t),{width:u,height:l}=t.source.data;r.bindBuffer(r.PIXEL_UNPACK_BUFFER,e),s.state.bindTexture(n,i),r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,!1),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),r.texSubImage2D(n,0,0,0,u,l,o,a,0),r.bindBuffer(r.PIXEL_UNPACK_BUFFER,null),s.state.unbindTexture()}updateTexture(e,t){const{gl:r}=this,{width:s,height:i}=t,{textureGPU:n,glTextureType:o,glFormat:a,glType:u,glInternalFormat:l}=this.backend.get(e);if(e.isRenderTargetTexture||void 0===n)return;const d=e=>e.isDataTexture?e.image.data:"undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap||e instanceof OffscreenCanvas?e:e.data;if(this.backend.state.bindTexture(o,n),this.setTextureParameters(o,e),e.isCompressedTexture){const s=e.mipmaps,i=t.image;for(let t=0;t0,c=t.renderTarget?t.renderTarget.height:this.backend.getDrawingBufferSize().y;if(d){const r=0!==o||0!==a;let d,h;if(!0===e.isDepthTexture?(d=s.DEPTH_BUFFER_BIT,h=s.DEPTH_ATTACHMENT,t.stencil&&(d|=s.STENCIL_BUFFER_BIT)):(d=s.COLOR_BUFFER_BIT,h=s.COLOR_ATTACHMENT0),r){const e=this.backend.get(t.renderTarget),r=e.framebuffers[t.getCacheKey()],h=e.msaaFrameBuffer;i.bindFramebuffer(s.DRAW_FRAMEBUFFER,r),i.bindFramebuffer(s.READ_FRAMEBUFFER,h);const p=c-a-l;s.blitFramebuffer(o,p,o+u,p+l,o,p,o+u,p+l,d,s.NEAREST),i.bindFramebuffer(s.READ_FRAMEBUFFER,r),i.bindTexture(s.TEXTURE_2D,n),s.copyTexSubImage2D(s.TEXTURE_2D,0,0,0,o,p,u,l),i.unbindTexture()}else{const e=s.createFramebuffer();i.bindFramebuffer(s.DRAW_FRAMEBUFFER,e),s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,h,s.TEXTURE_2D,n,0),s.blitFramebuffer(0,0,u,l,0,0,u,l,d,s.NEAREST),s.deleteFramebuffer(e)}}else i.bindTexture(s.TEXTURE_2D,n),s.copyTexSubImage2D(s.TEXTURE_2D,0,0,0,o,c-l-a,u,l),i.unbindTexture();e.generateMipmaps&&this.generateMipmaps(e),this.backend._setFramebuffer(t)}setupRenderBufferStorage(e,t){const{gl:r}=this,s=t.renderTarget,{samples:i,depthTexture:n,depthBuffer:o,stencilBuffer:a,width:u,height:l}=s;if(r.bindRenderbuffer(r.RENDERBUFFER,e),o&&!a){let t=r.DEPTH_COMPONENT24;i>0?(n&&n.isDepthTexture&&n.type===r.FLOAT&&(t=r.DEPTH_COMPONENT32F),r.renderbufferStorageMultisample(r.RENDERBUFFER,i,t,u,l)):r.renderbufferStorage(r.RENDERBUFFER,t,u,l),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,e)}else o&&a&&(i>0?r.renderbufferStorageMultisample(r.RENDERBUFFER,i,r.DEPTH24_STENCIL8,u,l):r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_STENCIL,u,l),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,e))}async copyTextureToBuffer(e,t,r,s,i,n){const{backend:o,gl:a}=this,{textureGPU:u,glFormat:l,glType:d}=this.backend.get(e),c=a.createFramebuffer();a.bindFramebuffer(a.READ_FRAMEBUFFER,c);const h=e.isCubeTexture?a.TEXTURE_CUBE_MAP_POSITIVE_X+n:a.TEXTURE_2D;a.framebufferTexture2D(a.READ_FRAMEBUFFER,a.COLOR_ATTACHMENT0,h,u,0);const p=this._getTypedArrayType(d),g=s*i*this._getBytesPerTexel(d,l),m=a.createBuffer();a.bindBuffer(a.PIXEL_PACK_BUFFER,m),a.bufferData(a.PIXEL_PACK_BUFFER,g,a.STREAM_READ),a.readPixels(t,r,s,i,l,d,0),a.bindBuffer(a.PIXEL_PACK_BUFFER,null),await o.utils._clientWaitAsync();const f=new p(g/p.BYTES_PER_ELEMENT);return a.bindBuffer(a.PIXEL_PACK_BUFFER,m),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:r}=this;let s=0;return e===r.UNSIGNED_BYTE&&(s=1),e!==r.UNSIGNED_SHORT_4_4_4_4&&e!==r.UNSIGNED_SHORT_5_5_5_1&&e!==r.UNSIGNED_SHORT_5_6_5&&e!==r.UNSIGNED_SHORT&&e!==r.HALF_FLOAT||(s=2),e!==r.UNSIGNED_INT&&e!==r.FLOAT||(s=4),t===r.RGBA?4*s:t===r.RGB?3*s:t===r.ALPHA?s:void 0}}class ev{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 tv{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 r=t.get("EXT_texture_filter_anisotropic");this.maxAnisotropy=e.getParameter(r.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else this.maxAnisotropy=0;return this.maxAnisotropy}}const rv={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 sv{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:r,mode:s,object:i,type:n,info:o,index:a}=this;0!==a?r.drawElements(s,t,n,e):r.drawArrays(s,e,t),o.update(i,t,s,1)}renderInstances(e,t,r){const{gl:s,mode:i,type:n,index:o,object:a,info:u}=this;0!==r&&(0!==o?s.drawElementsInstanced(i,t,n,e,r):s.drawArraysInstanced(i,e,t,r),u.update(a,t,i,r))}renderMultiDraw(e,t,r){const{extensions:s,mode:i,object:n,info:o}=this;if(0===r)return;const a=s.get("WEBGL_multi_draw");if(null===a)for(let s=0;s0)){const e=t.queryQueue.shift();this.initTimestampQuery(e)}}async resolveTimestampAsync(e,t="render"){if(!this.disjoint||!this.trackTimestamp)return;const r=this.get(e);r.gpuQueries||(r.gpuQueries=[]);for(let e=0;e0&&(r.currentOcclusionQueries=r.occlusionQueries,r.currentOcclusionQueryObjects=r.occlusionQueryObjects,r.lastOcclusionObject=null,r.occlusionQueries=new Array(s),r.occlusionQueryObjects=new Array(s),r.occlusionQueryIndex=0)}finishRender(e){const{gl:t,state:r}=this,s=this.get(e),i=s.previousContext,n=e.occlusionQueryCount;n>0&&(n>s.occlusionQueryIndex&&t.endQuery(t.ANY_SAMPLES_PASSED),this.resolveOccludedAsync(e));const o=e.textures;if(null!==o)for(let e=0;e0){const i=s.framebuffers[e.getCacheKey()],n=t.COLOR_BUFFER_BIT,o=s.msaaFrameBuffer,a=e.textures;r.bindFramebuffer(t.READ_FRAMEBUFFER,o),r.bindFramebuffer(t.DRAW_FRAMEBUFFER,i);for(let r=0;r{let o=0;for(let t=0;t1?f.renderInstances(x,y,b):f.render(x,y),a.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)}async copyTextureToBuffer(e,t,r,s,i,n){return this.textureUtils.copyTextureToBuffer(e,t,r,s,i,n)}createSampler(){}destroySampler(){}createNodeBuilder(e,t){return new L_(e,t)}createProgram(e){const t=this.gl,{stage:r,code:s}=e,i="fragment"===r?t.createShader(t.FRAGMENT_SHADER):t.createShader(t.VERTEX_SHADER);t.shaderSource(i,s),t.compileShader(i),this.set(e,{shaderGPU:i})}destroyProgram(e){this.delete(e)}createRenderPipeline(e,t){const r=this.gl,s=e.pipeline,{fragmentProgram:i,vertexProgram:n}=s,o=r.createProgram(),a=this.get(i).shaderGPU,u=this.get(n).shaderGPU;if(r.attachShader(o,a),r.attachShader(o,u),r.linkProgram(o),this.set(s,{programGPU:o,fragmentShader:a,vertexShader:u}),null!==t&&this.parallel){const i=new Promise((t=>{const i=this.parallel,n=()=>{r.getProgramParameter(o,i.COMPLETION_STATUS_KHR)?(this._completeCompile(e,s),t()):requestAnimationFrame(n)};n()}));t.push(i)}else this._completeCompile(e,s)}_handleSource(e,t){const r=e.split("\n"),s=[],i=Math.max(t-6,0),n=Math.min(t+6,r.length);for(let e=i;e":" "} ${i}: ${r[e]}`)}return s.join("\n")}_getShaderErrors(e,t,r){const s=e.getShaderParameter(t,e.COMPILE_STATUS),i=e.getShaderInfoLog(t).trim();if(s&&""===i)return"";const n=/ERROR: 0:(\d+)/.exec(i);if(n){const s=parseInt(n[1]);return r.toUpperCase()+"\n\n"+i+"\n\n"+this._handleSource(e.getShaderSource(t),s)}return i}_logProgramError(e,t,r){if(this.renderer.debug.checkShaderErrors){const s=this.gl,i=s.getProgramInfoLog(e).trim();if(!1===s.getProgramParameter(e,s.LINK_STATUS))if("function"==typeof this.renderer.debug.onShaderError)this.renderer.debug.onShaderError(s,e,r,t);else{const n=this._getShaderErrors(s,r,"vertex"),o=this._getShaderErrors(s,t,"fragment");console.error("THREE.WebGLProgram: Shader Error "+s.getError()+" - VALIDATE_STATUS "+s.getProgramParameter(e,s.VALIDATE_STATUS)+"\n\nProgram Info Log: "+i+"\n"+n+"\n"+o)}else""!==i&&console.warn("THREE.WebGLProgram: Program Info Log:",i)}}_completeCompile(e,t){const{state:r,gl:s}=this,i=this.get(t),{programGPU:n,fragmentShader:o,vertexShader:a}=i;!1===s.getProgramParameter(n,s.LINK_STATUS)&&this._logProgramError(n,o,a),r.useProgram(n);const u=e.getBindings();this._setupBindings(u,n),this.set(t,{programGPU:n})}createComputePipeline(e,t){const{state:r,gl:s}=this,i={stage:"fragment",code:"#version 300 es\nprecision highp float;\nvoid main() {}"};this.createProgram(i);const{computeProgram:n}=e,o=s.createProgram(),a=this.get(i).shaderGPU,u=this.get(n).shaderGPU,l=n.transforms,d=[],c=[];for(let e=0;erv[t]===e)),r=this.extensions;for(let e=0;e0){if(void 0===h){const s=[];h=t.createFramebuffer(),r.bindFramebuffer(t.FRAMEBUFFER,h);const i=[],l=e.textures;for(let r=0;r,\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:lv,stripIndexFormat:Rv},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:lv,stripIndexFormat:Rv},layout:"auto"}),this.flipYPipelines[e]=t),t}flipY(e,t,r=0){const s=t.format,{width:i,height:n}=t.size,o=this.getTransferPipeline(s),a=this.getFlipYPipeline(s),u=this.device.createTexture({size:{width:i,height:n,depthOrArrayLayers:1},format:s,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),l=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:xN,baseArrayLayer:r}),d=u.createView({baseMipLevel:0,mipLevelCount:1,dimension:xN,baseArrayLayer:0}),c=this.device.createCommandEncoder({}),h=(e,t,r)=>{const s=e.getBindGroupLayout(0),i=this.device.createBindGroup({layout:s,entries:[{binding:0,resource:this.flipYSampler},{binding:1,resource:t}]}),n=c.beginRenderPass({colorAttachments:[{view:r,loadOp:Tv,storeOp:bv,clearValue:[0,0,0,0]}]});n.setPipeline(e),n.setBindGroup(0,i),n.draw(4,1,0,0),n.end()};h(o,l,d),h(a,d,l),this.device.queue.submit([c.finish()]),u.destroy()}generateMipmaps(e,t,r=0){const s=this.get(e);void 0===s.useCount&&(s.useCount=0,s.layers=[]);const i=s.layers[r]||this._mipmapCreateBundles(e,t,r),n=this.device.createCommandEncoder({});this._mipmapRunBundles(n,i),this.device.queue.submit([n.finish()]),0!==s.useCount&&(s.layers[r]=i),s.useCount++}_mipmapCreateBundles(e,t,r){const s=this.getTransferPipeline(t.format),i=s.getBindGroupLayout(0);let n=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:xN,baseArrayLayer:r});const o=[];for(let a=1;a1;for(let o=0;o]*\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/i,VN=/([a-z_0-9]+)\s*:\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/gi,ON={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_depth_multisampled_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 GN extends KT{constructor(e){const{type:t,inputs:r,name:s,inputsCode:i,blockCode:n,outputType:o}=(e=>{const t=(e=e.trim()).match(LN);if(null!==t&&4===t.length){const r=t[2],s=[];let i=null;for(;null!==(i=VN.exec(r));)s.push({name:i[1],type:i[2]});const n=[];for(let e=0;e "+this.outputType:"";return`fn ${e} ( ${this.inputsCode.trim()} ) ${t}`+this.blockCode}}class kN extends qT{parseFunction(e){return new GN(e)}}const zN="undefined"!=typeof self?self.GPUShaderStage:{VERTEX:1,FRAGMENT:2,COMPUTE:4},$N={[Es.READ_ONLY]:"read",[Es.WRITE_ONLY]:"write",[Es.READ_WRITE]:"read_write"},HN={[cr]:"repeat",[hr]:"clamp",[pr]:"mirror"},WN={vertex:zN?zN.VERTEX:1,fragment:zN?zN.FRAGMENT:2,compute:zN?zN.COMPUTE:4},jN={instance:!0,swizzleAssign:!1,storageBuffer:!0},qN={"^^":"tsl_xor"},KN={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",mat3:"mat3x3",mat4:"mat4x4"},XN={},YN={tsl_xor:new my("fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }"),mod_float:new my("fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }"),mod_vec2:new my("fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }"),mod_vec3:new my("fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }"),mod_vec4:new my("fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }"),equals_bool:new my("fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }"),equals_bvec2:new my("fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }"),equals_bvec3:new my("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 my("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_float:new my("fn tsl_repeatWrapping_float( coord: f32 ) -> f32 { return fract( coord ); }"),mirrorWrapping_float:new my("fn tsl_mirrorWrapping_float( coord: f32 ) -> f32 { let mirrored = fract( coord * 0.5 ) * 2.0; return 1.0 - abs( 1.0 - mirrored ); }"),clampWrapping_float:new my("fn tsl_clampWrapping_float( coord: f32 ) -> f32 { return clamp( coord, 0.0, 1.0 ); }"),biquadraticTexture:new my("\nfn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, iRes : vec2u, level : u32 ) -> vec4f {\n\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, vec2u( iuv + vec2( 0.5, 0.5 ) ) % iRes, level );\n\tlet rg2 = textureLoad( map, vec2u( iuv + vec2( 1.5, 0.5 ) ) % iRes, level );\n\tlet rg3 = textureLoad( map, vec2u( iuv + vec2( 0.5, 1.5 ) ) % iRes, level );\n\tlet rg4 = textureLoad( map, vec2u( 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")},QN={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"};"undefined"!=typeof navigator&&/Windows/g.test(navigator.userAgent)&&(YN.pow_float=new my("fn tsl_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }"),YN.pow_vec2=new my("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 ) ); }",[YN.pow_float]),YN.pow_vec3=new my("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 ) ); }",[YN.pow_float]),YN.pow_vec4=new my("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 ) ); }",[YN.pow_float]),QN.pow_float="tsl_pow_float",QN.pow_vec2="tsl_pow_vec2",QN.pow_vec3="tsl_pow_vec3",QN.pow_vec4="tsl_pow_vec4");let ZN="";!0!==("undefined"!=typeof navigator&&/Firefox|Deno/g.test(navigator.userAgent))&&(ZN+="diagnostic( off, derivative_uniformity );\n");class JN extends PT{constructor(e,t){super(e,t,new kN),this.uniformGroups={},this.builtins={},this.directives={},this.scopedArrays=new Map}needsToWorkingColorSpace(e){return!0===e.isVideoTexture&&e.colorSpace!==y}_generateTextureSample(e,t,r,s,i=this.shaderStage){return"fragment"===i?s?`textureSample( ${t}, ${t}_sampler, ${r}, ${s} )`:`textureSample( ${t}, ${t}_sampler, ${r} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,r):this.generateTextureLod(e,t,r,s,"0")}_generateVideoSample(e,t,r=this.shaderStage){if("fragment"===r)return`textureSampleBaseClampToEdge( ${e}, ${e}_sampler, vec2( ${t}.x, 1.0 - ${t}.y ) )`;console.error(`WebGPURenderer: THREE.VideoTexture does not support ${r} shader.`)}_generateTextureSampleLevel(e,t,r,s,i,n=this.shaderStage){return"fragment"!==n&&"compute"!==n||!1!==this.isUnfilterable(e)?this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,r,s):this.generateTextureLod(e,t,r,i,s):`textureSampleLevel( ${t}, ${t}_sampler, ${r}, ${s} )`}generateWrapFunction(e){const t=`tsl_coord_${HN[e.wrapS]}S_${HN[e.wrapT]}_${e.isData3DTexture?"3d":"2d"}T`;let r=XN[t];if(void 0===r){const s=[],i=e.isData3DTexture?"vec3f":"vec2f";let n=`fn ${t}( coord : ${i} ) -> ${i} {\n\n\treturn ${i}(\n`;const o=(e,t)=>{e===cr?(s.push(YN.repeatWrapping_float),n+=`\t\ttsl_repeatWrapping_float( coord.${t} )`):e===hr?(s.push(YN.clampWrapping_float),n+=`\t\ttsl_clampWrapping_float( coord.${t} )`):e===pr?(s.push(YN.mirrorWrapping_float),n+=`\t\ttsl_mirrorWrapping_float( coord.${t} )`):(n+=`\t\tcoord.${t}`,console.warn(`WebGPURenderer: Unsupported texture wrap type "${e}" for vertex shader.`))};o(e.wrapS,"x"),n+=",\n",o(e.wrapT,"y"),e.isData3DTexture&&(n+=",\n",o(e.wrapR,"z")),n+="\n\t);\n\n}\n",XN[t]=r=new my(n,s)}return r.build(this),t}generateTextureDimension(e,t,r){const s=this.getDataFromNode(e,this.shaderStage,this.globalCache);void 0===s.dimensionsSnippet&&(s.dimensionsSnippet={});let i=s.dimensionsSnippet[r];if(void 0===s.dimensionsSnippet[r]){let n,o;const{primarySamples:a}=this.renderer.backend.utils.getTextureSampleData(e),u=a>1;o=e.isData3DTexture?"vec3":"vec2",n=u||e.isVideoTexture||e.isStorageTexture?t:`${t}${r?`, u32( ${r} )`:""}`,i=new Ba(new mu(`textureDimensions( ${n} )`,o)),s.dimensionsSnippet[r]=i,(e.isDataArrayTexture||e.isData3DTexture)&&(s.arrayLayerCount=new Ba(new mu(`textureNumLayers(${t})`,"u32"))),e.isTextureCube&&(s.cubeFaceCount=new Ba(new mu("6u","u32")))}return i.build(this)}generateFilteredTexture(e,t,r,s="0u"){this._include("biquadraticTexture");return`tsl_biquadraticTexture( ${t}, ${this.generateWrapFunction(e)}( ${r} ), ${this.generateTextureDimension(e,t,s)}, u32( ${s} ) )`}generateTextureLod(e,t,r,s,i="0u"){const n=this.generateWrapFunction(e),o=this.generateTextureDimension(e,t,i),a=e.isData3DTexture?"vec3":"vec2",u=`${a}(${n}(${r}) * ${a}(${o}))`;return this.generateTextureLoad(e,t,u,s,i)}generateTextureLoad(e,t,r,s,i="0u"){return!0===e.isVideoTexture||!0===e.isStorageTexture?`textureLoad( ${t}, ${r} )`:s?`textureLoad( ${t}, ${r}, ${s}, u32( ${i} ) )`:`textureLoad( ${t}, ${r}, u32( ${i} ) )`}generateTextureStore(e,t,r,s){return`textureStore( ${t}, ${r}, ${s} )`}isSampleCompare(e){return!0===e.isDepthTexture&&null!==e.compareFunction}isUnfilterable(e){return"float"!==this.getComponentTypeFromTexture(e)||!this.isAvailable("float32Filterable")&&!0===e.isDataTexture&&e.type===E||!1===this.isSampleCompare(e)&&e.minFilter===gr&&e.magFilter===gr||this.renderer.backend.utils.getTextureSampleData(e).primarySamples>1}generateTexture(e,t,r,s,i=this.shaderStage){let n=null;return n=!0===e.isVideoTexture?this._generateVideoSample(t,r,i):this.isUnfilterable(e)?this.generateTextureLod(e,t,r,s,"0",i):this._generateTextureSample(e,t,r,s,i),n}generateTextureGrad(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleGrad( ${t}, ${t}_sampler, ${r}, ${s[0]}, ${s[1]} )`;console.error(`WebGPURenderer: THREE.TextureNode.gradient() does not support ${n} shader.`)}generateTextureCompare(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleCompare( ${t}, ${t}_sampler, ${r}, ${s} )`;console.error(`WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${n} shader.`)}generateTextureLevel(e,t,r,s,i,n=this.shaderStage){let o=null;return o=!0===e.isVideoTexture?this._generateVideoSample(t,r,n):this._generateTextureSampleLevel(e,t,r,s,i,n),o}generateTextureBias(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleBias( ${t}, ${t}_sampler, ${r}, ${s} )`;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,r=e.type;return"texture"===r||"cubeTexture"===r||"storageTexture"===r||"texture3D"===r?t:"buffer"===r||"storageBuffer"===r||"indirectStorageBuffer"===r?`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=qN[e];return void 0!==t?(this._include(t),t):null}getNodeAccess(e,t){return"compute"!==t?Es.READ_ONLY:e.access}getStorageAccess(e,t){return $N[this.getNodeAccess(e,t)]}getUniformFromNode(e,t,r,s=null){const i=super.getUniformFromNode(e,t,r,s),n=this.getDataFromNode(e,r,this.globalCache);if(void 0===n.uniformGPU){let s;const o=e.groupNode,a=o.name,u=this.getBindGroupArray(a,r);if("texture"===t||"cubeTexture"===t||"storageTexture"===t||"texture3D"===t){let n=null;const a=this.getNodeAccess(e,r);if("texture"===t||"storageTexture"===t?n=new M_(i.name,i.node,o,a):"cubeTexture"===t?n=new B_(i.name,i.node,o,a):"texture3D"===t&&(n=new U_(i.name,i.node,o,a)),n.store=!0===e.isStorageTextureNode,n.setVisibility(WN[r]),"fragment"!==r&&"compute"!==r||!1!==this.isUnfilterable(e.value)||!1!==n.store)u.push(n),s=[n];else{const e=new EN(`${i.name}_sampler`,i.node,o);e.setVisibility(WN[r]),u.push(e,n),s=[e,n]}}else if("buffer"===t||"storageBuffer"===t||"indirectStorageBuffer"===t){const i=new("buffer"===t?S_:BN)(e,o);i.setVisibility(WN[r]),u.push(i),s=i}else{const e=this.uniformGroups[r]||(this.uniformGroups[r]={});let n=e[a];void 0===n&&(n=new C_(a,o),n.setVisibility(WN[r]),e[a]=n,u.push(n)),s=this.getNodeUniform(i,t),n.addUniform(s)}n.uniformGPU=s}return i}getBuiltin(e,t,r,s=this.shaderStage){const i=this.builtins[s]||(this.builtins[s]=new Map);return!1===i.has(e)&&i.set(e,{name:e,property:t,type:r}),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,r=this.flowShaderNode(e),s=[];for(const e of t.inputs)s.push(e.name+" : "+this.getType(e.type));let i=`fn ${t.name}( ${s.join(", ")} ) -> ${this.getType(t.type)} {\n${r.vars}\n${r.code}\n`;return r.result&&(i+=`\treturn ${r.result};\n`),i+="\n}\n",i}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")}getClipDistance(){return"varyings.hw_clip_distances"}isFlipY(){return!1}enableDirective(e,t=this.shaderStage){(this.directives[t]||(this.directives[t]=new Set)).add(e)}getDirectives(e){const t=[],r=this.directives[e];if(void 0!==r)for(const e of r)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")}enableHardwareClipping(e){this.enableClipDistances(),this.getBuiltin("clip_distances","hw_clip_distances",`array`,"vertex")}getBuiltins(e){const t=[],r=this.builtins[e];if(void 0!==r)for(const{name:e,property:s,type:i}of r.values())t.push(`@builtin( ${e} ) ${s} : ${i}`);return t.join(",\n\t")}getScopedArray(e,t,r,s){return!1===this.scopedArrays.has(e)&&this.scopedArrays.set(e,{name:e,scope:t,bufferType:r,bufferCount:s}),e}getScopedArrays(e){if("compute"!==e)return;const t=[];for(const{name:e,scope:r,bufferType:s,bufferCount:i}of this.scopedArrays.values()){const n=this.getType(s);t.push(`var<${r}> ${e}: array< ${n}, ${i} >;`)}return t.join("\n")}getAttributes(e){const t=[];if("compute"===e&&(this.getBuiltin("global_invocation_id","globalId","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 r=this.getAttributesArray();for(let e=0,s=r.length;e`)}const s=this.getBuiltins("output");return s&&t.push("\t"+s),t.join(",\n")}getStructs(e){const t=[],r=this.structs[e];for(let e=0,s=r.length;e output : ${i};\n\n`)}return t.join("\n\n")}getVar(e,t){return`var ${t} : ${this.getType(e)}`}getVars(e){const t=[],r=this.vars[e];if(void 0!==r)for(const e of r)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 r=this.varyings,s=this.vars[e];for(let i=0;i1&&(n="_multisampled"),!0===t.isCubeTexture)s="texture_cube";else if(!0===t.isDataArrayTexture||!0===t.isCompressedArrayTexture)s="texture_2d_array";else if(!0===t.isDepthTexture)s=`texture_depth${n}_2d`;else if(!0===t.isVideoTexture)s="texture_external";else if(!0===t.isData3DTexture)s="texture_3d";else if(!0===i.node.isStorageTextureNode){s=`texture_storage_2d<${DN(t)}, ${this.getStorageAccess(i.node,e)}>`}else{s=`texture${n}_2d<${this.getComponentTypeFromTexture(t).charAt(0)}32>`}r.push(`@binding( ${o.binding++} ) @group( ${o.group} ) var ${i.name} : ${s};`)}else if("buffer"===i.type||"storageBuffer"===i.type||"indirectStorageBuffer"===i.type){const t=i.node,r=this.getType(t.bufferType),n=t.bufferCount,a=n>0&&"buffer"===i.type?", "+n:"",u=t.isAtomic?`atomic<${r}>`:`${r}`,l=`\t${i.name} : array< ${u}${a} >\n`,d=t.isStorageBufferNode?`storage, ${this.getStorageAccess(t,e)}`:"uniform";s.push(this._getWGSLStructBinding("NodeBuffer_"+t.id,l,d,o.binding++,o.group))}else{const e=this.getType(this.getVectorType(i.type)),t=i.groupNode.name;(n[t]||(n[t]={index:o.binding++,id:o.group,snippets:[]})).snippets.push(`\t${i.name} : ${e}`)}}for(const e in n){const t=n[e];i.push(this._getWGSLStructBinding(e,t.snippets.join(",\n"),"uniform",t.index,t.id))}let o=r.join("\n");return o+=s.join("\n"),o+=i.join("\n"),o}buildCode(){const e=null!==this.material?{fragment:{},vertex:{}}:{compute:{}};this.sortBindingGroups();for(const t in e){const r=e[t];r.uniforms=this.getUniforms(t),r.attributes=this.getAttributes(t),r.varyings=this.getVaryings(t),r.structs=this.getStructs(t),r.vars=this.getVars(t),r.codes=this.getCodes(t),r.directives=this.getDirectives(t),r.scopedArrays=this.getScopedArrays(t);let s="// code\n\n";s+=this.flowCode[t];const i=this.flowNodes[t],n=i[i.length-1],o=n.outputNode,a=void 0!==o&&!0===o.isOutputStructNode;for(const e of i){const i=this.getFlowData(e),u=e.name;if(u&&(s.length>0&&(s+="\n"),s+=`\t// flow -> ${u}\n`),s+=`${i.code}\n\t`,e===n&&"compute"!==t)if(s+="// result\n\n\t","vertex"===t)s+=`varyings.Vertex = ${i.result};`;else if("fragment"===t)if(a)r.returnType=o.nodeType,s+=`return ${i.result};`;else{let e="\t@location(0) color: vec4";const t=this.getBuiltins("output");t&&(e+=",\n\t"+t),r.returnType="OutputStruct",r.structs+=this._getWGSLStruct("OutputStruct",e),r.structs+="\nvar output : OutputStruct;\n\n",s+=`output.color = ${i.result};\n\n\treturn output;`}}r.flow=s}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 r;return null!==t&&(r=this._getWGSLMethod(e+"_"+t)),void 0===r&&(r=this._getWGSLMethod(e)),r||e}getType(e){return KN[e]||e}isAvailable(e){let t=jN[e];return void 0===t&&("float32Filterable"===e?t=this.renderer.hasFeature("float32-filterable"):"clipDistance"===e&&(t=this.renderer.hasFeature("clip-distances")),jN[e]=t),t}_getWGSLMethod(e){return void 0!==YN[e]&&this._include(e),QN[e]}_include(e){const t=YN[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${ZN}\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 = globalId.x + globalId.y * numWorkgroups.x * u32(${t}) + globalId.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,r,s=0,i=0){const n=e+"Struct";return`${this._getWGSLStruct(n,t)}\n@binding( ${s} ) @group( ${i} )\nvar<${r}> ${e} : ${n};`}}class eS{constructor(e){this.backend=e}getCurrentDepthStencilFormat(e){let t;return null!==e.depthTexture?t=this.getTextureFormatGPU(e.depthTexture):e.depth&&e.stencil?t=Cv.Depth24PlusStencil8:e.depth&&(t=Cv.Depth24Plus),t}getTextureFormatGPU(e){return this.backend.get(e).format}getTextureSampleData(e){let t;if(e.isFramebufferTexture)t=1;else if(e.isDepthTexture&&!e.renderTarget){const e=this.backend.renderer,r=e.getRenderTarget();t=r?r.samples:e.samples}else e.renderTarget&&(t=e.renderTarget.samples);t=t||1;const r=t>1&&null!==e.renderTarget&&!0!==e.isDepthTexture&&!0!==e.isFramebufferTexture;return{samples:t,primarySamples:r?1:t,isMSAA:r}}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?nv:e.isLineSegments||e.isMesh&&!0===t.wireframe?ov:e.isLine?av:e.isMesh?uv: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")?Cv.BGRA8Unorm:navigator.gpu.getPreferredCanvasFormat()}}const tS=new Map([[Int8Array,["sint8","snorm8"]],[Uint8Array,["uint8","unorm8"]],[Int16Array,["sint16","snorm16"]],[Uint16Array,["uint16","unorm16"]],[Int32Array,["sint32","snorm32"]],[Uint32Array,["uint32","unorm32"]],[Float32Array,["float32"]]]),rS=new Map([[Le,["float16"]]]),sS=new Map([[Int32Array,"sint32"],[Int16Array,"sint32"],[Uint32Array,"uint32"],[Uint16Array,"uint32"],[Float32Array,"float32"]]);class iS{constructor(e){this.backend=e}createAttribute(e,t){const r=this._getBufferAttribute(e),s=this.backend,i=s.get(r);let n=i.buffer;if(void 0===n){const o=s.device;let a=r.array;if(!1===e.normalized)if(a.constructor===Int16Array)a=new Int32Array(a);else if(a.constructor===Uint16Array&&(a=new Uint32Array(a),t&GPUBufferUsage.INDEX))for(let e=0;e1&&(s.multisampled=!0,r.texture.isDepthTexture||(s.sampleType=pN)),r.texture.isDepthTexture)s.sampleType=gN;else if(r.texture.isDataTexture||r.texture.isDataArrayTexture||r.texture.isData3DTexture){const e=r.texture.type;e===x?s.sampleType=mN:e===b?s.sampleType=fN:e===E&&(this.backend.hasFeature("float32-filterable")?s.sampleType=hN:s.sampleType=pN)}r.isSampledCubeTexture?s.viewDimension=_N:r.texture.isDataArrayTexture||r.texture.isCompressedArrayTexture?s.viewDimension=TN:r.isSampledTexture3D&&(s.viewDimension=vN),e.texture=s}else console.error(`WebGPUBindingUtils: Unsupported binding "${r}".`);s.push(e)}return r.createBindGroupLayout({entries:s})}createBindings(e,t,r,s=0){const{backend:i,bindGroupLayoutCache:n}=this,o=i.get(e);let a,u=n.get(e.bindingsReference);void 0===u&&(u=this.createBindingsLayout(e),n.set(e.bindingsReference,u)),r>0&&(void 0===o.groups&&(o.groups=[],o.versions=[]),o.versions[r]===s&&(a=o.groups[r])),void 0===a&&(a=this.createBindGroup(e,u),r>0&&(o.groups[r]=a,o.versions[r]=s)),o.group=a,o.layout=u}updateBinding(e){const t=this.backend,r=t.device,s=e.buffer,i=t.get(e).buffer;r.queue.writeBuffer(i,0,s,0)}createBindGroup(e,t){const r=this.backend,s=r.device;let i=0;const n=[];for(const t of e.bindings){if(t.isUniformBuffer){const e=r.get(t);if(void 0===e.buffer){const r=t.byteLength,i=GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,n=s.createBuffer({label:"bindingBuffer_"+t.name,size:r,usage:i});e.buffer=n}n.push({binding:i,resource:{buffer:e.buffer}})}else if(t.isStorageBuffer){const e=r.get(t);if(void 0===e.buffer){const s=t.attribute;e.buffer=r.get(s).buffer}n.push({binding:i,resource:{buffer:e.buffer}})}else if(t.isSampler){const e=r.get(t.texture);n.push({binding:i,resource:e.sampler})}else if(t.isSampledTexture){const e=r.get(t.texture);let o;if(void 0!==e.externalTexture)o=s.importExternalTexture({source:e.externalTexture});else{const r=t.store?1:e.texture.mipLevelCount,s=`view-${e.texture.width}-${e.texture.height}-${r}`;if(o=e[s],void 0===o){const i=NN;let n;n=t.isSampledCubeTexture?_N:t.isSampledTexture3D?vN:t.texture.isDataArrayTexture||t.texture.isCompressedArrayTexture?TN:xN,o=e[s]=e.texture.createView({aspect:i,dimension:n,mipLevelCount:r})}}n.push({binding:i,resource:o})}i++}return s.createBindGroup({label:"bindGroup_"+e.name,layout:t,entries:n})}}class oS{constructor(e){this.backend=e}_getSampleCount(e){return this.backend.utils.getSampleCountRenderContext(e)}createRenderPipeline(e,t){const{object:r,material:s,geometry:i,pipeline:n}=e,{vertexProgram:o,fragmentProgram:a}=n,u=this.backend,l=u.device,d=u.utils,c=u.get(n),h=[];for(const t of e.getBindings()){const e=u.get(t);h.push(e.layout)}const p=u.attributeUtils.createShaderVertexBuffers(e);let g;!0===s.transparent&&s.blending!==D&&(g=this._getBlending(s));let m={};!0===s.stencilWrite&&(m={compare:this._getStencilCompare(s),failOp:this._getStencilOperation(s.stencilFail),depthFailOp:this._getStencilOperation(s.stencilZFail),passOp:this._getStencilOperation(s.stencilZPass)});const f=this._getColorWriteMask(s),y=[];if(null!==e.context.textures){const t=e.context.textures;for(let e=0;e1},layout:l.createPipelineLayout({bindGroupLayouts:h})},A={},R=e.context.depth,C=e.context.stencil;if(!0!==R&&!0!==C||(!0===R&&(A.format=v,A.depthWriteEnabled=s.depthWrite,A.depthCompare=_),!0===C&&(A.stencilFront=m,A.stencilBack={},A.stencilReadMask=s.stencilFuncMask,A.stencilWriteMask=s.stencilWriteMask),S.depthStencil=A),null===t)c.pipeline=l.createRenderPipeline(S);else{const e=new Promise((e=>{l.createRenderPipelineAsync(S).then((t=>{c.pipeline=t,e()}))}));t.push(e)}}createBundleEncoder(e){const t=this.backend,{utils:r,device:s}=t,i=r.getCurrentDepthStencilFormat(e),n={label:"renderBundleEncoder",colorFormats:[r.getCurrentColorFormat(e)],depthStencilFormat:i,sampleCount:this._getSampleCount(e)};return s.createRenderBundleEncoder(n)}createComputePipeline(e,t){const r=this.backend,s=r.device,i=r.get(e.computeProgram).module,n=r.get(e),o=[];for(const e of t){const t=r.get(e);o.push(t.layout)}n.pipeline=s.createComputePipeline({compute:i,layout:s.createPipelineLayout({bindGroupLayouts:o})})}_getBlending(e){let t,r;const s=e.blending,i=e.blendSrc,n=e.blendDst,o=e.blendEquation;if(s===yt){const s=null!==e.blendSrcAlpha?e.blendSrcAlpha:i,a=null!==e.blendDstAlpha?e.blendDstAlpha:n,u=null!==e.blendEquationAlpha?e.blendEquationAlpha:o;t={srcFactor:this._getBlendFactor(i),dstFactor:this._getBlendFactor(n),operation:this._getBlendOperation(o)},r={srcFactor:this._getBlendFactor(s),dstFactor:this._getBlendFactor(a),operation:this._getBlendOperation(u)}}else{const i=(e,s,i,n)=>{t={srcFactor:e,dstFactor:s,operation:jv},r={srcFactor:i,dstFactor:n,operation:jv}};if(e.premultipliedAlpha)switch(s){case F:i(Pv,Vv,Pv,Vv);break;case Tt:i(Pv,Pv,Pv,Pv);break;case xt:i(Fv,Dv,Fv,Pv);break;case bt:i(Fv,Iv,Fv,Lv)}else switch(s){case F:i(Lv,Vv,Pv,Vv);break;case Tt:i(Lv,Pv,Lv,Pv);break;case xt:i(Fv,Dv,Fv,Pv);break;case bt:i(Fv,Iv,Fv,Iv)}}if(void 0!==t&&void 0!==r)return{color:t,alpha:r};console.error("THREE.WebGPURenderer: Invalid blending: ",s)}_getBlendFactor(e){let t;switch(e){case st:t=Fv;break;case it:t=Pv;break;case nt:t=Iv;break;case dt:t=Dv;break;case ot:t=Lv;break;case ct:t=Vv;break;case ut:t=Ov;break;case ht:t=Gv;break;case lt:t=kv;break;case pt:t=zv;break;case at:t=$v;break;case 211:t=Hv;break;case 212:t=Wv;break;default:console.error("THREE.WebGPURenderer: Blend factor not supported.",e)}return t}_getStencilCompare(e){let t;const r=e.stencilFunc;switch(r){case Br:t=dv;break;case Mr:t=yv;break;case wr:t=cv;break;case Er:t=pv;break;case Cr:t=hv;break;case Rr:t=fv;break;case Ar:t=gv;break;case Sr:t=mv;break;default:console.error("THREE.WebGPURenderer: Invalid stencil function.",r)}return t}_getStencilOperation(e){let t;switch(e){case Or:t=Jv;break;case Vr:t=eN;break;case Lr:t=tN;break;case Dr:t=rN;break;case Ir:t=sN;break;case Pr:t=iN;break;case Fr:t=nN;break;case Ur:t=oN;break;default:console.error("THREE.WebGPURenderer: Invalid stencil operation.",t)}return t}_getBlendOperation(e){let t;switch(e){case et:t=jv;break;case tt:t=qv;break;case rt:t=Kv;break;case kr:t=Xv;break;case Gr:t=Yv;break;default:console.error("THREE.WebGPUPipelineUtils: Blend equation not supported.",e)}return t}_getPrimitiveState(e,t,r){const s={},i=this.backend.utils;switch(s.topology=i.getPrimitiveTopology(e,r),null!==t.index&&!0===e.isLine&&!0!==e.isLineSegments&&(s.stripIndexFormat=t.index.array instanceof Uint16Array?Av:Rv),r.side){case ke:s.frontFace=_v,s.cullMode=Sv;break;case T:s.frontFace=_v,s.cullMode=Nv;break;case le:s.frontFace=_v,s.cullMode=vv;break;default:console.error("THREE.WebGPUPipelineUtils: Unknown material.side value.",r.side)}return s}_getColorWriteMask(e){return!0===e.colorWrite?Zv:Qv}_getDepthCompare(e){let t;if(!1===e.depthTest)t=yv;else{const r=e.depthFunc;switch(r){case Et:t=dv;break;case Ct:t=yv;break;case Rt:t=cv;break;case At:t=pv;break;case St:t=hv;break;case Nt:t=fv;break;case vt:t=gv;break;case _t:t=mv;break;default:console.error("THREE.WebGPUPipelineUtils: Invalid depth function.",r)}}return t}}class aS extends G_{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 eS(this),this.attributeUtils=new iS(this),this.bindingUtils=new nS(this),this.pipelineUtils=new oS(this),this.textureUtils=new IN(this),this.occludedResolveCache=new Map}async init(e){await super.init(e);const t=this.parameters;let r;if(void 0===t.device){const e={powerPreference:t.powerPreference},s="undefined"!=typeof navigator?await navigator.gpu.requestAdapter(e):null;if(null===s)throw new Error("WebGPUBackend: Unable to create WebGPU adapter.");const i=Object.values(RN),n=[];for(const e of i)s.features.has(e)&&n.push(e);const o={requiredFeatures:n,requiredLimits:t.requiredLimits};r=await s.requestDevice(o)}else r=t.device;r.lost.then((t=>{const r={api:"WebGPU",message:t.message||"Unknown reason",reason:t.reason||null,originalEvent:t};e.onDeviceLost(r)}));const s=void 0!==t.context?t.context:e.domElement.getContext("webgpu");this.device=r,this.context=s;const i=t.alpha?"premultiplied":"opaque";this.trackTimestamp=this.trackTimestamp&&this.hasFeature(RN.TimestampQuery),this.context.configure({device:this.device,format:this.utils.getPreferredCanvasFormat(),usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:i}),this.updateSize()}get coordinateSystem(){return l}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}]},!0!==this.renderer.depth&&!0!==this.renderer.stencil||(e.depthStencilAttachment={view:this.textureUtils.getDepthBuffer(t.depth,t.stencil).createView()});const r=e.colorAttachments[0];this.renderer.samples>0?r.view=this.colorBuffer.createView():r.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,t={}){const r=e.renderTarget,s=this.get(r);let i=s.descriptors;if(void 0===i||s.width!==r.width||s.height!==r.height||s.dimensions!==r.dimensions||s.activeMipmapLevel!==r.activeMipmapLevel||s.activeCubeFace!==e.activeCubeFace||s.samples!==r.samples||s.loadOp!==t.loadOp){i={},s.descriptors=i;const e=()=>{r.removeEventListener("dispose",e),this.delete(r)};r.addEventListener("dispose",e)}const n=e.getCacheKey();let o=i[n];if(void 0===o){const a=e.textures,u=[];let l;for(let s=0;s0&&(t.currentOcclusionQuerySet&&t.currentOcclusionQuerySet.destroy(),t.currentOcclusionQueryBuffer&&t.currentOcclusionQueryBuffer.destroy(),t.currentOcclusionQuerySet=t.occlusionQuerySet,t.currentOcclusionQueryBuffer=t.occlusionQueryBuffer,t.currentOcclusionQueryObjects=t.occlusionQueryObjects,i=r.createQuerySet({type:"occlusion",count:s,label:`occlusionQuerySet_${e.id}`}),t.occlusionQuerySet=i,t.occlusionQueryIndex=0,t.occlusionQueryObjects=new Array(s),t.lastOcclusionObject=null),n=null===e.textures?this._getDefaultRenderPassDescriptor():this._getRenderPassDescriptor(e,{loadOp:xv}),this.initTimestampQuery(e,n),n.occlusionQuerySet=i;const o=n.depthStencilAttachment;if(null!==e.textures){const t=n.colorAttachments;for(let r=0;r0&&t.currentPass.executeBundles(t.renderBundles),r>t.occlusionQueryIndex&&t.currentPass.endOcclusionQuery(),t.currentPass.end(),r>0){const s=8*r;let i=this.occludedResolveCache.get(s);void 0===i&&(i=this.device.createBuffer({size:s,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),this.occludedResolveCache.set(s,i));const n=this.device.createBuffer({size:s,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});t.encoder.resolveQuerySet(t.occlusionQuerySet,0,r,i,0),t.encoder.copyBufferToBuffer(i,0,n,0,s),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?(u.x=Math.min(t.dispatchCount,o),u.y=Math.ceil(t.dispatchCount/o)):u.x=t.dispatchCount,i.dispatchWorkgroups(u.x,u.y,u.z)}finishCompute(e){const t=this.get(e);t.passEncoderGPU.end(),this.prepareTimestampBuffer(e,t.cmdEncoderGPU),this.device.queue.submit([t.cmdEncoderGPU.finish()])}async waitForGPU(){await this.device.queue.onSubmittedWorkDone()}draw(e,t){const{object:r,context:s,pipeline:i}=e,n=e.getBindings(),o=this.get(s),a=this.get(i).pipeline,u=o.currentSets,l=o.currentPass,d=e.getDrawParameters();if(null===d)return;u.pipeline!==a&&(l.setPipeline(a),u.pipeline=a);const c=u.bindingGroups;for(let e=0,t=n.length;e1?0:r;!0===p?l.drawIndexed(t[r],s,e[r]/h.array.BYTES_PER_ELEMENT,0,n):l.draw(t[r],s,e[r],n)}}else if(!0===p){const{vertexCount:s,instanceCount:i,firstVertex:n}=d,o=e.getIndirect();if(null!==o){const e=this.get(o).buffer;l.drawIndexedIndirect(e,0)}else l.drawIndexed(s,i,n,0,0);t.update(r,s,i)}else{const{vertexCount:s,instanceCount:i,firstVertex:n}=d,o=e.getIndirect();if(null!==o){const e=this.get(o).buffer;l.drawIndirect(e,0)}else l.draw(s,i,n,0);t.update(r,s,i)}}needsRenderUpdate(e){const t=this.get(e),{object:r,material:s}=e,i=this.utils,n=i.getSampleCountRenderContext(e.context),o=i.getCurrentColorSpace(e.context),a=i.getCurrentColorFormat(e.context),u=i.getCurrentDepthStencilFormat(e.context),l=i.getPrimitiveTopology(r,s);let d=!1;return t.material===s&&t.materialVersion===s.version&&t.transparent===s.transparent&&t.blending===s.blending&&t.premultipliedAlpha===s.premultipliedAlpha&&t.blendSrc===s.blendSrc&&t.blendDst===s.blendDst&&t.blendEquation===s.blendEquation&&t.blendSrcAlpha===s.blendSrcAlpha&&t.blendDstAlpha===s.blendDstAlpha&&t.blendEquationAlpha===s.blendEquationAlpha&&t.colorWrite===s.colorWrite&&t.depthWrite===s.depthWrite&&t.depthTest===s.depthTest&&t.depthFunc===s.depthFunc&&t.stencilWrite===s.stencilWrite&&t.stencilFunc===s.stencilFunc&&t.stencilFail===s.stencilFail&&t.stencilZFail===s.stencilZFail&&t.stencilZPass===s.stencilZPass&&t.stencilFuncMask===s.stencilFuncMask&&t.stencilWriteMask===s.stencilWriteMask&&t.side===s.side&&t.alphaToCoverage===s.alphaToCoverage&&t.sampleCount===n&&t.colorSpace===o&&t.colorFormat===a&&t.depthStencilFormat===u&&t.primitiveTopology===l&&t.clippingContextCacheKey===e.clippingContextCacheKey||(t.material=s,t.materialVersion=s.version,t.transparent=s.transparent,t.blending=s.blending,t.premultipliedAlpha=s.premultipliedAlpha,t.blendSrc=s.blendSrc,t.blendDst=s.blendDst,t.blendEquation=s.blendEquation,t.blendSrcAlpha=s.blendSrcAlpha,t.blendDstAlpha=s.blendDstAlpha,t.blendEquationAlpha=s.blendEquationAlpha,t.colorWrite=s.colorWrite,t.depthWrite=s.depthWrite,t.depthTest=s.depthTest,t.depthFunc=s.depthFunc,t.stencilWrite=s.stencilWrite,t.stencilFunc=s.stencilFunc,t.stencilFail=s.stencilFail,t.stencilZFail=s.stencilZFail,t.stencilZPass=s.stencilZPass,t.stencilFuncMask=s.stencilFuncMask,t.stencilWriteMask=s.stencilWriteMask,t.side=s.side,t.alphaToCoverage=s.alphaToCoverage,t.sampleCount=n,t.colorSpace=o,t.colorFormat=a,t.depthStencilFormat=u,t.primitiveTopology=l,t.clippingContextCacheKey=e.clippingContextCacheKey,d=!0),d}getRenderCacheKey(e){const{object:t,material:r}=e,s=this.utils,i=e.context;return[r.transparent,r.blending,r.premultipliedAlpha,r.blendSrc,r.blendDst,r.blendEquation,r.blendSrcAlpha,r.blendDstAlpha,r.blendEquationAlpha,r.colorWrite,r.depthWrite,r.depthTest,r.depthFunc,r.stencilWrite,r.stencilFunc,r.stencilFail,r.stencilZFail,r.stencilZPass,r.stencilFuncMask,r.stencilWriteMask,r.side,s.getSampleCountRenderContext(i),s.getCurrentColorSpace(i),s.getCurrentColorFormat(i),s.getCurrentDepthStencilFormat(i),s.getPrimitiveTopology(t,r),e.getGeometryCacheKey(),e.clippingContextCacheKey].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)}async copyTextureToBuffer(e,t,r,s,i,n){return this.textureUtils.copyTextureToBuffer(e,t,r,s,i,n)}initTimestampQuery(e,t){if(!this.trackTimestamp)return;const r=this.get(e);if(!r.timestampQuerySet){const t=e.isComputeNode?"compute":"render";r.timestampQuerySet=this.device.createQuerySet({type:"timestamp",count:2,label:`timestamp_${t}_${e.id}`})}t.timestampWrites={querySet:r.timestampQuerySet,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1}}prepareTimestampBuffer(e,t){if(!this.trackTimestamp)return;const r=this.get(e),s=2*BigUint64Array.BYTES_PER_ELEMENT;void 0===r.currentTimestampQueryBuffers&&(r.currentTimestampQueryBuffers={resolveBuffer:this.device.createBuffer({label:"timestamp resolve buffer",size:s,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),resultBuffer:this.device.createBuffer({label:"timestamp result buffer",size:s,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ})});const{resolveBuffer:i,resultBuffer:n}=r.currentTimestampQueryBuffers;t.resolveQuerySet(r.timestampQuerySet,0,2,i,0),"unmapped"===n.mapState&&t.copyBufferToBuffer(i,0,n,0,s)}async resolveTimestampAsync(e,t="render"){if(!this.trackTimestamp)return;const r=this.get(e);if(void 0===r.currentTimestampQueryBuffers)return;const{resultBuffer:s}=r.currentTimestampQueryBuffers;if("unmapped"===s.mapState){await s.mapAsync(GPUMapMode.READ);const e=new BigUint64Array(s.getMappedRange()),r=Number(e[1]-e[0])/1e6;this.renderer.info.updateTimestamp(t,r),s.unmap()}}createNodeBuilder(e,t){return new JN(e,t)}createProgram(e){this.get(e).module={module:this.device.createShaderModule({code:e.code,label:e.stage+(""!==e.name?`_${e.name}`:"")}),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 r=this.get(e),s=r.currentPass.finish();this.get(t).bundleGPU=s,r.currentSets=r._currentSets,r.currentPass=r._currentPass}addBundle(e,t){this.get(e).renderBundles.push(this.get(t).bundleGPU)}createBindings(e,t,r,s){this.bindingUtils.createBindings(e,t,r,s)}updateBindings(e,t,r,s){this.bindingUtils.createBindings(e,t,r,s)}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)}createIndirectStorageAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.STORAGE|GPUBufferUsage.INDIRECT|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,r=null,s=null,i=0){let n=0,o=0,a=0,u=0,l=0,d=0,c=e.image.width,h=e.image.height;null!==r&&(u=r.x,l=r.y,d=r.z||0,c=r.width,h=r.height),null!==s&&(n=s.x,o=s.y,a=s.z||0);const p=this.device.createCommandEncoder({label:"copyTextureToTexture_"+e.id+"_"+t.id}),g=this.get(e).texture,m=this.get(t).texture;p.copyTextureToTexture({texture:g,mipLevel:i,origin:{x:u,y:l,z:d}},{texture:m,mipLevel:i,origin:{x:n,y:o,z:a}},[c,h,1]),this.device.queue.submit([p.finish()])}copyFramebufferToTexture(e,t,r){const s=this.get(t);let i=null;i=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 n=this.get(e).texture;if(i.format!==n.format)return void console.error("WebGPUBackend: copyFramebufferToTexture: Source and destination formats do not match.",i.format,n.format);let o;if(s.currentPass?(s.currentPass.end(),o=s.encoder):o=this.device.createCommandEncoder({label:"copyFramebufferToTexture_"+e.id}),o.copyTextureToTexture({texture:i,origin:[r.x,r.y,0]},{texture:n},[r.z,r.w]),e.generateMipmaps&&this.textureUtils.generateMipmaps(e),s.currentPass){const{descriptor:e}=s;for(let t=0;t(console.warn("THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend."),new iv(e)));super(new t(e),e),this.library=new lS,this.isWebGPURenderer=!0}}class cS extends ts{constructor(){super(),this.isBundleGroup=!0,this.type="BundleGroup",this.static=!0,this.version=0}set needsUpdate(e){!0===e&&this.version++}}class hS{constructor(e,t=$i(0,0,1,1)){this.renderer=e,this.outputNode=t,this.outputColorTransform=!0,this.needsUpdate=!0;const r=new nh;r.name="PostProcessing",this._quadMesh=new cf(r)}render(){this._update();const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;e.toneMapping=h,e.outputColorSpace=Re,this._quadMesh.render(e),e.toneMapping=t,e.outputColorSpace=r}dispose(){this._quadMesh.material.dispose()}_update(){if(!0===this.needsUpdate){const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;this._quadMesh.material.fragmentNode=!0===this.outputColorTransform?xu(this.outputNode,t,r):this.outputNode.context({toneMapping:t,outputColorSpace:r}),this._quadMesh.material.needsUpdate=!0,this.needsUpdate=!1}}async renderAsync(){this._update();const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;e.toneMapping=h,e.outputColorSpace=Re,await this._quadMesh.renderAsync(e),e.toneMapping=t,e.outputColorSpace=r}}class pS extends J{constructor(e=1,t=1){super(),this.image={width:e,height:t},this.magFilter=z,this.minFilter=z,this.isStorageTexture=!0}}class gS extends xf{constructor(e,t){super(e,t,Uint32Array),this.isIndirectStorageBufferAttribute=!0}}class mS extends rs{constructor(e){super(e),this.textures={},this.nodes={}}load(e,t,r,s){const i=new ss(this.manager);i.setPath(this.path),i.setRequestHeader(this.requestHeader),i.setWithCredentials(this.withCredentials),i.load(e,(r=>{try{t(this.parse(JSON.parse(r)))}catch(t){s?s(t):console.error(t),this.manager.itemError(e)}}),r,s)}parseNodes(e){const t={};if(void 0!==e){for(const r of e){const{uuid:e,type:s}=r;t[e]=this.createNodeFromType(s),t[e].uuid=e}const r={nodes:t,textures:this.textures};for(const s of e){s.meta=r;t[s.uuid].deserialize(s),delete s.meta}}return t}parse(e){const t=this.createNodeFromType(e.type);t.uuid=e.uuid;const r={nodes:this.parseNodes(e.nodes),textures:this.textures};return e.meta=r,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),Bi()):Ti(new this.nodes[e])}}class fS extends is{constructor(e){super(e),this.nodes={},this.nodeMaterials={}}parse(e){const t=super.parse(e),r=this.nodes,s=e.inputNodes;for(const e in s){const i=s[e];t[e]=r[i]}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 yS extends ns{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 r=super.parse(e,t);return this._nodesJSON=null,r}parseNodes(e,t){if(void 0!==e){const r=new mS;return r.setNodes(this.nodes),r.setTextures(t),r.parseNodes(e)}return{}}parseMaterials(e,t){const r={};if(void 0!==e){const s=this.parseNodes(this._nodesJSON,t),i=new fS;i.setTextures(t),i.setNodes(s),i.setNodeMaterials(this.nodeMaterials);for(let t=0,s=e.length;t} + */ this.renderObjects = new WeakMap(); + + /** + * Whether the material uses node objects or not. + * + * @type {Boolean} + */ this.hasNode = this.containsNode( builder ); + + /** + * Whether the node builder's 3D object is animated or not. + * + * @type {Boolean} + */ this.hasAnimation = builder.object.isSkinnedMesh === true; + + /** + * A list of all possible material uniforms + * + * @type {Array} + */ this.refreshUniforms = refreshUniforms; + + /** + * Holds the current render ID from the node frame. + * + * @type {Number} + * @default 0 + */ this.renderId = 0; } + /** + * Returns `true` if the given render object is verified for the first time of this observer. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object is verified for the first time of this observer. + */ firstInitialization( renderObject ) { const hasInitialized = this.renderObjects.has( renderObject ); @@ -87,6 +134,12 @@ class NodeMaterialObserver { } + /** + * Returns monitoring data for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Object} The monitoring data. + */ getRenderObjectData( renderObject ) { let data = this.renderObjects.get( renderObject ); @@ -140,6 +193,13 @@ class NodeMaterialObserver { } + /** + * Returns an attribute data structure holding the attributes versions for + * monitoring. + * + * @param {Object} attributes - The geometry attributes. + * @return {Object} An object for monitoring the versions of attributes. + */ getAttributesData( attributes ) { const attributesData = {}; @@ -158,6 +218,13 @@ class NodeMaterialObserver { } + /** + * Returns `true` if the node builder's material uses + * node properties. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Boolean} Whether the node builder's material uses node properties or not. + */ containsNode( builder ) { const material = builder.material; @@ -176,6 +243,13 @@ class NodeMaterialObserver { } + /** + * Returns a material data structure holding the material property values for + * monitoring. + * + * @param {Material} material - The material. + * @return {Object} An object for monitoring material properties. + */ getMaterialData( material ) { const data = {}; @@ -210,6 +284,12 @@ class NodeMaterialObserver { } + /** + * Returns `true` if the given render object has not changed its state. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object has changed its state or not. + */ equals( renderObject ) { const { object, material, geometry } = renderObject; @@ -390,6 +470,13 @@ class NodeMaterialObserver { } + /** + * Checks if the given render object requires a refresh. + * + * @param {RenderObject} renderObject - The render object. + * @param {NodeFrame} nodeFrame - The current node frame. + * @return {Boolean} Whether the given render object requires a refresh or not. + */ needsRefresh( renderObject, nodeFrame ) { if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) ) @@ -509,7 +596,7 @@ function getCacheKey$1( object, force = false ) { for ( const { property, childNode } of getNodeChildren( object ) ) { - values.push( values, cyrb53( property.slice( 0, - 4 ) ), childNode.getCacheKey( force ) ); + values.push( cyrb53( property.slice( 0, - 4 ) ), childNode.getCacheKey( force ) ); } @@ -582,6 +669,8 @@ const typeFromLength = /*@__PURE__*/ new Map( [ [ 16, 'mat4' ] ] ); +const dataFromObject = /*@__PURE__*/ new WeakMap(); + /** * Returns the data type for the given the length. * @@ -595,6 +684,39 @@ function getTypeFromLength( length ) { } +/** + * Returns the typed array for the given data type. + * + * @method + * @param {String} type - The data type. + * @return {TypedArray} The typed array. + */ +function getTypedArrayFromType( type ) { + + // Handle component type for vectors and matrices + if ( /[iu]?vec\d/.test( type ) ) { + + // Handle int vectors + if ( type.startsWith( 'ivec' ) ) return Int32Array; + // Handle uint vectors + if ( type.startsWith( 'uvec' ) ) return Uint32Array; + // Default to float vectors + return Float32Array; + + } + + // Handle matrices (always float) + if ( /mat\d/.test( type ) ) return Float32Array; + + // Basic types + if ( /float/.test( type ) ) return Float32Array; + if ( /uint/.test( type ) ) return Uint32Array; + if ( /int/.test( type ) ) return Int32Array; + + throw new Error( `THREE.NodeUtils: Unsupported type: ${type}` ); + +} + /** * Returns the length for the given data type. * @@ -748,6 +870,27 @@ function getValueFromType( type, ...params ) { } +/** + * Gets the object data that can be shared between different rendering steps. + * + * @param {Object} object - The object to get the data for. + * @return {Object} The object data. + */ +function getDataFromObject( object ) { + + let data = dataFromObject.get( object ); + + if ( data === undefined ) { + + data = {}; + dataFromObject.set( object, data ); + + } + + return data; + +} + /** * Converts the given array buffer to a Base64 string. * @@ -789,9 +932,11 @@ var NodeUtils = /*#__PURE__*/Object.freeze({ arrayBufferToBase64: arrayBufferToBase64, base64ToArrayBuffer: base64ToArrayBuffer, getCacheKey: getCacheKey$1, + getDataFromObject: getDataFromObject, getLengthFromType: getLengthFromType, getNodeChildren: getNodeChildren, getTypeFromLength: getTypeFromLength, + getTypedArrayFromType: getTypedArrayFromType, getValueFromType: getValueFromType, getValueType: getValueType, hash: hash$1, @@ -799,6 +944,8 @@ var NodeUtils = /*#__PURE__*/Object.freeze({ hashString: hashString }); +/** @module NodeConstants **/ + /** * Possible shader stages. * @@ -1338,8 +1485,9 @@ class Node extends EventDispatcher { } - // return a outputNode if exists - return null; + // return a outputNode if exists or null + + return nodeProperties.outputNode || null; } @@ -1473,12 +1621,19 @@ class Node extends EventDispatcher { if ( properties.initialized !== true ) { - const stackNodesBeforeSetup = builder.stack.nodes.length; + //const stackNodesBeforeSetup = builder.stack.nodes.length; properties.initialized = true; - properties.outputNode = this.setup( builder ); - if ( properties.outputNode !== null && builder.stack.nodes.length !== stackNodesBeforeSetup ) ; + const outputNode = this.setup( builder ); // return a node or null + const isNodeOutput = outputNode && outputNode.isNode === true; + + /*if ( isNodeOutput && builder.stack.nodes.length !== stackNodesBeforeSetup ) { + + // !! no outputNode !! + //outputNode = builder.stack; + + }*/ for ( const childNode of Object.values( properties ) ) { @@ -1490,6 +1645,14 @@ class Node extends EventDispatcher { } + if ( isNodeOutput ) { + + outputNode.build( builder ); + + } + + properties.outputNode = outputNode; + } } else if ( buildStage === 'analyze' ) { @@ -1736,7 +1899,7 @@ class ArrayElementNode extends Node { // @TODO: If extending from TempNode it br } /** - * Constructs array element node. + * Constructs an array element node. * * @param {Node} node - The array-like node. * @param {Node} indexNode - The index node that defines the element access. @@ -2618,7 +2781,7 @@ class ConstNode extends InputNode { } -// +/** @module TSLCore **/ let currentStack = null; @@ -2915,7 +3078,7 @@ class ShaderCallNodeInternal extends Node { } else { const jsFunc = shaderNode.jsFunc; - const outputNode = inputNodes !== null ? jsFunc( inputNodes, builder ) : jsFunc( builder ); + const outputNode = inputNodes !== null || jsFunc.length > 1 ? jsFunc( inputNodes || [], builder ) : jsFunc( builder ); result = nodeObject( outputNode ); @@ -3163,6 +3326,13 @@ const Fn = ( jsFunc, nodeType ) => { }; +/** + * @function + * @deprecated since r168. Use {@link Fn} instead. + * + * @param {...any} params + * @returns {Function} + */ const tslFn = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.ShaderNode: tslFn() has been renamed to Fn().' ); @@ -3263,6 +3433,8 @@ const split = ( node, channels ) => nodeObject( new SplitNode( nodeObject( node addMethodChaining( 'element', element ); addMethodChaining( 'convert', convert ); +/** @module UniformGroupNode **/ + /** * This node can be used to group single instances of {@link UniformNode} * and manage them as a uniform buffer. @@ -3352,13 +3524,48 @@ class UniformGroupNode extends Node { } +/** + * TSL function for creating a uniform group node with the given name. + * + * @function + * @param {String} name - The name of the uniform group node. + * @returns {UniformGroupNode} + */ const uniformGroup = ( name ) => new UniformGroupNode( name ); + +/** + * TSL function for creating a shared uniform group node with the given name and order. + * + * @function + * @param {String} name - The name of the uniform group node. + * @param {Number} [order=0] - Influences the internal sorting. + * @returns {UniformGroupNode} + */ const sharedUniformGroup = ( name, order = 0 ) => new UniformGroupNode( name, true, order ); +/** + * TSL object that represents a shared uniform group node which is updated once per frame. + * + * @type {UniformGroupNode} + */ const frameGroup = /*@__PURE__*/ sharedUniformGroup( 'frame' ); + +/** + * TSL object that represents a shared uniform group node which is updated once per render. + * + * @type {UniformGroupNode} + */ const renderGroup = /*@__PURE__*/ sharedUniformGroup( 'render' ); + +/** + * TSL object that represents a uniform group node which is updated once per object. + * + * @type {UniformGroupNode} + */ const objectGroup = /*@__PURE__*/ uniformGroup( 'object' ); +/** @module UniformNode **/ + /** * Class for representing a uniform. * @@ -3511,6 +3718,14 @@ class UniformNode extends InputNode { } +/** + * TSL function for creating a uniform node. + * + * @function + * @param {Any} arg1 - The value of this node. Usually a JS primitive or three.js object (vector, matrix, color, texture). + * @param {String?} arg2 - The node type. If no explicit type is defined, the node tries to derive the type from its value. + * @returns {UniformNode} + */ const uniform = ( arg1, arg2 ) => { const nodeType = getConstNodeType( arg2 || arg1 ); @@ -3522,8 +3737,10 @@ const uniform = ( arg1, arg2 ) => { }; +/** @module PropertyNode **/ + /** - * This class represents a shader property. It can be used on + * This class represents a shader property. It can be used * to explicitly define a property and assign a value to it. * * ```js @@ -3620,38 +3837,224 @@ class PropertyNode extends Node { } +/** + * TSL function for creating a property node. + * + * @function + * @param {String} type - The type of the node. + * @param {String?} [name=null] - The name of the property in the shader. + * @returns {PropertyNode} + */ const property = ( type, name ) => nodeObject( new PropertyNode( type, name ) ); + +/** + * TSL function for creating a varying property node. + * + * @function + * @param {String} type - The type of the node. + * @param {String?} [name=null] - The name of the varying in the shader. + * @returns {PropertyNode} + */ const varyingProperty = ( type, name ) => nodeObject( new PropertyNode( type, name, true ) ); +/** + * TSL object that represents the shader variable `DiffuseColor`. + * + * @type {PropertyNode} + */ const diffuseColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'DiffuseColor' ); + +/** + * TSL object that represents the shader variable `EmissiveColor`. + * + * @type {PropertyNode} + */ const emissive = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'EmissiveColor' ); + +/** + * TSL object that represents the shader variable `Roughness`. + * + * @type {PropertyNode} + */ const roughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Roughness' ); + +/** + * TSL object that represents the shader variable `Metalness`. + * + * @type {PropertyNode} + */ const metalness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Metalness' ); + +/** + * TSL object that represents the shader variable `Clearcoat`. + * + * @type {PropertyNode} + */ const clearcoat = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Clearcoat' ); + +/** + * TSL object that represents the shader variable `ClearcoatRoughness`. + * + * @type {PropertyNode} + */ const clearcoatRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'ClearcoatRoughness' ); + +/** + * TSL object that represents the shader variable `Sheen`. + * + * @type {PropertyNode} + */ const sheen = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'Sheen' ); + +/** + * TSL object that represents the shader variable `SheenRoughness`. + * + * @type {PropertyNode} + */ const sheenRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SheenRoughness' ); + +/** + * TSL object that represents the shader variable `Iridescence`. + * + * @type {PropertyNode} + */ const iridescence = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Iridescence' ); + +/** + * TSL object that represents the shader variable `IridescenceIOR`. + * + * @type {PropertyNode} + */ const iridescenceIOR = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceIOR' ); + +/** + * TSL object that represents the shader variable `IridescenceThickness`. + * + * @type {PropertyNode} + */ const iridescenceThickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceThickness' ); + +/** + * TSL object that represents the shader variable `AlphaT`. + * + * @type {PropertyNode} + */ const alphaT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AlphaT' ); + +/** + * TSL object that represents the shader variable `Anisotropy`. + * + * @type {PropertyNode} + */ const anisotropy = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Anisotropy' ); + +/** + * TSL object that represents the shader variable `AnisotropyT`. + * + * @type {PropertyNode} + */ const anisotropyT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyT' ); + +/** + * TSL object that represents the shader variable `AnisotropyB`. + * + * @type {PropertyNode} + */ const anisotropyB = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyB' ); + +/** + * TSL object that represents the shader variable `SpecularColor`. + * + * @type {PropertyNode} + */ const specularColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'SpecularColor' ); + +/** + * TSL object that represents the shader variable `SpecularF90`. + * + * @type {PropertyNode} + */ const specularF90 = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SpecularF90' ); + +/** + * TSL object that represents the shader variable `Shininess`. + * + * @type {PropertyNode} + */ const shininess = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Shininess' ); + +/** + * TSL object that represents the shader variable `Output`. + * + * @type {PropertyNode} + */ const output = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'Output' ); + +/** + * TSL object that represents the shader variable `dashSize`. + * + * @type {PropertyNode} + */ const dashSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'dashSize' ); + +/** + * TSL object that represents the shader variable `gapSize`. + * + * @type {PropertyNode} + */ const gapSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'gapSize' ); + +/** + * TSL object that represents the shader variable `pointWidth`. + * + * @type {PropertyNode} + */ const pointWidth = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'pointWidth' ); + +/** + * TSL object that represents the shader variable `IOR`. + * + * @type {PropertyNode} + */ const ior = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IOR' ); + +/** + * TSL object that represents the shader variable `Transmission`. + * + * @type {PropertyNode} + */ const transmission = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Transmission' ); + +/** + * TSL object that represents the shader variable `Thickness`. + * + * @type {PropertyNode} + */ const thickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Thickness' ); + +/** + * TSL object that represents the shader variable `AttenuationDistance`. + * + * @type {PropertyNode} + */ const attenuationDistance = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AttenuationDistance' ); + +/** + * TSL object that represents the shader variable `AttenuationColor`. + * + * @type {PropertyNode} + */ const attenuationColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'AttenuationColor' ); + +/** + * TSL object that represents the shader variable `Dispersion`. + * + * @type {PropertyNode} + */ const dispersion = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Dispersion' ); +/** @module AssignNode **/ + /** * These node represents an assign operation. Meaning a node is assigned * to another node. @@ -3810,6 +4213,14 @@ class AssignNode extends TempNode { } +/** + * TSL function for creating an assign node. + * + * @function + * @param {Node} targetNode - The target node. + * @param {Node} sourceNode - The source type. + * @returns {AssignNode} + */ const assign = /*@__PURE__*/ nodeProxy( AssignNode ); addMethodChaining( 'assign', assign ); @@ -3957,6 +4368,8 @@ const call = ( func, ...params ) => { addMethodChaining( 'call', call ); +/** @module OperatorNode **/ + /** * This node represents basic mathematical and logical operations like addition, * subtraction or comparisons (e.g. `equal()`). @@ -4019,6 +4432,15 @@ class OperatorNode extends TempNode { */ this.bNode = bNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isOperatorNode = true; + } /** @@ -4257,26 +4679,218 @@ class OperatorNode extends TempNode { } +/** + * Returns the addition of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ const add = /*@__PURE__*/ nodeProxy( OperatorNode, '+' ); + +/** + * Returns the subtraction of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ const sub = /*@__PURE__*/ nodeProxy( OperatorNode, '-' ); + +/** + * Returns the multiplication of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ const mul = /*@__PURE__*/ nodeProxy( OperatorNode, '*' ); + +/** + * Returns the division of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ const div = /*@__PURE__*/ nodeProxy( OperatorNode, '/' ); + +/** + * Computes the remainder of dividing the first node by the second, for integer values. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const modInt = /*@__PURE__*/ nodeProxy( OperatorNode, '%' ); + +/** + * Checks if two nodes are equal. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const equal = /*@__PURE__*/ nodeProxy( OperatorNode, '==' ); + +/** + * Checks if two nodes are not equal. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const notEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '!=' ); + +/** + * Checks if the first node is less than the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const lessThan = /*@__PURE__*/ nodeProxy( OperatorNode, '<' ); + +/** + * Checks if the first node is greater than the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const greaterThan = /*@__PURE__*/ nodeProxy( OperatorNode, '>' ); + +/** + * Checks if the first node is less than or equal to the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const lessThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '<=' ); + +/** + * Checks if the first node is greater than or equal to the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const greaterThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '>=' ); + +/** + * Performs logical AND on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const and = /*@__PURE__*/ nodeProxy( OperatorNode, '&&' ); + +/** + * Performs logical OR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const or = /*@__PURE__*/ nodeProxy( OperatorNode, '||' ); + +/** + * Performs logical NOT on a node. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const not = /*@__PURE__*/ nodeProxy( OperatorNode, '!' ); + +/** + * Performs logical XOR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const xor = /*@__PURE__*/ nodeProxy( OperatorNode, '^^' ); + +/** + * Performs bitwise AND on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const bitAnd = /*@__PURE__*/ nodeProxy( OperatorNode, '&' ); + +/** + * Performs bitwise NOT on a node. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const bitNot = /*@__PURE__*/ nodeProxy( OperatorNode, '~' ); + +/** + * Performs bitwise OR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const bitOr = /*@__PURE__*/ nodeProxy( OperatorNode, '|' ); + +/** + * Performs bitwise XOR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ const bitXor = /*@__PURE__*/ nodeProxy( OperatorNode, '^' ); + +/** + * Shifts a node to the left. + * + * @function + * @param {Node} aNode - The node to shift. + * @param {Node} bNode - The value to shift. + * @returns {OperatorNode} + */ const shiftLeft = /*@__PURE__*/ nodeProxy( OperatorNode, '<<' ); + +/** + * Shifts a node to the right. + * + * @function + * @param {Node} aNode - The node to shift. + * @param {Node} bNode - The value to shift. + * @returns {OperatorNode} + */ const shiftRight = /*@__PURE__*/ nodeProxy( OperatorNode, '>>' ); addMethodChaining( 'add', add ); @@ -4301,7 +4915,13 @@ addMethodChaining( 'bitXor', bitXor ); addMethodChaining( 'shiftLeft', shiftLeft ); addMethodChaining( 'shiftRight', shiftRight ); - +/** + * @function + * @deprecated since r168. Use {@link modInt} instead. + * + * @param {...any} params + * @returns {Function} + */ const remainder = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.OperatorNode: .remainder() has been renamed to .modInt().' ); @@ -4311,6 +4931,8 @@ const remainder = ( ...params ) => { // @deprecated, r168 addMethodChaining( 'remainder', remainder ); +/** @module MathNode **/ + /** * This node represents a variety of mathematical methods available in shaders. * They are divided into three categories: @@ -4342,11 +4964,9 @@ class MathNode extends TempNode { super(); /** - * This flag can be used for type testing. + * The method name. * - * @type {Boolean} - * @readonly - * @default true + * @type {String} */ this.method = method; @@ -4373,6 +4993,15 @@ class MathNode extends TempNode { */ this.cNode = cNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isMathNode = true; + } /** @@ -4449,7 +5078,7 @@ class MathNode extends TempNode { generate( builder, output ) { - const method = this.method; + let method = this.method; const type = this.getNodeType( builder ); const inputType = this.getInputType( builder ); @@ -4458,7 +5087,7 @@ class MathNode extends TempNode { const b = this.bNode; const c = this.cNode; - const isWebGL = builder.renderer.isWebGLRenderer === true; + const coordinateSystem = builder.renderer.coordinateSystem; if ( method === MathNode.TRANSFORM_DIRECTION ) { @@ -4509,14 +5138,14 @@ class MathNode extends TempNode { b.build( builder, type ) ); - } else if ( isWebGL && method === MathNode.STEP ) { + } else if ( coordinateSystem === WebGLCoordinateSystem && 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 ) { + } else if ( ( coordinateSystem === WebGLCoordinateSystem && ( method === MathNode.MIN || method === MathNode.MAX ) ) || method === MathNode.MOD ) { params.push( a.build( builder, inputType ), @@ -4541,6 +5170,12 @@ class MathNode extends TempNode { } else { + if ( coordinateSystem === WebGPUCoordinateSystem && method === MathNode.ATAN && b !== null ) { + + method = 'atan2'; + + } + params.push( a.build( builder, inputType ) ); if ( b !== null ) params.push( b.build( builder, inputType ) ); if ( c !== null ) params.push( c.build( builder, inputType ) ); @@ -4575,7 +5210,6 @@ class MathNode extends TempNode { MathNode.ALL = 'all'; MathNode.ANY = 'any'; -MathNode.EQUALS = 'equals'; MathNode.RADIANS = 'radians'; MathNode.DEGREES = 'degrees'; @@ -4606,12 +5240,12 @@ MathNode.ROUND = 'round'; MathNode.RECIPROCAL = 'reciprocal'; MathNode.TRUNC = 'trunc'; MathNode.FWIDTH = 'fwidth'; -MathNode.BITCAST = 'bitcast'; MathNode.TRANSPOSE = 'transpose'; // 2 inputs -MathNode.ATAN2 = 'atan2'; +MathNode.BITCAST = 'bitcast'; +MathNode.EQUALS = 'equals'; MathNode.MIN = 'min'; MathNode.MAX = 'max'; MathNode.MOD = 'mod'; @@ -4632,72 +5266,574 @@ MathNode.REFRACT = 'refract'; MathNode.SMOOTHSTEP = 'smoothstep'; MathNode.FACEFORWARD = 'faceforward'; +// 1 inputs + +/** + * A small value used to handle floating-point precision errors. + * + * @type {Node} + */ const EPSILON = /*@__PURE__*/ float( 1e-6 ); + +/** + * Represents infinity. + * + * @type {Node} + */ const INFINITY = /*@__PURE__*/ float( 1e6 ); + +/** + * Represents PI. + * + * @type {Node} + */ const PI = /*@__PURE__*/ float( Math.PI ); + +/** + * Represents PI * 2. + * + * @type {Node} + */ const PI2 = /*@__PURE__*/ float( Math.PI * 2 ); +/** + * Returns `true` if all components of `x` are `true`. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const all = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ALL ); + +/** + * Returns `true` if any components of `x` are `true`. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const any = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ANY ); -const equals = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EQUALS ); +/** + * Converts a quantity in degrees to radians. + * + * @function + * @param {Node | Number} x - The input in degrees. + * @returns {Node} + */ const radians = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RADIANS ); + +/** + * Convert a quantity in radians to degrees. + * + * @function + * @param {Node | Number} x - The input in radians. + * @returns {Node} + */ const degrees = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DEGREES ); + +/** + * Returns the natural exponentiation of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const exp = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP ); + +/** + * Returns 2 raised to the power of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const exp2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP2 ); + +/** + * Returns the natural logarithm of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const log = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG ); + +/** + * Returns the base 2 logarithm of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const log2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG2 ); + +/** + * Returns the square root of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const sqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SQRT ); + +/** + * Returns the inverse of the square root of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const inverseSqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.INVERSE_SQRT ); + +/** + * Finds the nearest integer less than or equal to the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const floor = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FLOOR ); + +/** + * Finds the nearest integer that is greater than or equal to the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const ceil = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CEIL ); + +/** + * Calculates the unit vector in the same direction as the original vector. + * + * @function + * @param {Node} x - The input vector. + * @returns {Node} + */ const normalize = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NORMALIZE ); + +/** + * Computes the fractional part of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const fract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FRACT ); + +/** + * Returns the sine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const sin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIN ); + +/** + * Returns the cosine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const cos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.COS ); + +/** + * Returns the tangent of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const tan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TAN ); + +/** + * Returns the arcsine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const asin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ASIN ); + +/** + * Returns the arccosine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const acos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ACOS ); + +/** + * Returns the arc-tangent of the parameter. + * If two parameters are provided, the result is `atan2(y/x)`. + * + * @function + * @param {Node | Number} y - The y parameter. + * @param {(Node | Number)?} x - The x parameter. + * @returns {Node} + */ const atan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN ); + +/** + * Returns the absolute value of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const abs = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ABS ); + +/** + * Extracts the sign of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const sign = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIGN ); + +/** + * Calculates the length of a vector. + * + * @function + * @param {Node} x - The parameter. + * @returns {Node} + */ const length = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LENGTH ); + +/** + * Negates the value of the parameter (-x). + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const negate = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NEGATE ); + +/** + * Return `1` minus the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const oneMinus = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ONE_MINUS ); + +/** + * Returns the partial derivative of the parameter with respect to x. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const dFdx = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDX ); + +/** + * Returns the partial derivative of the parameter with respect to y. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const dFdy = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDY ); + +/** + * Rounds the parameter to the nearest integer. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const round = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ROUND ); + +/** + * Returns the reciprocal of the parameter `(1/x)`. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const reciprocal = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RECIPROCAL ); + +/** + * Truncates the parameter, removing the fractional part. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const trunc = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRUNC ); + +/** + * Returns the sum of the absolute derivatives in x and y. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ const fwidth = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FWIDTH ); -const bitcast = /*@__PURE__*/ nodeProxy( MathNode, MathNode.BITCAST ); + +/** + * Returns the transpose of a matrix. + * + * @function + * @param {Node} x - The parameter. + * @returns {Node} + */ const transpose = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSPOSE ); -const atan2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN2 ); +// 2 inputs + +/** + * Reinterpret the bit representation of a value in one type as a value in another type. + * + * @function + * @param {Node | Number} x - The parameter. + * @param {String} y - The new type. + * @returns {Node} + */ +const bitcast = /*@__PURE__*/ nodeProxy( MathNode, MathNode.BITCAST ); + +/** + * Returns `true` if `x` equals `y`. + * + * @function + * @param {Node | Number} x - The first parameter. + * @param {Node | Number} y - The second parameter. + * @returns {Node} + */ +const equals = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EQUALS ); + +/** + * Returns the lesser of two values. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ const min$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIN ); + +/** + * Returns the greater of two values. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ const max$1 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MAX ); + +/** + * Computes the remainder of dividing the first node by the second one. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ const mod = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MOD ); + +/** + * Generate a step function by comparing two values. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ const step = /*@__PURE__*/ nodeProxy( MathNode, MathNode.STEP ); + +/** + * Calculates the reflection direction for an incident vector. + * + * @function + * @param {Node} I - The incident vector. + * @param {Node} N - The normal vector. + * @returns {Node} + */ const reflect = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFLECT ); + +/** + * Calculates the distance between two points. + * + * @function + * @param {Node} x - The first point. + * @param {Node} y - The second point. + * @returns {Node} + */ const distance = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DISTANCE ); + +/** + * Calculates the absolute difference between two values. + * + * @function + * @param {Node | Number} x - The first parameter. + * @param {Node | Number} y - The second parameter. + * @returns {Node} + */ const difference = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DIFFERENCE ); + +/** + * Calculates the dot product of two vectors. + * + * @function + * @param {Node} x - The first vector. + * @param {Node} y - The second vector. + * @returns {Node} + */ const dot = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DOT ); + +/** + * Calculates the cross product of two vectors. + * + * @function + * @param {Node} x - The first vector. + * @param {Node} y - The second vector. + * @returns {Node} + */ const cross = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CROSS ); + +/** + * Return the value of the first parameter raised to the power of the second one. + * + * @function + * @param {Node | Number} x - The first parameter. + * @param {Node | Number} y - The second parameter. + * @returns {Node} + */ const pow = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW ); + +/** + * Returns the square of the parameter. + * + * @function + * @param {Node | Number} x - The first parameter. + * @returns {Node} + */ const pow2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 2 ); + +/** + * Returns the cube of the parameter. + * + * @function + * @param {Node | Number} x - The first parameter. + * @returns {Node} + */ const pow3 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 3 ); + +/** + * Returns the fourth power of the parameter. + * + * @function + * @param {Node | Number} x - The first parameter. + * @returns {Node} + */ const pow4 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 4 ); + +/** + * Transforms the direction of a vector by a matrix and then normalizes the result. + * + * @function + * @param {Node} direction - The direction vector. + * @param {Node} matrix - The transformation matrix. + * @returns {Node} + */ const transformDirection = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSFORM_DIRECTION ); +/** + * Returns the cube root of a number. + * + * @function + * @param {Node | Number} a - The first parameter. + * @returns {Node} + */ const cbrt = ( a ) => mul( sign( a ), pow( abs( a ), 1.0 / 3.0 ) ); + +/** + * Calculate the squared length of a vector. + * + * @function + * @param {Node} a - The vector. + * @returns {Node} + */ const lengthSq = ( a ) => dot( a, a ); + +/** + * Linearly interpolates between two values. + * + * @function + * @param {Node | Number} a - The first parameter. + * @param {Node | Number} b - The second parameter. + * @param {Node | Number} t - The interpolation value. + * @returns {Node} + */ const mix = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIX ); + +/** + * Constrains a value to lie between two further values. + * + * @function + * @param {Node | Number} value - The value to constrain. + * @param {Node | Number} [low=0] - The lower bound. + * @param {Node | Number} [high=1] - The upper bound. + * @returns {Node} + */ const clamp = ( value, low = 0, high = 1 ) => nodeObject( new MathNode( MathNode.CLAMP, nodeObject( value ), nodeObject( low ), nodeObject( high ) ) ); + +/** + * Constrains a value between `0` and `1`. + * + * @function + * @param {Node | Number} value - The value to constrain. + * @returns {Node} + */ const saturate = ( value ) => clamp( value ); + +/** + * Calculates the refraction direction for an incident vector. + * + * @function + * @param {Node} I - The incident vector. + * @param {Node} N - The normal vector. + * @param {Node} eta - The the ratio of indices of refraction. + * @returns {Node} + */ const refract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFRACT ); + +/** + * Performs a Hermite interpolation between two values. + * + * @function + * @param {Node | Number} low - The value of the lower edge of the Hermite function. + * @param {Node | Number} high - The value of the upper edge of the Hermite function. + * @param {Node | Number} x - The source value for interpolation. + * @returns {Node} + */ const smoothstep = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SMOOTHSTEP ); + +/** + * Returns a vector pointing in the same direction as another. + * + * @function + * @param {Node} N - The vector to orient. + * @param {Node} I - The incident vector. + * @param {Node} Nref - The reference vector. + * @returns {Node} + */ const faceForward = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FACEFORWARD ); +/** + * Returns a random value for the given uv. + * + * @function + * @param {Node} uv - The uv node. + * @returns {Node} + */ const rand = /*@__PURE__*/ Fn( ( [ uv ] ) => { const a = 12.9898, b = 78.233, c = 43758.5453; @@ -4707,9 +5843,52 @@ const rand = /*@__PURE__*/ Fn( ( [ uv ] ) => { } ); +/** + * Alias for `mix()` with a different parameter order. + * + * @function + * @param {Node | Number} t - The interpolation value. + * @param {Node | Number} e1 - The first parameter. + * @param {Node | Number} e2 - The second parameter. + * @returns {Node} + */ const mixElement = ( t, e1, e2 ) => mix( e1, e2, t ); + +/** + * Alias for `smoothstep()` with a different parameter order. + * + * @function + * @param {Node | Number} x - The source value for interpolation. + * @param {Node | Number} low - The value of the lower edge of the Hermite function. + * @param {Node | Number} high - The value of the upper edge of the Hermite function. + * @returns {Node} + */ const smoothstepElement = ( x, low, high ) => smoothstep( low, high, x ); +/** + * Returns the arc-tangent of the quotient of its parameters. + * + * @function + * @deprecated since r172. Use {@link atan} instead. + * + * @param {Node | Number} y - The y parameter. + * @param {Node | Number} x - The x parameter. + * @returns {Node} + */ +const atan2 = ( y, x ) => { // @deprecated, r172 + + console.warn( 'THREE.TSL: "atan2" is overloaded. Use "atan" instead.' ); + return atan( y, x ); + +}; + +// GLSL alias function + +const faceforward = faceForward; +const inversesqrt = inverseSqrt; + +// Method chaining + addMethodChaining( 'all', all ); addMethodChaining( 'any', any ); addMethodChaining( 'equals', equals ); @@ -4769,6 +5948,8 @@ addMethodChaining( 'cbrt', cbrt ); addMethodChaining( 'transpose', transpose ); addMethodChaining( 'rand', rand ); +/** @module ConditionalNode **/ + /** * Represents a logical `if/else` statement. Can be used as an alternative * to the `If()`/`Else()` syntax. @@ -4777,7 +5958,7 @@ addMethodChaining( 'rand', rand ); * ```js * velocity = position.greaterThanEqual( limit ).select( velocity.negate(), velocity ); * ``` - * The `select()` method is called in a chaining fashion on a codition. The parameter nodes of `select()` + * The `select()` method is called in a chaining fashion on a condition. The parameter nodes of `select()` * determine the outcome of the entire statement. * * @augments Node @@ -4818,7 +5999,8 @@ class ConditionalNode extends Node { /** * The node that is evaluate when the condition ends up `false`. * - * @type {Node} + * @type {Node?} + * @default null */ this.elseNode = elseNode; @@ -4833,11 +6015,23 @@ class ConditionalNode extends Node { */ getNodeType( builder ) { - const ifType = this.ifNode.getNodeType( builder ); + const { ifNode, elseNode } = builder.getNodeProperties( this ); + + if ( ifNode === undefined ) { + + // fallback setup + + this.setup( builder ); + + return this.getNodeType( builder ); - if ( this.elseNode !== null ) { + } + + const ifType = ifNode.getNodeType( builder ); + + if ( elseNode !== null ) { - const elseType = this.elseNode.getNodeType( builder ); + const elseType = elseNode.getNodeType( builder ); if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) { @@ -4948,12 +6142,28 @@ class ConditionalNode extends Node { } +/** + * TSL function for creating a conditional node. + * + * @function + * @param {Node} condNode - The node that defines the condition. + * @param {Node} ifNode - The node that is evaluate when the condition ends up `true`. + * @param {Node?} [elseNode=null] - The node that is evaluate when the condition ends up `false`. + * @returns {ConditionalNode} + */ const select = /*@__PURE__*/ nodeProxy( ConditionalNode ); addMethodChaining( 'select', select ); -// +// deprecated +/** + * @function + * @deprecated since r168. Use {@link select} instead. + * + * @param {...any} params + * @returns {ConditionalNode} + */ const cond = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.ConditionalNode: cond() has been renamed to select().' ); @@ -4963,6 +6173,8 @@ const cond = ( ...params ) => { // @deprecated, r168 addMethodChaining( 'cond', cond ); +/** @module ContextNode **/ + /** * This node can be used as a context management component for another node. * {@link NodeBuilder} performs its node building process in a specific context and @@ -5018,9 +6230,9 @@ class ContextNode extends Node { } /** - * This method is overwritten to ensure it returns the reference to {@link ContextNode#node}. + * This method is overwritten to ensure it returns the reference to {@link module:ContextNode~ContextNode#node}. * - * @return {Node} A reference to {@link ContextNode#node}. + * @return {Node} A reference to {@link module:ContextNode~ContextNode#node}. */ getScope() { @@ -5029,10 +6241,10 @@ class ContextNode extends Node { } /** - * This method is overwritten to ensure it returns the type to {@link ContextNode#node}. + * This method is overwritten to ensure it returns the type of {@link module:ContextNode~ContextNode#node}. * * @param {NodeBuilder} builder - The current node builder. - * @return {String} The type of {@link ContextNode#node}. + * @return {String} The node type. */ getNodeType( builder ) { @@ -5076,12 +6288,31 @@ class ContextNode extends Node { } +/** + * TSL function for creating a context node. + * + * @function + * @param {Node} node - The node whose context should be modified. + * @param {Object} [value={}] - The modified context data. + * @returns {ContextNode} + */ const context = /*@__PURE__*/ nodeProxy( ContextNode ); + +/** + * TSL function for defining a label context value for a given node. + * + * @function + * @param {Node} node - The node whose context should be modified. + * @param {String} name - The name/label to set. + * @returns {ContextNode} + */ const label = ( node, name ) => context( node, { label: name } ); addMethodChaining( 'context', context ); addMethodChaining( 'label', label ); +/** @module VarNode **/ + /** * Class for representing shader variables as nodes. Variables are created from * existing nodes like the following: @@ -5105,8 +6336,9 @@ class VarNode extends Node { * * @param {Node} node - The node for which a variable should be created. * @param {String?} name - The name of the variable in the shader. + * @param {Boolean?} readOnly - The read-only flag. */ - constructor( node, name = null ) { + constructor( node, name = null, readOnly = false ) { super(); @@ -5143,6 +6375,15 @@ class VarNode extends Node { */ this.isVarNode = true; + /** + * + * The read-only flag. + * + * @type {Boolean} + * @default false + */ + this.readOnly = readOnly; + } getHash( builder ) { @@ -5159,15 +6400,50 @@ class VarNode extends Node { generate( builder ) { - const { node, name } = this; + const { node, name, readOnly } = this; + const { renderer } = builder; + + const isWebGPUBackend = renderer.backend.isWebGPUBackend === true; + + let isDeterministic = false; + let shouldTreatAsReadOnly = false; - const nodeVar = builder.getVarFromNode( this, name, builder.getVectorType( this.getNodeType( builder ) ) ); + if ( readOnly ) { + + isDeterministic = builder.isDeterministic( node ); + + shouldTreatAsReadOnly = isWebGPUBackend ? readOnly : isDeterministic; + + } + + const vectorType = builder.getVectorType( this.getNodeType( builder ) ); + const snippet = node.build( builder, vectorType ); + + const nodeVar = builder.getVarFromNode( this, name, vectorType, undefined, shouldTreatAsReadOnly ); const propertyName = builder.getPropertyName( nodeVar ); - const snippet = node.build( builder, nodeVar.type ); + let declarationPrefix = propertyName; + + if ( shouldTreatAsReadOnly ) { + + const type = builder.getType( nodeVar.type ); + + if ( isWebGPUBackend ) { - builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); + declarationPrefix = isDeterministic + ? `const ${ propertyName }` + : `let ${ propertyName }`; + + } else { + + declarationPrefix = `const ${ type } ${ propertyName }`; + + } + + } + + builder.addLineFlowCode( `${ declarationPrefix } = ${ snippet }`, this ); return propertyName; @@ -5175,15 +6451,53 @@ class VarNode extends Node { } +/** + * TSL function for creating a var node. + * + * @function + * @param {Node} node - The node for which a variable should be created. + * @param {String?} name - The name of the variable in the shader. + * @returns {VarNode} + */ const createVar = /*@__PURE__*/ nodeProxy( VarNode ); -addMethodChaining( 'toVar', ( ...params ) => createVar( ...params ).append() ); +/** + * TSL function for creating a var node. + * + * @function + * @param {Node} node - The node for which a variable should be created. + * @param {String?} name - The name of the variable in the shader. + * @returns {VarNode} + */ +const Var = ( node, name = null ) => createVar( node, name ).append(); + +/** + * TSL function for creating a const node. + * + * @function + * @param {Node} node - The node for which a constant should be created. + * @param {String?} name - The name of the constant in the shader. + * @returns {VarNode} + */ +const Const = ( node, name = null ) => createVar( node, name, true ).append(); + +// Method chaining + +addMethodChaining( 'toVar', Var ); +addMethodChaining( 'toConst', Const ); // Deprecated +/** + * @function + * @deprecated since r170. Use `Var( node )` or `node.toVar()` instead. + * + * @param {Any} node + * @returns {VarNode} + */ const temp = ( node ) => { // @deprecated, r170 - console.warn( 'TSL: "temp" is deprecated. Use ".toVar()" instead.' ); + console.warn( 'TSL: "temp( node )" is deprecated. Use "Var( node )" or "node.toVar()" instead.' ); return createVar( node ); @@ -5191,6 +6505,8 @@ const temp = ( node ) => { // @deprecated, r170 addMethodChaining( 'temp', temp ); +/** @module VaryingNode **/ + /** * Class for representing shader varyings as nodes. Varyings are create from * existing nodes like the following: @@ -5320,7 +6636,9 @@ class VaryingNode extends Node { const properties = builder.getNodeProperties( this ); const varying = this.setupVarying( builder ); - if ( properties.propertyName === undefined ) { + const needsReassign = builder.shaderStage === 'fragment' && properties.reassignPosition === true && builder.context.needsPositionReassign; + + if ( properties.propertyName === undefined || needsReassign ) { const type = this.getNodeType( builder ); const propertyName = builder.getPropertyName( varying, NodeShaderStage.VERTEX ); @@ -5330,6 +6648,17 @@ class VaryingNode extends Node { properties.propertyName = propertyName; + if ( needsReassign ) { + + // once reassign varying in fragment stage + properties.reassignPosition = false; + + } else if ( properties.reassignPosition === undefined && builder.context.isPositionNodeInput ) { + + properties.reassignPosition = true; + + } + } return builder.getPropertyName( varying ); @@ -5338,9 +6667,27 @@ class VaryingNode extends Node { } +/** + * TSL function for creating a varying node. + * + * @function + * @param {Node} node - The node for which a varying should be created. + * @param {String?} name - The name of the varying in the shader. + * @returns {VaryingNode} + */ const varying = /*@__PURE__*/ nodeProxy( VaryingNode ); +/** + * Computes a node in the vertex stage. + * + * @function + * @param {Node} node - The node which should be executed in the vertex stage. + * @returns {VaryingNode} + */ +const vertexStage = ( node ) => varying( node ); + addMethodChaining( 'varying', varying ); +addMethodChaining( 'vertexStage', vertexStage ); /** @module ColorSpaceFunctions **/ @@ -5394,6 +6741,8 @@ const sRGBTransferOETF = /*@__PURE__*/ Fn( ( [ color ] ) => { ] } ); +/** @module ColorSpaceNode **/ + const WORKING_COLOR_SPACE = 'WorkingColorSpace'; const OUTPUT_COLOR_SPACE = 'OutputColorSpace'; @@ -5432,14 +6781,14 @@ class ColorSpaceNode extends TempNode { /** * The source color space. * - * @type {Node} + * @type {String} */ this.source = source; /** * The target color space. * - * @type {Node} + * @type {String} */ this.target = target; @@ -5512,12 +6861,53 @@ class ColorSpaceNode extends TempNode { } +/** + * TSL function for converting a given color node to the current output color space. + * + * @function + * @param {Node} node - Represents the node to convert. + * @returns {ColorSpaceNode} + */ const toOutputColorSpace = ( node ) => nodeObject( new ColorSpaceNode( nodeObject( node ), WORKING_COLOR_SPACE, OUTPUT_COLOR_SPACE ) ); + +/** + * TSL function for converting a given color node to the current working color space. + * + * @function + * @param {Node} node - Represents the node to convert. + * @returns {ColorSpaceNode} + */ const toWorkingColorSpace = ( node ) => nodeObject( new ColorSpaceNode( nodeObject( node ), OUTPUT_COLOR_SPACE, WORKING_COLOR_SPACE ) ); +/** + * TSL function for converting a given color node from the current working color space to the given color space. + * + * @function + * @param {Node} node - Represents the node to convert. + * @param {String} colorSpace - The target color space. + * @returns {ColorSpaceNode} + */ const workingToColorSpace = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), WORKING_COLOR_SPACE, colorSpace ) ); + +/** + * TSL function for converting a given color node from the given color space to the current working color space. + * + * @function + * @param {Node} node - Represents the node to convert. + * @param {String} colorSpace - The source color space. + * @returns {ColorSpaceNode} + */ const colorSpaceToWorking = ( node, colorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), colorSpace, WORKING_COLOR_SPACE ) ); +/** + * TSL function for converting a given color node from one color space to another one. + * + * @function + * @param {Node} node - Represents the node to convert. + * @param {String} sourceColorSpace - The source color space. + * @param {String} targetColorSpace - The target color space. + * @returns {ColorSpaceNode} + */ const convertColorSpace = ( node, sourceColorSpace, targetColorSpace ) => nodeObject( new ColorSpaceNode( nodeObject( node ), sourceColorSpace, targetColorSpace ) ); addMethodChaining( 'toOutputColorSpace', toOutputColorSpace ); @@ -5526,6 +6916,17 @@ addMethodChaining( 'toWorkingColorSpace', toWorkingColorSpace ); addMethodChaining( 'workingToColorSpace', workingToColorSpace ); addMethodChaining( 'colorSpaceToWorking', colorSpaceToWorking ); +// TODO: Avoid duplicated code and ues only ReferenceBaseNode or ReferenceNode + +/** @module ReferenceBaseNode **/ + +/** + * This class is only relevant if the referenced property is array-like. + * In this case, `ReferenceElementNode` allows to refer to a specific + * element inside the data structure via an index. + * + * @augments ArrayElementNode + */ let ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode { static get type() { @@ -5534,16 +6935,43 @@ let ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode } + /** + * Constructs a new reference element node. + * + * @param {Node?} referenceNode - The reference node. + * @param {Node} indexNode - The index node that defines the element access. + */ constructor( referenceNode, indexNode ) { super( referenceNode, indexNode ); + /** + * Similar to {@link module:ReferenceBaseNode~ReferenceBaseNode#reference}, an additional + * property references to the current node. + * + * @type {Node?} + * @default null + */ this.referenceNode = referenceNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isReferenceElementNode = true; } + /** + * This method is overwritten since the node type is inferred from + * the uniform type of the reference node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType() { return this.referenceNode.uniformType; @@ -5562,6 +6990,14 @@ let ReferenceElementNode$1 = class ReferenceElementNode extends ArrayElementNode }; +/** + * Base class for nodes which establishes a reference to a property of another object. + * In this way, the value of the node is automatically linked to the value of + * referenced object. Reference nodes internally represent the linked value + * as a uniform. + * + * @augments Node + */ class ReferenceBaseNode extends Node { static get type() { @@ -5570,24 +7006,97 @@ class ReferenceBaseNode extends Node { } + /** + * Constructs a new reference base node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} uniformType - The uniform type that should be used to represent the property value. + * @param {Object?} [object=null] - The object the property belongs to. + * @param {Number?} [count=null] - When the linked property is an array-like, this parameter defines its length. + */ constructor( property, uniformType, object = null, count = null ) { super(); + /** + * The name of the property the node refers to. + * + * @type {String} + */ this.property = property; + + /** + * The uniform type that should be used to represent the property value. + * + * @type {String} + */ this.uniformType = uniformType; + + /** + * The object the property belongs to. + * + * @type {Object?} + * @default null + */ this.object = object; + + /** + * When the linked property is an array, this parameter defines its length. + * + * @type {Number?} + * @default null + */ this.count = count; + /** + * The property name might have dots so nested properties can be referred. + * The hierarchy of the names is stored inside this array. + * + * @type {Array} + */ this.properties = property.split( '.' ); + + /** + * Points to the current referred object. This property exists next to {@link module:ReferenceNode~ReferenceNode#object} + * since the final reference might be updated from calling code. + * + * @type {Object?} + * @default null + */ this.reference = object; + + /** + * The uniform node that holds the value of the reference node. + * + * @type {UniformNode} + * @default null + */ this.node = null; + + /** + * The uniform group of the internal uniform. + * + * @type {UniformGroupNode} + * @default null + */ this.group = null; + /** + * Overwritten since reference nodes are updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; } + /** + * Sets the uniform group for this reference node. + * + * @param {UniformGroupNode} group - The uniform group to set. + * @return {ReferenceBaseNode} A reference to this node. + */ setGroup( group ) { this.group = group; @@ -5596,12 +7105,25 @@ class ReferenceBaseNode extends Node { } + /** + * When the referred property is array-like, this method can be used + * to access elements via an index node. + * + * @param {IndexNode} indexNode - indexNode. + * @return {ReferenceElementNode} A reference to an element. + */ element( indexNode ) { return nodeObject( new ReferenceElementNode$1( this, nodeObject( indexNode ) ) ); } + /** + * Sets the node type which automatically defines the internal + * uniform type. + * + * @param {String} uniformType - The type to set. + */ setNodeType( uniformType ) { const node = uniform( null, uniformType ).getSelf(); @@ -5616,6 +7138,13 @@ class ReferenceBaseNode extends Node { } + /** + * This method is overwritten since the node type is inferred from + * the type of the reference node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( this.node === null ) { @@ -5629,6 +7158,12 @@ class ReferenceBaseNode extends Node { } + /** + * Returns the property value from the given referred object. + * + * @param {Object} [object=this.reference] - The object to retrieve the property value from. + * @return {Any} The value. + */ getValueFromReference( object = this.reference ) { const { properties } = this; @@ -5645,6 +7180,13 @@ class ReferenceBaseNode extends Node { } + /** + * Allows to update the reference based on the given state. The state is only + * evaluated {@link module:ReferenceBaseNode~ReferenceBaseNode#object} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.object !== null ? this.object : state.object; @@ -5653,6 +7195,12 @@ class ReferenceBaseNode extends Node { } + /** + * The output of the reference node is the internal uniform node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {UniformNode} The output node. + */ setup() { this.updateValue(); @@ -5661,12 +7209,21 @@ class ReferenceBaseNode extends Node { } + /** + * Overwritten to to update the internal uniform value. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( /*frame*/ ) { this.updateValue(); } + /** + * Retrieves the value from the referred object property and uses it + * to updated the internal uniform. + */ updateValue() { if ( this.node === null ) this.setNodeType( this.uniformType ); @@ -5687,8 +7244,30 @@ class ReferenceBaseNode extends Node { } +/** + * TSL function for creating a reference base node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Object} object - The object the property belongs to. + * @returns {ReferenceBaseNode} + */ const reference$1 = ( name, type, object ) => nodeObject( new ReferenceBaseNode( name, type, object ) ); +/** @module RendererReferenceNode **/ + +/** + * This node is a special type of reference node which is intended + * for linking renderer properties with node values. + * ```js + * const exposureNode = rendererReference( 'toneMappingExposure', 'float', renderer ); + * ``` + * When changing `renderer.toneMappingExposure`, the node value of `exposureNode` will + * automatically be updated. + * + * @augments ReferenceBaseNode + */ class RendererReferenceNode extends ReferenceBaseNode { static get type() { @@ -5697,16 +7276,38 @@ class RendererReferenceNode extends ReferenceBaseNode { } + /** + * Constructs a new renderer reference node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} inputType - The uniform type that should be used to represent the property value. + * @param {Renderer?} [renderer=null] - The renderer the property belongs to. When no renderer is set, + * the node refers to the renderer of the current state. + */ constructor( property, inputType, renderer = null ) { super( property, inputType, renderer ); + /** + * The renderer the property belongs to. When no renderer is set, + * the node refers to the renderer of the current state. + * + * @type {Renderer?} + * @default null + */ this.renderer = renderer; this.setGroup( renderGroup ); } + /** + * Updates the reference based on the given state. The state is only evaluated + * {@link module:RendererReferenceNode~RendererReferenceNode#renderer} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.renderer !== null ? this.renderer : state.renderer; @@ -5717,7 +7318,19 @@ class RendererReferenceNode extends ReferenceBaseNode { } -const rendererReference = ( name, type, renderer ) => nodeObject( new RendererReferenceNode( name, type, renderer ) ); +/** + * TSL function for creating a renderer reference node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Renderer?} [renderer=null] - The renderer the property belongs to. When no renderer is set, + * the node refers to the renderer of the current state. + * @returns {RendererReferenceNode} + */ +const rendererReference = ( name, type, renderer = null ) => nodeObject( new RendererReferenceNode( name, type, renderer ) ); + +/** @module ToneMappingNode **/ /** * This node represents a tone mapping operation. @@ -5761,7 +7374,7 @@ class ToneMappingNode extends TempNode { /** * Represents the color to process. * - * @type {Node} + * @type {Node?} * @default null */ this.colorNode = colorNode; @@ -5809,11 +7422,50 @@ class ToneMappingNode extends TempNode { } +/** + * TSL function for creating a tone mapping node. + * + * @function + * @param {Number} mapping - The tone mapping type. + * @param {Node | Number} exposure - The tone mapping exposure. + * @param {Node | Color} color - The color node to process. + * @returns {ToneMappingNode} + */ const toneMapping = ( mapping, exposure, color ) => nodeObject( new ToneMappingNode( mapping, nodeObject( exposure ), nodeObject( color ) ) ); + +/** + * TSL object that represents the global tone mapping exposure of the renderer. + * + * @type {RendererReferenceNode} + */ const toneMappingExposure = /*@__PURE__*/ rendererReference( 'toneMappingExposure', 'float' ); addMethodChaining( 'toneMapping', ( color, mapping, exposure ) => toneMapping( mapping, exposure, color ) ); +/** @module BufferAttributeNode **/ + +/** + * In earlier `three.js` versions it was only possible to define attribute data + * on geometry level. With `BufferAttributeNode`, it is also possible to do this + * on the node level. + * ```js + * const geometry = new THREE.PlaneGeometry(); + * const positionAttribute = geometry.getAttribute( 'position' ); + * + * const colors = []; + * for ( let i = 0; i < position.count; i ++ ) { + * colors.push( 1, 0, 0 ); + * } + * + * material.colorNode = bufferAttribute( new THREE.Float32BufferAttribute( colors, 3 ) ); + * ``` + * This new approach is especially interesting when geometry data are generated via + * compute shaders. The below line converts a storage buffer into an attribute node. + * ```js + * material.positionNode = positionBuffer.toAttribute(); + * ``` + * @augments InputNode + */ class BufferAttributeNode extends InputNode { static get type() { @@ -5822,21 +7474,82 @@ class BufferAttributeNode extends InputNode { } + /** + * Constructs a new buffer attribute node. + * + * @param {BufferAttribute|InterleavedBuffer|TypedArray} value - The attribute data. + * @param {String?} [bufferType=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [bufferStride=0] - The buffer stride. + * @param {Number} [bufferOffset=0] - The buffer offset. + */ constructor( value, bufferType = null, bufferStride = 0, bufferOffset = 0 ) { super( value, bufferType ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBufferNode = true; + /** + * The buffer type (e.g. `'vec3'`). + * + * @type {String} + * @default null + */ this.bufferType = bufferType; + + /** + * The buffer stride. + * + * @type {Number} + * @default 0 + */ this.bufferStride = bufferStride; + + /** + * The buffer offset. + * + * @type {Number} + * @default 0 + */ this.bufferOffset = bufferOffset; + /** + * The usage property. Set this to `THREE.DynamicDrawUsage` via `.setUsage()`, + * if you are planning to update the attribute data per frame. + * + * @type {Number} + * @default StaticDrawUsage + */ this.usage = StaticDrawUsage; + + /** + * Whether the attribute is instanced or not. + * + * @type {Boolean} + * @default false + */ this.instanced = false; + /** + * A reference to the buffer attribute. + * + * @type {BufferAttribute?} + * @default null + */ this.attribute = null; + /** + * `BufferAttributeNode` sets this property to `true` by default. + * + * @type {Boolean} + * @default true + */ this.global = true; if ( value && value.isBufferAttribute === true ) { @@ -5849,6 +7562,13 @@ class BufferAttributeNode extends InputNode { } + /** + * This method is overwritten since the attribute data might be shared + * and thus the hash should be shared as well. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The hash. + */ getHash( builder ) { if ( this.bufferStride === 0 && this.bufferOffset === 0 ) { @@ -5873,6 +7593,13 @@ class BufferAttributeNode extends InputNode { } + /** + * This method is overwritten since the node type is inferred from + * the buffer attribute. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( this.bufferType === null ) { @@ -5885,6 +7612,13 @@ class BufferAttributeNode extends InputNode { } + /** + * Depending on which value was passed to the node, `setup()` behaves + * differently. If no instance of `BufferAttribute` was passed, the method + * creates an internal attribute and configures it respectively. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { if ( this.attribute !== null ) return; @@ -5905,6 +7639,12 @@ class BufferAttributeNode extends InputNode { } + /** + * Generates the code snippet of the buffer attribute node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( builder ) { const nodeType = this.getNodeType( builder ); @@ -5932,12 +7672,24 @@ class BufferAttributeNode extends InputNode { } + /** + * Overwrites the default implementation to return a fixed value `'bufferAttribute'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'bufferAttribute'; } + /** + * Sets the `usage` property to the given value. + * + * @param {Number} value - The usage to set. + * @return {BufferAttributeNode} A reference to this node. + */ setUsage( value ) { this.usage = value; @@ -5952,6 +7704,12 @@ class BufferAttributeNode extends InputNode { } + /** + * Sets the `instanced` property to the given value. + * + * @param {Number} value - The value to set. + * @return {BufferAttributeNode} A reference to this node. + */ setInstanced( value ) { this.instanced = value; @@ -5962,14 +7720,64 @@ class BufferAttributeNode extends InputNode { } -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 ); +/** + * TSL function for creating a buffer attribute node. + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +const bufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) ); -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 ); +/** + * TSL function for creating a buffer attribute node but with dynamic draw usage. + * Use this function if attribute data are updated per frame. + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +const dynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage ); + +/** + * TSL function for creating a buffer attribute node but with enabled instancing + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +const instancedBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setInstanced( true ); + +/** + * TSL function for creating a buffer attribute node but with dynamic draw usage and enabled instancing + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +const instancedDynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true ); addMethodChaining( 'toAttribute', ( bufferNode ) => bufferAttribute( bufferNode.value ) ); +/** @module ComputeNode **/ + +/** + * TODO + * + * @augments Node + */ class ComputeNode extends Node { static get type() { @@ -5978,39 +7786,116 @@ class ComputeNode extends Node { } + /** + * Constructs a new compute node. + * + * @param {Node} computeNode - TODO + * @param {Number} count - TODO. + * @param {Array} [workgroupSize=[64]] - TODO. + */ constructor( computeNode, count, workgroupSize = [ 64 ] ) { super( 'void' ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isComputeNode = true; + /** + * TODO + * + * @type {Node} + */ this.computeNode = computeNode; + /** + * TODO + * + * @type {Number} + */ this.count = count; + + /** + * TODO + * + * @type {Array} + * @default [64] + */ this.workgroupSize = workgroupSize; + + /** + * TODO + * + * @type {Number} + */ this.dispatchCount = 0; + /** + * TODO + * + * @type {Number} + */ this.version = 1; + + /** + * The name or label of the uniform. + * + * @type {String} + * @default '' + */ + this.name = ''; + + /** + * The `updateBeforeType` is set to `NodeUpdateType.OBJECT` since {@link ComputeNode#updateBefore} + * is executed once per object by default. + * + * @type {String} + * @default 'object' + */ this.updateBeforeType = NodeUpdateType.OBJECT; + /** + * TODO + * + * @type {Function} + */ this.onInitFunction = null; this.updateDispatchCount(); } + /** + * Executes the `dispose` event for this node. + */ dispose() { this.dispatchEvent( { type: 'dispose' } ); } - set needsUpdate( value ) { + /** + * Sets the {@link ComputeNode#name} property. + * + * @param {String} name - The name of the uniform. + * @return {ComputeNode} A reference to this node. + */ + label( name ) { - if ( value === true ) this.version ++; + this.name = name; + + return this; } + /** + * TODO + */ updateDispatchCount() { const { count, workgroupSize } = this; @@ -6024,6 +7909,12 @@ class ComputeNode extends Node { } + /** + * TODO + * + * @param {Function} callback - TODO. + * @return {ComputeNode} A reference to this node. + */ onInit( callback ) { this.onInitFunction = callback; @@ -6032,6 +7923,11 @@ class ComputeNode extends Node { } + /** + * The method execute the compute for this node. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ updateBefore( { renderer } ) { renderer.compute( this ); @@ -6058,10 +7954,21 @@ class ComputeNode extends Node { } +/** + * TSL function for creating a compute node. + * + * @function + * @param {Node} node - TODO + * @param {Number} count - TODO. + * @param {Array} [workgroupSize=[64]] - TODO. + * @returns {AtomicFunctionNode} + */ const compute = ( node, count, workgroupSize ) => nodeObject( new ComputeNode( nodeObject( node ), count, workgroupSize ) ); addMethodChaining( 'compute', compute ); +/** @module CacheNode **/ + /** * This node can be used as a cache management component for another node. * Caching is in general used by default in {@link NodeBuilder} but this node @@ -6115,7 +8022,16 @@ class CacheNode extends Node { getNodeType( builder ) { - return this.node.getNodeType( builder ); + const previousCache = builder.getCache(); + const cache = builder.getCacheFromNode( this, this.parent ); + + builder.setCache( cache ); + + const nodeType = this.node.getNodeType( builder ); + + builder.setCache( previousCache ); + + return nodeType; } @@ -6136,10 +8052,20 @@ class CacheNode extends Node { } -const cache = ( node, ...params ) => nodeObject( new CacheNode( nodeObject( node ), ...params ) ); +/** + * TSL function for creating a cache node. + * + * @function + * @param {Node} node - The node that should be cached. + * @param {Boolean} parent - Whether this node refers to a shared parent cache or not. + * @returns {CacheNode} + */ +const cache = ( node, parent ) => nodeObject( new CacheNode( nodeObject( node ), parent ) ); addMethodChaining( 'cache', cache ); +/** @module BypassNode **/ + /** * The class generates the code of a given node but returns another node in the output. * This can be used to call a method or node that does not return a value, i.e. @@ -6216,10 +8142,20 @@ class BypassNode extends Node { } +/** + * TSL function for creating a bypass node. + * + * @function + * @param {Node} outputNode - The output node. + * @param {Node} callNode - The call node. + * @returns {BypassNode} + */ const bypass = /*@__PURE__*/ nodeProxy( BypassNode ); addMethodChaining( 'bypass', bypass ); +/** @module RemapNode **/ + /** * This node allows to remap a node value from one range into another. E.g a value of * `0.4` in the range `[ 0.3, 0.5 ]` should be remapped into the normalized range `[ 0, 1 ]`. @@ -6310,12 +8246,37 @@ class RemapNode extends Node { } +/** + * TSL function for creating a remap node. + * + * @function + * @param {Node} node - The node that should be remapped. + * @param {Node} inLowNode - The source or current lower bound of the range. + * @param {Node} inHighNode - The source or current upper bound of the range. + * @param {Node} [outLowNode=float(0)] - The target lower bound of the range. + * @param {Node} [outHighNode=float(1)] - The target upper bound of the range. + * @returns {RemapNode} + */ const remap = /*@__PURE__*/ nodeProxy( RemapNode, null, null, { doClamp: false } ); + +/** + * TSL function for creating a remap node, but with enabled clamping. + * + * @function + * @param {Node} node - The node that should be remapped. + * @param {Node} inLowNode - The source or current lower bound of the range. + * @param {Node} inHighNode - The source or current upper bound of the range. + * @param {Node} [outLowNode=float(0)] - The target lower bound of the range. + * @param {Node} [outHighNode=float(1)] - The target upper bound of the range. + * @returns {RemapNode} + */ const remapClamp = /*@__PURE__*/ nodeProxy( RemapNode ); addMethodChaining( 'remap', remap ); addMethodChaining( 'remapClamp', remapClamp ); +/** @module ExpressionNode **/ + /** * This class can be used to implement basic expressions in shader code. * Basic examples for that are `return`, `continue` or `discard` statements. @@ -6369,6 +8330,14 @@ class ExpressionNode extends Node { } +/** + * TSL function for creating an expression node. + * + * @function + * @param {String} [snippet=''] - The native code snippet. + * @param {String} [nodeType='void'] - The node type. + * @returns {ExpressionNode} + */ const expression = /*@__PURE__*/ nodeProxy( ExpressionNode ); /** @module Discard **/ @@ -6392,6 +8361,8 @@ const Return = () => expression( 'return' ).append(); addMethodChaining( 'discard', Discard ); +/** @module RenderOutputNode **/ + /** * Normally, tone mapping and color conversion happens automatically * before outputting pixel too the default (screen) framebuffer. In certain @@ -6427,7 +8398,7 @@ class RenderOutputNode extends TempNode { * Constructs a new render output node. * * @param {Node} colorNode - The color node to process. - * @param {String} toneMapping - The tone mapping type. + * @param {Number} toneMapping - The tone mapping type. * @param {String} outputColorSpace - The output color space. */ constructor( colorNode, toneMapping, outputColorSpace ) { @@ -6495,6 +8466,15 @@ class RenderOutputNode extends TempNode { } +/** + * TSL function for creating a posterize node. + * + * @function + * @param {Node} color - The color node to process. + * @param {Number?} [toneMapping=null] - The tone mapping type. + * @param {String?} [outputColorSpace=null] - The output color space. + * @returns {RenderOutputNode} + */ const renderOutput = ( color, toneMapping = null, outputColorSpace = null ) => nodeObject( new RenderOutputNode( nodeObject( color ), toneMapping, outputColorSpace ) ); addMethodChaining( 'renderOutput', renderOutput ); @@ -6509,6 +8489,8 @@ function addNodeElement( name/*, nodeElement*/ ) { } +/** @module AttributeNode **/ + /** * Base class for representing shader attributes as nodes. * @@ -6661,10 +8643,36 @@ class AttributeNode extends Node { } +/** + * TSL function for creating an attribute node. + * + * @function + * @param {String} name - The name of the attribute. + * @param {String?} nodeType - The node type. + * @returns {AttributeNode} + */ const attribute = ( name, nodeType ) => nodeObject( new AttributeNode( name, nodeType ) ); -const uv = ( index ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); +/** @module UV **/ + +/** + * TSL function for creating an uv attribute node with the given index. + * + * @function + * @param {Number} [index=0] - The uv index. + * @return {AttributeNode} The uv attribute node. + */ +const uv = ( index = 0 ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); +/** @module TextureSizeNode **/ + +/** + * A node that represents the dimensions of a texture. The texture size is + * retrieved in the shader via built-in shader functions like `textureDimensions()` + * or `textureSize()`. + * + * @augments Node + */ class TextureSizeNode extends Node { static get type() { @@ -6673,13 +8681,38 @@ class TextureSizeNode extends Node { } + /** + * Constructs a new texture size node. + * + * @param {TextureNode} textureNode - A texture node which size should be retrieved. + * @param {Node?} [levelNode=null] - A level node which defines the requested mip. + */ constructor( textureNode, levelNode = null ) { super( 'uvec2' ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isTextureSizeNode = true; + /** + * A texture node which size should be retrieved. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * A level node which defines the requested mip. + * + * @type {Node} + * @default null + */ this.levelNode = levelNode; } @@ -6695,8 +8728,18 @@ class TextureSizeNode extends Node { } +/** + * TSL function for creating a texture size node. + * + * @function + * @param {TextureNode} textureNode - A texture node which size should be retrieved. + * @param {Node?} [levelNode=null] - A level node which defines the requested mip. + * @returns {TextureSizeNode} + */ const textureSize = /*@__PURE__*/ nodeProxy( TextureSizeNode ); +/** @module MatcapUVNode **/ + /** * A special type of uniform node that computes the * maximum mipmap level for a given texture node. @@ -6705,7 +8748,7 @@ const textureSize = /*@__PURE__*/ nodeProxy( TextureSizeNode ); * const level = maxMipLevel( textureNode ); * ``` * - * @augments UniformNode + * @augments module:UniformNode~UniformNode */ class MaxMipLevelNode extends UniformNode { @@ -6785,8 +8828,22 @@ class MaxMipLevelNode extends UniformNode { } +/** + * TSL function for creating a max mip level node. + * + * @function + * @param {TextureNode} textureNode - The texture node to compute the max mip level for. + * @returns {MaxMipLevelNode} + */ const maxMipLevel = /*@__PURE__*/ nodeProxy( MaxMipLevelNode ); +/** @module TextureNode **/ + +/** + * This type of uniform node represents a 2D texture. + * + * @augments module:UniformNode~UniformNode + */ class TextureNode extends UniformNode { static get type() { @@ -6795,26 +8852,125 @@ class TextureNode extends UniformNode { } + /** + * Constructs a new texture node. + * + * @param {Texture} value - The texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + */ constructor( value, uvNode = null, levelNode = null, biasNode = null ) { super( value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isTextureNode = true; + /** + * Represents the texture coordinates. + * + * @type {Node?} + * @default null + */ this.uvNode = uvNode; + + /** + * Represents the mip level that should be selected. + * + * @type {Node?} + * @default null + */ this.levelNode = levelNode; + + /** + * Represents the bias to be applied during level-of-detail computation. + * + * @type {Node?} + * @default null + */ this.biasNode = biasNode; + + /** + * Represents a reference value a texture sample is compared to. + * + * @type {Node?} + * @default null + */ this.compareNode = null; + + /** + * When using texture arrays, the depth node defines the layer to select. + * + * @type {Node?} + * @default null + */ this.depthNode = null; + + /** + * When defined, a texture is sampled using explicit gradients. + * + * @type {Array>?} + * @default null + */ this.gradNode = null; + /** + * Whether texture values should be sampled or fetched. + * + * @type {Boolean} + * @default true + */ this.sampler = true; + + /** + * Whether the uv transformation matrix should be + * automatically updated or not. Use `setUpdateMatrix()` + * if you want to change the value of the property. + * + * @type {Boolean} + * @default false + */ this.updateMatrix = false; + + /** + * By default the `update()` method is not executed. `setUpdateMatrix()` + * sets the value to `frame` when the uv transformation matrix should + * automatically be updated. + * + * @type {String} + * @default 'none' + */ this.updateType = NodeUpdateType.NONE; + /** + * The reference node. + * + * @type {Node?} + * @default null + */ this.referenceNode = null; + /** + * The texture value is stored in a private property. + * + * @private + * @type {Texture} + */ this._value = value; + + /** + * The uniform node that represents the uv transformation matrix. + * + * @private + * @type {UniformNode?} + */ this._matrixUniform = null; this.setUpdateMatrix( uvNode === null ); @@ -6835,18 +8991,35 @@ class TextureNode extends UniformNode { } + /** + * The texture value. + * + * @type {Texture} + */ get value() { return this.referenceNode ? this.referenceNode.value : this._value; } + /** + * Overwritten since the uniform hash is defined by the texture's UUID. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The uniform hash. + */ getUniformHash( /*builder*/ ) { return this.value.uuid; } + /** + * Overwritten since the node type is inferred from the texture type. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( /*builder*/ ) { if ( this.value.isDepthTexture === true ) return 'float'; @@ -6865,24 +9038,47 @@ class TextureNode extends UniformNode { } + /** + * Overwrites the default implementation to return a fixed value `'texture'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'texture'; } + /** + * Returns a default uvs based on the current texture's channel. + * + * @return {AttributeNode} The default uvs. + */ getDefaultUV() { return uv( this.value.channel ); } + /** + * Overwritten to always return the texture reference of the node. + * + * @param {Any} state - This method can be invocated in different contexts so `state` can refer to any object type. + * @return {Texture} The texture reference. + */ updateReference( /*state*/ ) { return this.value; } + /** + * Transforms the given uv node with the texture transformation matrix. + * + * @param {Node} uvNode - The uv node to transform. + * @return {Node} The transformed uv node. + */ getTransformedUV( uvNode ) { if ( this._matrixUniform === null ) this._matrixUniform = uniform( this.value.matrix ); @@ -6891,15 +9087,29 @@ class TextureNode extends UniformNode { } + /** + * Defines whether the uv transformation matrix should automatically be updated or not. + * + * @param {Boolean} value - The update toggle. + * @return {TextureNode} A reference to this node. + */ setUpdateMatrix( value ) { this.updateMatrix = value; - this.updateType = value ? NodeUpdateType.FRAME : NodeUpdateType.NONE; + this.updateType = value ? NodeUpdateType.RENDER : NodeUpdateType.NONE; return this; } + /** + * Setups the uv node. Depending on the backend as well as texture's image and type, it might be necessary + * to modify the uv node for correct sampling. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to setup. + * @return {Node} The updated uv node. + */ setupUV( builder, uvNode ) { const texture = this.value; @@ -6922,6 +9132,11 @@ class TextureNode extends UniformNode { } + /** + * Setups texture node by preparing the internal nodes for code generation. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const properties = builder.getNodeProperties( this ); @@ -6929,6 +9144,16 @@ class TextureNode extends UniformNode { // + const texture = this.value; + + if ( ! texture || texture.isTexture !== true ) { + + throw new Error( 'THREE.TSL: `texture( value )` function expects a valid instance of THREE.Texture().' ); + + } + + // + let uvNode = this.uvNode; if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) { @@ -6968,12 +9193,32 @@ class TextureNode extends UniformNode { } + /** + * Generates the uv code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to generate code for. + * @return {String} The generated code snippet. + */ generateUV( builder, uvNode ) { return uvNode.build( builder, this.sampler === true ? 'vec2' : 'ivec2' ); } + /** + * Generates the snippet for the texture sampling. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} textureProperty - The texture property. + * @param {String} uvSnippet - The uv snippet. + * @param {String} levelSnippet - The level snippet. + * @param {String} biasSnippet - The bias snippet. + * @param {String} depthSnippet - The depth snippet. + * @param {String} compareSnippet - The compare snippet. + * @param {String} gradSnippet - The grad snippet. + * @return {String} The generated code snippet. + */ generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ) { const texture = this.value; @@ -7010,18 +9255,18 @@ class TextureNode extends UniformNode { } + /** + * Generates the code snippet of the texture node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output. + * @return {String} The generated code 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 properties = builder.getNodeProperties( this ); const textureProperty = super.generate( builder, 'property' ); if ( output === 'sampler' ) { @@ -7077,6 +9322,12 @@ class TextureNode extends UniformNode { } + /** + * Sets the sampler value. + * + * @param {Boolean} value - The sampler value to set. + * @return {TextureNode} A reference to this texture node. + */ setSampler( value ) { this.sampler = value; @@ -7085,6 +9336,11 @@ class TextureNode extends UniformNode { } + /** + * Returns the sampler value. + * + * @return {Boolean} The sampler value. + */ getSampler() { return this.sampler; @@ -7093,6 +9349,13 @@ class TextureNode extends UniformNode { // @TODO: Move to TSL + /** + * @function + * @deprecated since r172. Use {@link TextureNode#sample} instead. + * + * @param {Node} uvNode - The uv node. + * @return {TextureNode} A texture node representing the texture sample. + */ uv( uvNode ) { // @deprecated, r172 console.warn( 'THREE.TextureNode: .uv() has been renamed. Use .sample() instead.' ); @@ -7101,6 +9364,12 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture with the given uv node. + * + * @param {Node} uvNode - The uv node. + * @return {TextureNode} A texture node representing the texture sample. + */ sample( uvNode ) { const textureNode = this.clone(); @@ -7111,6 +9380,12 @@ class TextureNode extends UniformNode { } + /** + * Samples a blurred version of the texture by defining an internal bias. + * + * @param {Node} amountNode - How blurred the texture should be. + * @return {TextureNode} A texture node representing the texture sample. + */ blur( amountNode ) { const textureNode = this.clone(); @@ -7121,6 +9396,12 @@ class TextureNode extends UniformNode { } + /** + * Samples a specific mip of the texture. + * + * @param {Node} levelNode - The mip level to sample. + * @return {TextureNode} A texture node representing the texture sample. + */ level( levelNode ) { const textureNode = this.clone(); @@ -7131,12 +9412,24 @@ class TextureNode extends UniformNode { } + /** + * Returns the texture size of the requested level. + * + * @param {Node} levelNode - The level to compute the size for. + * @return {TextureSizeNode} The texture size. + */ size( levelNode ) { return textureSize( this, levelNode ); } + /** + * Samples the texture with the given bias. + * + * @param {Node} biasNode - The bias node. + * @return {TextureNode} A texture node representing the texture sample. + */ bias( biasNode ) { const textureNode = this.clone(); @@ -7147,6 +9440,12 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture by executing a compare operation. + * + * @param {Node} compareNode - The node that defines the compare value. + * @return {TextureNode} A texture node representing the texture sample. + */ compare( compareNode ) { const textureNode = this.clone(); @@ -7157,6 +9456,13 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture using an explicit gradient. + * + * @param {Node} gradNodeX - The gradX node. + * @param {Node} gradNodeY - The gradY node. + * @return {TextureNode} A texture node representing the texture sample. + */ grad( gradNodeX, gradNodeY ) { const textureNode = this.clone(); @@ -7167,6 +9473,12 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture by defining a depth node. + * + * @param {Node} depthNode - The depth node. + * @return {TextureNode} A texture node representing the texture sample. + */ depth( depthNode ) { const textureNode = this.clone(); @@ -7201,6 +9513,9 @@ class TextureNode extends UniformNode { } + /** + * The update is used to implement the update of the uv transformation matrix. + */ update() { const texture = this.value; @@ -7216,6 +9531,11 @@ class TextureNode extends UniformNode { } + /** + * Clones the texture node. + * + * @return {TextureNode} The cloned texture node. + */ clone() { const newNode = new this.constructor( this.value, this.uvNode, this.levelNode, this.biasNode ); @@ -7227,22 +9547,114 @@ class TextureNode extends UniformNode { } +/** + * TSL function for creating a texture node. + * + * @function + * @param {Texture} value - The texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + * @returns {TextureNode} + */ const texture = /*@__PURE__*/ nodeProxy( TextureNode ); + +/** + * TSL function for creating a texture node that fetches/loads texels without interpolation. + * + * @function + * @param {Texture} value - The texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + * @returns {TextureNode} + */ const textureLoad = ( ...params ) => texture( ...params ).setSampler( false ); //export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level ); +/** + * Converts a texture or texture node to a sampler. + * + * @function + * @param {TextureNode|Texture} aTexture - The texture or texture node to convert. + * @returns {Node} + */ const sampler = ( aTexture ) => ( aTexture.isNode === true ? aTexture : texture( aTexture ) ).convert( 'sampler' ); +/** @module Camera **/ + +/** + * TSL object that represents the `near` value of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraNear = /*@__PURE__*/ uniform( 'float' ).label( 'cameraNear' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.near ); + +/** + * TSL object that represents the `far` value of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraFar = /*@__PURE__*/ uniform( 'float' ).label( 'cameraFar' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.far ); + +/** + * TSL object that represents the projection matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraProjectionMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrix ); + +/** + * TSL object that represents the inverse projection matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraProjectionMatrixInverse = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraProjectionMatrixInverse' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.projectionMatrixInverse ); + +/** + * TSL object that represents the view matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraViewMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraViewMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorldInverse ); + +/** + * TSL object that represents the world matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraWorldMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraWorldMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.matrixWorld ); + +/** + * TSL object that represents the normal matrix of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraNormalMatrix = /*@__PURE__*/ uniform( 'mat3' ).label( 'cameraNormalMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.normalMatrix ); + +/** + * TSL object that represents the position in world space of the camera used for the current render. + * + * @type {UniformNode} + */ const cameraPosition = /*@__PURE__*/ uniform( new Vector3() ).label( 'cameraPosition' ).setGroup( renderGroup ).onRenderUpdate( ( { camera }, self ) => self.value.setFromMatrixPosition( camera.matrixWorld ) ); +/** @module Object3DNode **/ + +/** + * This node can be used to access transformation related metrics of 3D objects. + * Depending on the selected scope, a different metric is represented as a uniform + * in the shader. The following scopes are supported: + * + * - `POSITION`: The object's position in world space. + * - `VIEW_POSITION`: The object's position in view/camera space. + * - `DIRECTION`: The object's direction in world space. + * - `SCALE`: The object's scale in world space. + * - `WORLD_MATRIX`: The object's matrix in world space. + * + * @augments Node + */ class Object3DNode extends Node { static get type() { @@ -7251,19 +9663,55 @@ class Object3DNode extends Node { } + /** + * Constructs a new object 3D node. + * + * @param {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} scope - The node represents a different type of transformation depending on the scope. + * @param {Object3D?} [object3d=null] - The 3D object. + */ constructor( scope, object3d = null ) { super(); + /** + * The node reports a different type of transformation depending on the scope. + * + * @type {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} + */ this.scope = scope; + + /** + * The 3D object. + * + * @type {Object3D?} + * @default null + */ this.object3d = object3d; + /** + * Overwritten since this type of node is updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; + /** + * Holds the value of the node as a uniform. + * + * @private + * @type {UniformNode} + */ this._uniformNode = new UniformNode( null ); } + /** + * Overwritten since the node type is inferred from the scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType() { const scope = this.scope; @@ -7280,6 +9728,11 @@ class Object3DNode extends Node { } + /** + * Updates the uniform value depending on the scope. + * + * @param {NodeFrame} frame - The current node frame. + */ update( frame ) { const object = this.object3d; @@ -7321,6 +9774,13 @@ class Object3DNode extends Node { } + /** + * Generates the code snippet of the uniform node. The node type of the uniform + * node also depends on the selected scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( builder ) { const scope = this.scope; @@ -7363,12 +9823,61 @@ Object3DNode.SCALE = 'scale'; Object3DNode.VIEW_POSITION = 'viewPosition'; Object3DNode.DIRECTION = 'direction'; +/** + * TSL function for creating an object 3D node that represents the object's direction in world space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectDirection = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.DIRECTION ); + +/** + * TSL function for creating an object 3D node that represents the object's world matrix. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectWorldMatrix = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX ); + +/** + * TSL function for creating an object 3D node that represents the object's position in world space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.POSITION ); + +/** + * TSL function for creating an object 3D node that represents the object's scale in world space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectScale = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.SCALE ); + +/** + * TSL function for creating an object 3D node that represents the object's position in view/camera space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ const objectViewPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION ); +/** @module ModelNode **/ + +/** + * This type of node is a specialized version of `Object3DNode` + * with larger set of model related metrics. Unlike `Object3DNode`, + * `ModelNode` extracts the reference to the 3D object from the + * current node frame state. + * + * @augments module:Object3DNode~Object3DNode + */ class ModelNode extends Object3DNode { static get type() { @@ -7377,12 +9886,23 @@ class ModelNode extends Object3DNode { } + /** + * Constructs a new object model node. + * + * @param {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} scope - The node represents a different type of transformation depending on the scope. + */ constructor( scope ) { super( scope ); } + /** + * Extracts the model reference from the frame state and then + * updates the uniform value depending on the scope. + * + * @param {NodeFrame} frame - The current node frame. + */ update( frame ) { this.object3d = frame.object; @@ -7393,16 +9913,84 @@ class ModelNode extends Object3DNode { } +/** + * TSL object that represents the object's direction in world space. + * + * @type {ModelNode} + */ const modelDirection = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.DIRECTION ); + +/** + * TSL object that represents the object's world matrix. + * + * @type {ModelNode} + */ const modelWorldMatrix = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX ); + +/** + * TSL object that represents the object's position in world space. + * + * @type {ModelNode} + */ const modelPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.POSITION ); + +/** + * TSL object that represents the object's scale in world space. + * + * @type {ModelNode} + */ const modelScale = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.SCALE ); + +/** + * TSL object that represents the object's position in view/camera space. + * + * @type {ModelNode} + */ const modelViewPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.VIEW_POSITION ); + +/** + * TSL object that represents the object's normal matrix. + * + * @type {UniformNode} + */ const modelNormalMatrix = /*@__PURE__*/ uniform( new Matrix3() ).onObjectUpdate( ( { object }, self ) => self.value.getNormalMatrix( object.matrixWorld ) ); + +/** + * TSL object that represents the object's inverse world matrix. + * + * @type {UniformNode} + */ 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 ) => { +/** + * TSL object that represents the object's model view matrix. + * + * @type {Node} + */ +const modelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { + + return builder.renderer.nodes.modelViewMatrix || mediumpModelViewMatrix; + +} ).once() )().toVar( 'modelViewMatrix' ); + +// GPU Precision + +/** + * TSL object that represents the object's model view in `mediump` precision. + * + * @type {Node} + */ +const mediumpModelViewMatrix = /*@__PURE__*/ cameraViewMatrix.mul( modelWorldMatrix ); + +// CPU Precision + +/** + * TSL object that represents the object's model view in `highp` precision + * which is achieved by computing the matrix in JS and not in the shader. + * + * @type {Node} + */ +const highpModelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { builder.context.isHighPrecisionModelViewMatrix = true; @@ -7412,9 +10000,15 @@ const highPrecisionModelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { } ); -} ).once() )().toVar( 'highPrecisionModelViewMatrix' ); +} ).once() )().toVar( 'highpModelViewMatrix' ); -const highPrecisionModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { +/** + * TSL object that represents the object's model normal view in `highp` precision + * which is achieved by computing the matrix in JS and not in the shader. + * + * @type {Node} + */ +const highpModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { const isHighPrecisionModelViewMatrix = builder.context.isHighPrecisionModelViewMatrix; @@ -7430,16 +10024,66 @@ const highPrecisionModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { } ); -} ).once() )().toVar( 'highPrecisionModelNormalMatrix' ); +} ).once() )().toVar( 'highpModelNormalViewMatrix' ); + +/** @module Position **/ +/** + * TSL object that represents the position attribute of the current rendered object. + * + * @type {AttributeNode} + */ const positionGeometry = /*@__PURE__*/ attribute( 'position', 'vec3' ); + +/** + * TSL object that represents the vertex position in local space of the current rendered object. + * + * @type {AttributeNode} + */ const positionLocal = /*@__PURE__*/ positionGeometry.varying( 'positionLocal' ); + +/** + * TSL object that represents the previous vertex position in local space of the current rendered object. + * Used in context of {@link module:VelocityNode~VelocityNode} for rendering motion vectors. + * + * @type {AttributeNode} + */ 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' ); + +/** + * TSL object that represents the vertex position in world space of the current rendered object. + * + * @type {VaryingNode} + */ +const positionWorld = /*@__PURE__*/ modelWorldMatrix.mul( positionLocal ).xyz.varying( 'v_positionWorld' ).context( { needsPositionReassign: true } ); + +/** + * TSL object that represents the position world direction of the current rendered object. + * + * @type {Node} + */ +const positionWorldDirection = /*@__PURE__*/ positionLocal.transformDirection( modelWorldMatrix ).varying( 'v_positionWorldDirection' ).normalize().toVar( 'positionWorldDirection' ).context( { needsPositionReassign: true } ); + +/** + * TSL object that represents the vertex position in view space of the current rendered object. + * + * @type {VaryingNode} + */ +const positionView = /*@__PURE__*/ ( Fn( ( builder ) => { + + return builder.context.setupPositionView(); + +}, 'vec3' ).once() )().varying( 'v_positionView' ).context( { needsPositionReassign: true } ); + +/** + * TSL object that represents the position view direction of the current rendered object. + * + * @type {VaryingNode} + */ const positionViewDirection = /*@__PURE__*/ positionView.negate().varying( 'v_positionViewDirection' ).normalize().toVar( 'positionViewDirection' ); +/** @module FrontFacingNode **/ + /** * This node can be used to evaluate whether a primitive is front or back facing. * @@ -7491,11 +10135,35 @@ class FrontFacingNode extends Node { } +/** + * TSL object that represents whether a primitive is front or back facing + * + * @type {FrontFacingNode} + */ const frontFacing = /*@__PURE__*/ nodeImmutable( FrontFacingNode ); + +/** + * TSL object that represents the front facing status as a number instead of a bool. + * `1` means front facing, `-1` means back facing. + * + * @type {Node} + */ const faceDirection = /*@__PURE__*/ float( frontFacing ).mul( 2.0 ).sub( 1.0 ); +/** @module Normal **/ + +/** + * TSL object that represents the normal attribute of the current rendered object. + * + * @type {Node} + */ const normalGeometry = /*@__PURE__*/ attribute( 'normal', 'vec3' ); +/** + * TSL object that represents the vertex normal in local space of the current rendered object. + * + * @type {Node} + */ const normalLocal = /*@__PURE__*/ ( Fn( ( builder ) => { if ( builder.geometry.hasAttribute( 'normal' ) === false ) { @@ -7510,8 +10178,18 @@ const normalLocal = /*@__PURE__*/ ( Fn( ( builder ) => { }, 'vec3' ).once() )().toVar( 'normalLocal' ); +/** + * TSL object that represents the flat vertex normal in view space of the current rendered object. + * + * @type {Node} + */ const normalFlat = /*@__PURE__*/ positionView.dFdx().cross( positionView.dFdy() ).normalize().toVar( 'normalFlat' ); +/** + * TSL object that represents the vertex normal in view space of the current rendered object. + * + * @type {Node} + */ const normalView = /*@__PURE__*/ ( Fn( ( builder ) => { let node; @@ -7530,23 +10208,54 @@ const normalView = /*@__PURE__*/ ( Fn( ( builder ) => { }, 'vec3' ).once() )().toVar( 'normalView' ); +/** + * TSL object that represents the vertex normal in world space of the current rendered object. + * + * @type {Node} + */ const normalWorld = /*@__PURE__*/ varying( normalView.transformDirection( cameraViewMatrix ), 'v_normalWorld' ).normalize().toVar( 'normalWorld' ); +/** + * TSL object that represents the transformed vertex normal in view space of the current rendered object. + * + * @type {Node} + */ const transformedNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { - return builder.context.setupNormal(); + // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode) -}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedNormalView' ); + return builder.context.setupNormal().context( { getUV: null } ); +}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedNormalView' ); +/** + * TSL object that represents the transformed vertex normal in world space of the current rendered object. + * + * @type {Node} + */ const transformedNormalWorld = /*@__PURE__*/ transformedNormalView.transformDirection( cameraViewMatrix ).toVar( 'transformedNormalWorld' ); +/** + * TSL object that represents the transformed clearcoat vertex normal in view space of the current rendered object. + * + * @type {Node} + */ const transformedClearcoatNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { - return builder.context.setupClearcoatNormal(); + // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode) + + return builder.context.setupClearcoatNormal().context( { getUV: null } ); }, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedClearcoatNormalView' ); +/** + * Transforms the normal with the given matrix. + * + * @function + * @param {Node} normal - The normal. + * @param {Node} [matrix=modelWorldMatrix] - The matrix. + * @return {Node} The transformed normal. + */ const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorldMatrix ] ) => { const m = mat3( matrix ); @@ -7557,6 +10266,14 @@ const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorldMatrix } ); +/** + * Transforms the given normal from local to view space. + * + * @function + * @param {Node} normal - The normal. + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The transformed normal. + */ const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => { const modelNormalViewMatrix = builder.renderer.nodes.modelNormalViewMatrix; @@ -7575,14 +10292,52 @@ const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => { } ); +/** @module MaterialProperties **/ + +/** + * TSL object that represents the refraction ratio of the material used for rendering the current object. + * + * @type {UniformNode} + */ const materialRefractionRatio = /*@__PURE__*/ uniform( 0 ).onReference( ( { material } ) => material ).onRenderUpdate( ( { material } ) => material.refractionRatio ); +/** @module ReflectVector **/ + +/** + * The reflect vector in view space. + * + * @type {Node} + */ const reflectView = /*@__PURE__*/ positionViewDirection.negate().reflect( transformedNormalView ); + +/** + * The refract vector in view space. + * + * @type {Node} + */ const refractView = /*@__PURE__*/ positionViewDirection.negate().refract( transformedNormalView, materialRefractionRatio ); +/** + * Used for sampling cube maps when using cube reflection mapping. + * + * @type {Node} + */ const reflectVector = /*@__PURE__*/ reflectView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); + +/** + * Used for sampling cube maps when using cube refraction mapping. + * + * @type {Node} + */ const refractVector = /*@__PURE__*/ refractView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); +/** @module CubeTextureNode **/ + +/** + * This type of uniform node represents a cube texture. + * + * @augments module:TextureNode~TextureNode + */ class CubeTextureNode extends TextureNode { static get type() { @@ -7591,20 +10346,46 @@ class CubeTextureNode extends TextureNode { } + /** + * Constructs a new cube texture node. + * + * @param {CubeTexture} value - The cube texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + */ constructor( value, uvNode = null, levelNode = null, biasNode = null ) { super( value, uvNode, levelNode, biasNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isCubeTextureNode = true; } + /** + * Overwrites the default implementation to return a fixed value `'cubeTexture'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'cubeTexture'; } + /** + * Returns a default uvs based on the mapping type of the cube texture. + * + * @return {Node} The default uv attribute. + */ getDefaultUV() { const texture = this.value; @@ -7627,8 +10408,22 @@ class CubeTextureNode extends TextureNode { } + /** + * Overwritten with an empty implementation since the `updateMatrix` flag is ignored + * for cube textures. The uv transformation matrix is not applied to cube textures. + * + * @param {Boolean} value - The update toggle. + */ setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for CubeTextureNode + /** + * Setups the uv node. Depending on the backend as well as the texture type, it might be necessary + * to modify the uv node for correct sampling. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to setup. + * @return {Node} The updated uv node. + */ setupUV( builder, uvNode ) { const texture = this.value; @@ -7645,6 +10440,13 @@ class CubeTextureNode extends TextureNode { } + /** + * Generates the uv code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} cubeUV - The uv node to generate code for. + * @return {String} The generated code snippet. + */ generateUV( builder, cubeUV ) { return cubeUV.build( builder, 'vec3' ); @@ -7653,8 +10455,34 @@ class CubeTextureNode extends TextureNode { } +/** + * TSL function for creating a cube texture node. + * + * @function + * @param {CubeTexture} value - The cube texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + * @returns {CubeTextureNode} + */ const cubeTexture = /*@__PURE__*/ nodeProxy( CubeTextureNode ); +/** @module BufferNode **/ + +/** + * A special type of uniform node which represents array-like data + * as uniform buffers. The access usually happens via `element()` + * which returns an instance of {@link ArrayElementNode}. For example: + * + * ```js + * const bufferNode = buffer( array, 'mat4', count ); + * const matrixNode = bufferNode.element( index ); // access a matrix from the buffer + * ``` + * In general, it is recommended to use the more managed {@link UniformArrayNode} + * since it handles more input types and automatically cares about buffer paddings. + * + * @augments module:UniformNode~UniformNode + */ class BufferNode extends UniformNode { static get type() { @@ -7663,23 +10491,61 @@ class BufferNode extends UniformNode { } + /** + * Constructs a new buffer node. + * + * @param {Array} value - Array-like buffer data. + * @param {String} bufferType - The data type of the buffer. + * @param {Number} [bufferCount=0] - The count of buffer elements. + */ constructor( value, bufferType, bufferCount = 0 ) { super( value, bufferType ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBufferNode = true; + /** + * The data type of the buffer. + * + * @type {String} + */ this.bufferType = bufferType; + + /** + * The uniform node that holds the value of the reference node. + * + * @type {Number} + * @default 0 + */ this.bufferCount = bufferCount; } + /** + * The data type of the buffer elements. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The element type. + */ getElementType( builder ) { return this.getNodeType( builder ); } + /** + * Overwrites the default implementation to return a fixed value `'buffer'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'buffer'; @@ -7688,8 +10554,24 @@ class BufferNode extends UniformNode { } +/** + * TSL function for creating a buffer node. + * + * @function + * @param {Array} value - Array-like buffer data. + * @param {String} type - The data type of a buffer element. + * @param {Number} count - The count of buffer elements. + * @returns {BufferNode} + */ const buffer = ( value, type, count ) => nodeObject( new BufferNode( value, type, count ) ); +/** @module UniformArrayNode **/ + +/** + * Represents the element access on uniform array nodes. + * + * @augments ArrayElementNode + */ class UniformArrayElementNode extends ArrayElementNode { static get type() { @@ -7698,10 +10580,23 @@ class UniformArrayElementNode extends ArrayElementNode { } - constructor( arrayBuffer, indexNode ) { + /** + * Constructs a new buffer node. + * + * @param {UniformArrayNode} uniformArrayNode - The uniform array node to access. + * @param {IndexNode} indexNode - The index data that define the position of the accessed element in the array. + */ + constructor( uniformArrayNode, indexNode ) { - super( arrayBuffer, indexNode ); + super( uniformArrayNode, indexNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isArrayBufferElementNode = true; } @@ -7718,6 +10613,23 @@ class UniformArrayElementNode extends ArrayElementNode { } +/** + * Similar to {@link module:BufferNode~BufferNode} this module represents array-like data as + * uniform buffers. Unlike {@link module:BufferNode~BufferNode}, it can handle more common + * data types in the array (e.g `three.js` primitives) and automatically + * manage buffer padding. It should be the first choice when working with + * uniforms buffers. + * ```js + * const tintColors = uniformArray( [ + * new Color( 1, 0, 0 ), + * new Color( 0, 1, 0 ), + * new Color( 0, 0, 1 ) + * ], 'color' ); + * + * const redColor = tintColors.element( 0 ); + * + * @augments module:BufferNode~BufferNode + */ class UniformArrayNode extends BufferNode { static get type() { @@ -7726,32 +10638,89 @@ class UniformArrayNode extends BufferNode { } + /** + * Constructs a new uniform array node. + * + * @param {Array} value - Array holding the buffer data. + * @param {String?} [elementType=null] - The data type of a buffer element. + */ constructor( value, elementType = null ) { super( null ); + /** + * Array holding the buffer data. Unlike {@link module:BufferNode~BufferNode}, the array can + * hold number primitives as well as three.js objects like vectors, matrices + * or colors. + * + * @type {Array} + */ this.array = value; + + /** + * The data type of an array element. + * + * @type {String} + */ this.elementType = elementType === null ? getValueType( value[ 0 ] ) : elementType; + + /** + * The padded type. Uniform buffers must conform to a certain buffer layout + * so a separate type is computed to ensure correct buffer size. + * + * @type {String} + */ this.paddedType = this.getPaddedType(); + /** + * Overwritten since uniform array nodes are updated per render. + * + * @type {String} + * @default 'render' + */ this.updateType = NodeUpdateType.RENDER; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isArrayBufferNode = true; } - getNodeType() { + /** + * This method is overwritten since the node type is inferred from the + * {@link module:UniformArrayNode~UniformArrayNode#paddedType}. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ + getNodeType( /*builder*/ ) { return this.paddedType; } + /** + * The data type of the array elements. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The element type. + */ getElementType() { return this.elementType; } + /** + * Returns the padded type based on the element type. + * + * @return {String} The padded type. + */ getPaddedType() { const elementType = this.elementType; @@ -7780,6 +10749,12 @@ class UniformArrayNode extends BufferNode { } + /** + * The update makes sure to correctly transfer the data from the (complex) objects + * in the array to the internal, correctly padded value buffer. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( /*frame*/ ) { const { array, value } = this; @@ -7880,6 +10855,12 @@ class UniformArrayNode extends BufferNode { } + /** + * Implement the value buffer creation based on the array data. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {null} + */ setup( builder ) { const length = this.array.length; @@ -7901,6 +10882,13 @@ class UniformArrayNode extends BufferNode { } + /** + * Overwrites the default `element()` method to provide element access + * based on {@link module:UniformArrayNode~UniformArrayNode}. + * + * @param {IndexNode} indexNode - The index node. + * @return {UniformArrayElementNode} + */ element( indexNode ) { return nodeObject( new UniformArrayElementNode( this, nodeObject( indexNode ) ) ); @@ -7909,10 +10897,24 @@ class UniformArrayNode extends BufferNode { } +/** + * TSL function for creating an uniform array node. + * + * @function + * @param {Array} values - Array-like data. + * @param {String} nodeType - The data type of the array elements. + * @returns {UniformArrayNode} + */ const uniformArray = ( values, nodeType ) => nodeObject( new UniformArrayNode( values, nodeType ) ); -// - +/** + * @function + * @deprecated since r168. Use {@link uniformArray} instead. + * + * @param {Array} values - Array-like data. + * @param {String} nodeType - The data type of the array elements. + * @returns {UniformArrayNode} + */ const uniforms = ( values, nodeType ) => { // @deprecated, r168 console.warn( 'TSL.UniformArrayNode: uniforms() has been renamed to uniformArray().' ); @@ -7920,6 +10922,17 @@ const uniforms = ( values, nodeType ) => { // @deprecated, r168 }; +// TODO: Avoid duplicated code and ues only ReferenceBaseNode or ReferenceNode + +/** @module ReferenceNode **/ + +/** + * This class is only relevant if the referenced property is array-like. + * In this case, `ReferenceElementNode` allows to refer to a specific + * element inside the data structure via an index. + * + * @augments ArrayElementNode + */ class ReferenceElementNode extends ArrayElementNode { static get type() { @@ -7928,16 +10941,43 @@ class ReferenceElementNode extends ArrayElementNode { } + /** + * Constructs a new reference element node. + * + * @param {Node?} referenceNode - The reference node. + * @param {Node} indexNode - The index node that defines the element access. + */ constructor( referenceNode, indexNode ) { super( referenceNode, indexNode ); + /** + * Similar to {@link module:ReferenceNode~ReferenceNode#reference}, an additional + * property references to the current node. + * + * @type {Node?} + * @default null + */ this.referenceNode = referenceNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isReferenceElementNode = true; } + /** + * This method is overwritten since the node type is inferred from + * the uniform type of the reference node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType() { return this.referenceNode.uniformType; @@ -7956,7 +10996,14 @@ class ReferenceElementNode extends ArrayElementNode { } -// TODO: Extends this from ReferenceBaseNode +/** + * This type of node establishes a reference to a property of another object. + * In this way, the value of the node is automatically linked to the value of + * referenced object. Reference nodes internally represent the linked value + * as a uniform. + * + * @augments Node + */ class ReferenceNode extends Node { static get type() { @@ -7965,31 +11012,118 @@ class ReferenceNode extends Node { } + /** + * Constructs a new reference node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} uniformType - The uniform type that should be used to represent the property value. + * @param {Object?} [object=null] - The object the property belongs to. + * @param {Number?} [count=null] - When the linked property is an array-like, this parameter defines its length. + */ constructor( property, uniformType, object = null, count = null ) { super(); + /** + * The name of the property the node refers to. + * + * @type {String} + */ this.property = property; + + /** + * The uniform type that should be used to represent the property value. + * + * @type {String} + */ this.uniformType = uniformType; + + /** + * The object the property belongs to. + * + * @type {Object?} + * @default null + */ this.object = object; + + /** + * When the linked property is an array, this parameter defines its length. + * + * @type {Number?} + * @default null + */ this.count = count; + /** + * The property name might have dots so nested properties can be referred. + * The hierarchy of the names is stored inside this array. + * + * @type {Array} + */ this.properties = property.split( '.' ); + + /** + * Points to the current referred object. This property exists next to {@link module:ReferenceNode~ReferenceNode#object} + * since the final reference might be updated from calling code. + * + * @type {Object?} + * @default null + */ this.reference = object; + + /** + * The uniform node that holds the value of the reference node. + * + * @type {UniformNode} + * @default null + */ this.node = null; + + /** + * The uniform group of the internal uniform. + * + * @type {UniformGroupNode} + * @default null + */ this.group = null; + + /** + * An optional label of the internal uniform node. + * + * @type {String?} + * @default null + */ this.name = null; + /** + * Overwritten since reference nodes are updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; } + /** + * When the referred property is array-like, this method can be used + * to access elements via an index node. + * + * @param {IndexNode} indexNode - indexNode. + * @return {ReferenceElementNode} A reference to an element. + */ element( indexNode ) { return nodeObject( new ReferenceElementNode( this, nodeObject( indexNode ) ) ); } + /** + * Sets the uniform group for this reference node. + * + * @param {UniformGroupNode} group - The uniform group to set. + * @return {ReferenceNode} A reference to this node. + */ setGroup( group ) { this.group = group; @@ -7998,6 +11132,12 @@ class ReferenceNode extends Node { } + /** + * Sets the label for the internal uniform. + * + * @param {String} name - The label to set. + * @return {ReferenceNode} A reference to this node. + */ label( name ) { this.name = name; @@ -8006,6 +11146,12 @@ class ReferenceNode extends Node { } + /** + * Sets the node type which automatically defines the internal + * uniform type. + * + * @param {String} uniformType - The type to set. + */ setNodeType( uniformType ) { let node = null; @@ -8044,6 +11190,13 @@ class ReferenceNode extends Node { } + /** + * This method is overwritten since the node type is inferred from + * the type of the reference node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( this.node === null ) { @@ -8057,6 +11210,12 @@ class ReferenceNode extends Node { } + /** + * Returns the property value from the given referred object. + * + * @param {Object} [object=this.reference] - The object to retrieve the property value from. + * @return {Any} The value. + */ getValueFromReference( object = this.reference ) { const { properties } = this; @@ -8073,6 +11232,13 @@ class ReferenceNode extends Node { } + /** + * Allows to update the reference based on the given state. The state is only + * evaluated {@link module:ReferenceNode~ReferenceNode#object} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.object !== null ? this.object : state.object; @@ -8081,7 +11247,13 @@ class ReferenceNode extends Node { } - setup() { + /** + * The output of the reference node is the internal uniform node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {UniformNode} The output node. + */ + setup( /* builder */ ) { this.updateValue(); @@ -8089,12 +11261,21 @@ class ReferenceNode extends Node { } + /** + * Overwritten to to update the internal uniform value. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( /*frame*/ ) { this.updateValue(); } + /** + * Retrieves the value from the referred object property and uses it + * to updated the internal uniform. + */ updateValue() { if ( this.node === null ) this.setNodeType( this.uniformType ); @@ -8115,9 +11296,43 @@ class ReferenceNode extends Node { } +/** + * TSL function for creating a reference node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Object} object - The object the property belongs to. + * @returns {ReferenceNode} + */ const reference = ( name, type, object ) => nodeObject( new ReferenceNode( name, type, object ) ); + +/** + * TSL function for creating a reference node. Use this function if you want need a reference + * to an array-like property that should be represented as a uniform buffer. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Number} count - The number of value inside the array-like object. + * @param {Object} object - An array-like object the property belongs to. + * @returns {ReferenceNode} + */ const referenceBuffer = ( name, type, count, object ) => nodeObject( new ReferenceNode( name, type, object, count ) ); +/** @module MaterialReferenceNode **/ + +/** + * This node is a special type of reference node which is intended + * for linking material properties with node values. + * ```js + * const opacityNode = materialReference( 'opacity', 'float', material ); + * ``` + * When changing `material.opacity`, the node value of `opacityNode` will + * automatically be updated. + * + * @augments module:ReferenceNode~ReferenceNode + */ class MaterialReferenceNode extends ReferenceNode { static get type() { @@ -8126,26 +11341,45 @@ class MaterialReferenceNode extends ReferenceNode { } + /** + * Constructs a new material reference node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} inputType - The uniform type that should be used to represent the property value. + * @param {Material?} [material=null] - The material the property belongs to. When no material is set, + * the node refers to the material of the current rendered object. + */ constructor( property, inputType, material = null ) { super( property, inputType, material ); + /** + * The material the property belongs to. When no material is set, + * the node refers to the material of the current rendered object. + * + * @type {Material?} + * @default null + */ this.material = material; - //this.updateType = NodeUpdateType.RENDER; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMaterialReferenceNode = true; } - /*setNodeType( node ) { - - super.setNodeType( node ); - - this.node.groupNode = renderGroup; - - }*/ - + /** + * Updates the reference based on the given state. The state is only evaluated + * {@link module:MaterialReferenceNode~MaterialReferenceNode#material} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.material !== null ? this.material : state.material; @@ -8156,8 +11390,25 @@ class MaterialReferenceNode extends ReferenceNode { } -const materialReference = ( name, type, material ) => nodeObject( new MaterialReferenceNode( name, type, material ) ); +/** + * TSL function for creating a material reference node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Material?} [material=null] - The material the property belongs to. + * When no material is set, the node refers to the material of the current rendered object. + * @returns {MaterialReferenceNode} + */ +const materialReference = ( name, type, material = null ) => nodeObject( new MaterialReferenceNode( name, type, material ) ); + +/** @module Tangent **/ +/** + * TSL object that represents the tangent attribute of the current rendered object. + * + * @type {Node} + */ const tangentGeometry = /*@__PURE__*/ Fn( ( builder ) => { if ( builder.geometry.hasAttribute( 'tangent' ) === false ) { @@ -8170,26 +11421,119 @@ const tangentGeometry = /*@__PURE__*/ Fn( ( builder ) => { } )(); +/** + * TSL object that represents the vertex tangent in local space of the current rendered object. + * + * @type {Node} + */ const tangentLocal = /*@__PURE__*/ tangentGeometry.xyz.toVar( 'tangentLocal' ); + +/** + * TSL object that represents the vertex tangent in view space of the current rendered object. + * + * @type {Node} + */ const tangentView = /*@__PURE__*/ modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.varying( 'v_tangentView' ).normalize().toVar( 'tangentView' ); + +/** + * TSL object that represents the vertex tangent in world space of the current rendered object. + * + * @type {Node} + */ const tangentWorld = /*@__PURE__*/ tangentView.transformDirection( cameraViewMatrix ).varying( 'v_tangentWorld' ).normalize().toVar( 'tangentWorld' ); + +/** + * TSL object that represents the transformed vertex tangent in view space of the current rendered object. + * + * @type {Node} + */ const transformedTangentView = /*@__PURE__*/ tangentView.toVar( 'transformedTangentView' ); + +/** + * TSL object that represents the transformed vertex tangent in world space of the current rendered object. + * + * @type {Node} + */ const transformedTangentWorld = /*@__PURE__*/ transformedTangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedTangentWorld' ); +/** @module Bitangent **/ + const getBitangent = ( crossNormalTangent ) => crossNormalTangent.mul( tangentGeometry.w ).xyz; +/** + * TSL object that represents the bitangent attribute of the current rendered object. + * + * @type {Node} + */ const bitangentGeometry = /*@__PURE__*/ varying( getBitangent( normalGeometry.cross( tangentGeometry ) ), 'v_bitangentGeometry' ).normalize().toVar( 'bitangentGeometry' ); + +/** + * TSL object that represents the vertex bitangent in local space of the current rendered object. + * + * @type {Node} + */ const bitangentLocal = /*@__PURE__*/ varying( getBitangent( normalLocal.cross( tangentLocal ) ), 'v_bitangentLocal' ).normalize().toVar( 'bitangentLocal' ); + +/** + * TSL object that represents the vertex bitangent in view space of the current rendered object. + * + * @type {Node} + */ const bitangentView = /*@__PURE__*/ varying( getBitangent( normalView.cross( tangentView ) ), 'v_bitangentView' ).normalize().toVar( 'bitangentView' ); + +/** + * TSL object that represents the vertex bitangent in world space of the current rendered object. + * + * @type {Node} + */ const bitangentWorld = /*@__PURE__*/ varying( getBitangent( normalWorld.cross( tangentWorld ) ), 'v_bitangentWorld' ).normalize().toVar( 'bitangentWorld' ); + +/** + * TSL object that represents the transformed vertex bitangent in view space of the current rendered object. + * + * @type {Node} + */ const transformedBitangentView = /*@__PURE__*/ getBitangent( transformedNormalView.cross( transformedTangentView ) ).normalize().toVar( 'transformedBitangentView' ); + +/** + * TSL object that represents the transformed vertex bitangent in world space of the current rendered object. + * + * @type {Node} + */ const transformedBitangentWorld = /*@__PURE__*/ transformedBitangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedBitangentWorld' ); +/** @module AccessorsUtils **/ + +/** + * TSL object that represents the TBN matrix in view space. + * + * @type {Node} + */ const TBNViewMatrix = /*@__PURE__*/ mat3( tangentView, bitangentView, normalView ); +/** + * TSL object that represents the parallax direction. + * + * @type {Node} + */ const parallaxDirection = /*@__PURE__*/ positionViewDirection.mul( TBNViewMatrix )/*.normalize()*/; + +/** + * TSL function for computing parallax uv coordinates. + * + * @function + * @param {Node} uv - A uv node. + * @param {Node} scale - A scale node. + * @returns {Node} Parallax uv coordinates. + */ const parallaxUV = ( uv, scale ) => uv.sub( parallaxDirection.mul( scale ) ); +/** + * TSL function for computing bent normals. + * + * @function + * @returns {Node} Bent normals. + */ const transformedBentNormalView = /*@__PURE__*/ ( () => { // https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/anisotropy @@ -8203,6 +11547,8 @@ const transformedBentNormalView = /*@__PURE__*/ ( () => { } )(); +/** @module NormalMapNode **/ + // Normal Mapping Without Precomputed Tangents // http://www.thetenthplanet.de/archives/1180 @@ -8250,8 +11596,8 @@ class NormalMapNode extends TempNode { /** * Constructs a new normal map node. * - * @param {Node} node - Represents the normal map data. - * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. + * @param {Node} node - Represents the normal map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. */ constructor( node, scaleNode = null ) { @@ -8260,14 +11606,14 @@ class NormalMapNode extends TempNode { /** * Represents the normal map data. * - * @type {Node} + * @type {Node} */ this.node = node; /** * Controls the intensity of the effect. * - * @type {Node?} + * @type {Node?} * @default null */ this.scaleNode = scaleNode; @@ -8327,8 +11673,18 @@ class NormalMapNode extends TempNode { } +/** + * TSL function for creating a normal map node. + * + * @function + * @param {Node} node - Represents the normal map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. + * @returns {NormalMapNode} + */ const normalMap = /*@__PURE__*/ nodeProxy( NormalMapNode ); +/** @module BumpMapNode **/ + // Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen // https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf @@ -8388,8 +11744,8 @@ class BumpMapNode extends TempNode { /** * Constructs a new bump map node. * - * @param {Node} textureNode - Represents the bump map data. - * @param {Node?} [scaleNode=null] - Controls the intensity of the bump effect. + * @param {Node} textureNode - Represents the bump map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the bump effect. */ constructor( textureNode, scaleNode = null ) { @@ -8398,14 +11754,14 @@ class BumpMapNode extends TempNode { /** * Represents the bump map data. * - * @type {Node} + * @type {Node} */ this.textureNode = textureNode; /** * Controls the intensity of the bump effect. * - * @type {Node?} + * @type {Node?} * @default null */ this.scaleNode = scaleNode; @@ -8427,10 +11783,28 @@ class BumpMapNode extends TempNode { } +/** + * TSL function for creating a bump map node. + * + * @function + * @param {Node} textureNode - Represents the bump map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the bump effect. + * @returns {BumpMapNode} + */ const bumpMap = /*@__PURE__*/ nodeProxy( BumpMapNode ); +/** @module MaterialNode **/ + const _propertyCache = new Map(); +/** + * This class should simplify the node access to material properties. + * It internal uses reference nodes to make sure changes to material + * properties are automatically reflected to predefined TSL objects + * like e.g. `materialColor`. + * + * @augments Node + */ class MaterialNode extends Node { static get type() { @@ -8439,14 +11813,31 @@ class MaterialNode extends Node { } + /** + * Constructs a new material node. + * + * @param {String} scope - The scope defines what kind of material property is referred by the node. + */ constructor( scope ) { super(); + /** + * The scope defines what material property is referred by the node. + * + * @type {String} + */ this.scope = scope; } + /** + * Returns a cached reference node for the given property and type. + * + * @param {String} property - The name of the material property. + * @param {String} type - The uniform type of the property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getCache( property, type ) { let node = _propertyCache.get( property ); @@ -8463,24 +11854,49 @@ class MaterialNode extends Node { } + /** + * Returns a float-typed material reference node for the given property name. + * + * @param {String} property - The name of the material property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getFloat( property ) { return this.getCache( property, 'float' ); } + /** + * Returns a color-typed material reference node for the given property name. + * + * @param {String} property - The name of the material property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getColor( property ) { return this.getCache( property, 'color' ); } + /** + * Returns a texture-typed material reference node for the given property name. + * + * @param {String} property - The name of the material property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getTexture( property ) { return this.getCache( property === 'map' ? 'map' : property + 'Map', 'texture' ); } + /** + * The node setup is done depending on the selected scope. Multiple material properties + * might be grouped into a single node composition if they logically belong together. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The node representing the selected scope. + */ setup( builder ) { const material = builder.context.material; @@ -8530,15 +11946,15 @@ class MaterialNode extends Node { } else if ( scope === MaterialNode.SPECULAR_INTENSITY ) { - const specularIntensity = this.getFloat( scope ); + const specularIntensityNode = this.getFloat( scope ); - if ( material.specularMap ) { + if ( material.specularIntensityMap && material.specularIntensityMap.isTexture === true ) { - node = specularIntensity.mul( this.getTexture( scope ).a ); + node = specularIntensityNode.mul( this.getTexture( scope ).a ); } else { - node = specularIntensity; + node = specularIntensityNode; } @@ -8753,7 +12169,7 @@ class MaterialNode extends Node { node = this.getTexture( scope ).rgb.mul( this.getFloat( 'lightMapIntensity' ) ); - } else if ( scope === MaterialNode.AO_MAP ) { + } else if ( scope === MaterialNode.AO ) { node = this.getTexture( scope ).r.sub( 1.0 ).mul( this.getFloat( 'aoMapIntensity' ) ).add( 1.0 ); @@ -8804,50 +12220,293 @@ MaterialNode.LINE_DASH_SIZE = 'dashSize'; MaterialNode.LINE_GAP_SIZE = 'gapSize'; MaterialNode.LINE_WIDTH = 'linewidth'; MaterialNode.LINE_DASH_OFFSET = 'dashOffset'; -MaterialNode.POINT_WIDTH = 'pointWidth'; +MaterialNode.POINT_SIZE = 'size'; MaterialNode.DISPERSION = 'dispersion'; MaterialNode.LIGHT_MAP = 'light'; -MaterialNode.AO_MAP = 'ao'; +MaterialNode.AO = 'ao'; +/** + * TSL object that represents alpha test of the current material. + * + * @type {Node} + */ const materialAlphaTest = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ALPHA_TEST ); + +/** + * TSL object that represents the diffuse color of the current material. + * The value is composed via `color` * `map`. + * + * @type {Node} + */ const materialColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.COLOR ); + +/** + * TSL object that represents the shininess of the current material. + * + * @type {Node} + */ const materialShininess = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHININESS ); + +/** + * TSL object that represents the emissive color of the current material. + * The value is composed via `emissive` * `emissiveIntensity` * `emissiveMap`. + * + * @type {Node} + */ const materialEmissive = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.EMISSIVE ); + +/** + * TSL object that represents the opacity of the current material. + * The value is composed via `opacity` * `alphaMap`. + * + * @type {Node} + */ const materialOpacity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.OPACITY ); + +/** + * TSL object that represents the specular of the current material. + * + * @type {Node} + */ const materialSpecular = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR ); +/** + * TSL object that represents the specular intensity of the current material. + * The value is composed via `specularIntensity` * `specularMap.a`. + * + * @type {Node} + */ const materialSpecularIntensity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_INTENSITY ); + +/** + * TSL object that represents the specular color of the current material. + * The value is composed via `specularColor` * `specularMap.rgb`. + * + * @type {Node} + */ const materialSpecularColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR ); +/** + * TSL object that represents the specular strength of the current material. + * The value is composed via `specularMap.r`. + * + * @type {Node} + */ const materialSpecularStrength = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_STRENGTH ); + +/** + * TSL object that represents the reflectivity of the current material. + * + * @type {Node} + */ const materialReflectivity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.REFLECTIVITY ); + +/** + * TSL object that represents the roughness of the current material. + * The value is composed via `roughness` * `roughnessMap.g`. + * + * @type {Node} + */ const materialRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS ); + +/** + * TSL object that represents the metalness of the current material. + * The value is composed via `metalness` * `metalnessMap.b`. + * + * @type {Node} + */ const materialMetalness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.METALNESS ); -const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.NORMAL ).context( { getUV: null } ); + +/** + * TSL object that represents the normal of the current material. + * The value will be either `normalMap` * `normalScale`, `bumpMap` * `bumpScale` or `normalView`. + * + * @type {Node} + */ +const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.NORMAL ); + +/** + * TSL object that represents the clearcoat of the current material. + * The value is composed via `clearcoat` * `clearcoatMap.r` + * + * @type {Node} + */ const materialClearcoat = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT ); + +/** + * TSL object that represents the clearcoat roughness of the current material. + * The value is composed via `clearcoatRoughness` * `clearcoatRoughnessMap.r`. + * + * @type {Node} + */ const materialClearcoatRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_ROUGHNESS ); -const materialClearcoatNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL ).context( { getUV: null } ); + +/** + * TSL object that represents the clearcoat normal of the current material. + * The value will be either `clearcoatNormalMap` or `normalView`. + * + * @type {Node} + */ +const materialClearcoatNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL ); + +/** + * TSL object that represents the rotation of the current sprite material. + * + * @type {Node} + */ const materialRotation = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROTATION ); + +/** + * TSL object that represents the sheen color of the current material. + * The value is composed via `sheen` * `sheenColor` * `sheenColorMap`. + * + * @type {Node} + */ const materialSheen = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN ); + +/** + * TSL object that represents the sheen roughness of the current material. + * The value is composed via `sheenRoughness` * `sheenRoughnessMap.a`. + * + * @type {Node} + */ const materialSheenRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN_ROUGHNESS ); + +/** + * TSL object that represents the anisotropy of the current material. + * + * @type {Node} + */ const materialAnisotropy = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ANISOTROPY ); + +/** + * TSL object that represents the iridescence of the current material. + * + * @type {Node} + */ const materialIridescence = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE ); + +/** + * TSL object that represents the iridescence IOR of the current material. + * + * @type {Node} + */ const materialIridescenceIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_IOR ); + +/** + * TSL object that represents the iridescence thickness of the current material. + * + * @type {Node} + */ const materialIridescenceThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_THICKNESS ); + +/** + * TSL object that represents the transmission of the current material. + * The value is composed via `transmission` * `transmissionMap.r`. + * + * @type {Node} + */ const materialTransmission = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.TRANSMISSION ); + +/** + * TSL object that represents the thickness of the current material. + * The value is composed via `thickness` * `thicknessMap.g`. + * + * @type {Node} + */ const materialThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.THICKNESS ); + +/** + * TSL object that represents the IOR of the current material. + * + * @type {Node} + */ const materialIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IOR ); + +/** + * TSL object that represents the attenuation distance of the current material. + * + * @type {Node} + */ const materialAttenuationDistance = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_DISTANCE ); + +/** + * TSL object that represents the attenuation color of the current material. + * + * @type {Node} + */ const materialAttenuationColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_COLOR ); + +/** + * TSL object that represents the scale of the current dashed line material. + * + * @type {Node} + */ const materialLineScale = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_SCALE ); + +/** + * TSL object that represents the dash size of the current dashed line material. + * + * @type {Node} + */ const materialLineDashSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_SIZE ); + +/** + * TSL object that represents the gap size of the current dashed line material. + * + * @type {Node} + */ const materialLineGapSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_GAP_SIZE ); + +/** + * TSL object that represents the line width of the current line material. + * + * @type {Node} + */ const materialLineWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_WIDTH ); + +/** + * TSL object that represents the dash offset of the current line material. + * + * @type {Node} + */ const materialLineDashOffset = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_OFFSET ); -const materialPointWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.POINT_WIDTH ); + +/** + * TSL object that represents the point size of the current points material. + * + * @type {Node} + */ +const materialPointSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.POINT_SIZE ); + +/** + * TSL object that represents the dispersion of the current material. + * + * @type {Node} + */ const materialDispersion = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.DISPERSION ); + +/** + * TSL object that represents the light map of the current material. + * The value is composed via `lightMapIntensity` * `lightMap.rgb`. + * + * @type {Node} + */ const materialLightMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LIGHT_MAP ); -const materialAOMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.AO_MAP ); + +/** + * TSL object that represents the ambient occlusion map of the current material. + * The value is composed via `aoMap.r` - 1 * `aoMapIntensity` + 1. + * + * @type {Node} + */ +const materialAO = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.AO ); + +/** + * TSL object that represents the anisotropy vector of the current material. + * + * @type {Node} + */ const materialAnisotropyVector = /*@__PURE__*/ uniform( new Vector2() ).onReference( function ( frame ) { return frame.material; @@ -8858,40 +12517,20 @@ const materialAnisotropyVector = /*@__PURE__*/ uniform( new Vector2() ).onRefere } ); -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 ); +/** @module ModelViewProjectionNode **/ - } - - const position = this.positionNode || positionLocal; - const viewMatrix = builder.renderer.nodes.modelViewMatrix || modelViewMatrix; - - return cameraProjectionMatrix.mul( viewMatrix ).mul( position ); +/** + * TSL object that represents the position in clip space after the model-view-projection transform of the current rendered object. + * + * @type {VaryingNode} + */ +const modelViewProjection = /*@__PURE__*/ ( Fn( ( builder ) => { - } + return builder.context.setupModelViewProjection(); -} +}, 'vec4' ).once() )().varying( 'v_modelViewProjection' ); -const modelViewProjection = /*@__PURE__*/ nodeProxy( ModelViewProjectionNode ); +/** @module IndexNode **/ /** * This class represents shader indices of different types. The following predefined node @@ -9005,13 +12644,58 @@ IndexNode.INVOCATION_LOCAL = 'invocationLocal'; IndexNode.INVOCATION_SUBGROUP = 'invocationSubgroup'; IndexNode.DRAW = 'draw'; +/** + * TSL object that represents the index of a vertex within a mesh. + * + * @type {IndexNode} + */ const vertexIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.VERTEX ); + +/** + * TSL object that represents the index of either a mesh instance or an invocation of a compute shader. + * + * @type {IndexNode} + */ const instanceIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INSTANCE ); + +/** + * TSL object that represents the index of the subgroup the current compute invocation belongs to. + * + * @type {IndexNode} + */ const subgroupIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.SUBGROUP ); + +/** + * TSL object that represents the index of a compute invocation within the scope of a subgroup. + * + * @type {IndexNode} + */ const invocationSubgroupIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INVOCATION_SUBGROUP ); + +/** + * TSL object that represents the index of a compute invocation within the scope of a workgroup load. + * + * @type {IndexNode} + */ const invocationLocalIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.INVOCATION_LOCAL ); + +/** + * TSL object that represents the index of a draw call. + * + * @type {IndexNode} + */ const drawIndex = /*@__PURE__*/ nodeImmutable( IndexNode, IndexNode.DRAW ); +/** @module InstanceNode **/ + +/** + * This node implements the vertex shader logic which is required + * when rendering 3D objects via instancing. The code makes sure + * vertex positions, normals and colors can be modified via instanced + * data. + * + * @augments Node + */ class InstanceNode extends Node { static get type() { @@ -9020,25 +12704,84 @@ class InstanceNode extends Node { } + /** + * Constructs a new instance node. + * + * @param {Number} count - The number of instances. + * @param {InstancedBufferAttribute} instanceMatrix - Instanced buffer attribute representing the instance transformations. + * @param {InstancedBufferAttribute} instanceColor - Instanced buffer attribute representing the instance colors. + */ constructor( count, instanceMatrix, instanceColor ) { super( 'void' ); + /** + * The number of instances. + * + * @type {Number} + */ this.count = count; + + /** + * Instanced buffer attribute representing the transformation of instances. + * + * @type {InstancedBufferAttribute} + */ this.instanceMatrix = instanceMatrix; + + /** + * Instanced buffer attribute representing the color of instances. + * + * @type {InstancedBufferAttribute} + */ this.instanceColor = instanceColor; + /** + * The node that represents the instance matrix data. + * + * @type {Node} + */ this.instanceMatrixNode = null; + /** + * The node that represents the instance color data. + * + * @type {Node} + */ this.instanceColorNode = null; + /** + * The update type is set to `frame` since an update + * of instanced buffer data must be checked per frame. + * + * @type {String} + * @default 'frame' + */ this.updateType = NodeUpdateType.FRAME; + /** + * A reference to a buffer that is used by `instanceMatrixNode`. + * + * @type {InstancedInterleavedBuffer} + */ this.buffer = null; + + /** + * A reference to a buffer that is used by `instanceColorNode`. + * + * @type {InstancedInterleavedBuffer} + */ this.bufferColor = null; } + /** + * Setups the internal buffers and nodes and assigns the transformed vertex data + * to predefined node variables for accumulation. That follows the same patterns + * like with morph and skinning nodes. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const { count, instanceMatrix, instanceColor } = this; @@ -9118,6 +12861,11 @@ class InstanceNode extends Node { } + /** + * Checks if the internal buffers required an update. + * + * @param {NodeFrame} frame - The current node frame. + */ update( /*frame*/ ) { if ( this.instanceMatrix.usage !== DynamicDrawUsage && this.buffer !== null && this.instanceMatrix.version !== this.buffer.version ) { @@ -9136,8 +12884,25 @@ class InstanceNode extends Node { } +/** + * TSL function for creating an instance node. + * + * @function + * @param {Number} count - The number of instances. + * @param {InstancedBufferAttribute} instanceMatrix - Instanced buffer attribute representing the instance transformations. + * @param {InstancedBufferAttribute} instanceColor - Instanced buffer attribute representing the instance colors. + * @returns {InstanceNode} + */ const instance = /*@__PURE__*/ nodeProxy( InstanceNode ); +/** @module InstancedMeshNode **/ + +/** + * This is a special version of `InstanceNode` which requires the usage of {@link InstancedMesh}. + * It allows an easier setup of the instance node. + * + * @augments module:InstanceNode~InstanceNode + */ class InstancedMeshNode extends InstanceNode { static get type() { @@ -9146,20 +12911,46 @@ class InstancedMeshNode extends InstanceNode { } - constructor( instanceMesh ) { + /** + * Constructs a new instanced mesh node. + * + * @param {InstancedMesh} instancedMesh - The instanced mesh. + */ + constructor( instancedMesh ) { - const { count, instanceMatrix, instanceColor } = instanceMesh; + const { count, instanceMatrix, instanceColor } = instancedMesh; super( count, instanceMatrix, instanceColor ); - this.instanceMesh = instanceMesh; + /** + * A reference to the instanced mesh. + * + * @type {InstancedMesh} + */ + this.instancedMesh = instancedMesh; } } +/** + * TSL function for creating an instanced mesh node. + * + * @function + * @param {InstancedMesh} instancedMesh - The instancedMesh. + * @returns {InstancedMeshNode} + */ const instancedMesh = /*@__PURE__*/ nodeProxy( InstancedMeshNode ); +/** @module BatchNode **/ + +/** + * This node implements the vertex shader logic which is required + * when rendering 3D objects via batching. `BatchNode` must be used + * with instances of {@link BatchedMesh}. + * + * @augments Node + */ class BatchNode extends Node { static get type() { @@ -9168,21 +12959,41 @@ class BatchNode extends Node { } + /** + * Constructs a new batch node. + * + * @param {BatchedMesh} batchMesh - A reference to batched mesh. + */ constructor( batchMesh ) { super( 'void' ); + /** + * A reference to batched mesh. + * + * @type {BatchedMesh} + */ this.batchMesh = batchMesh; - + /** + * The batching index node. + * + * @type {IndexNode?} + * @default null + */ this.batchingIdNode = null; } + /** + * Setups the internal buffers and nodes and assigns the transformed vertex data + * to predefined node variables for accumulation. That follows the same patterns + * like with morph and skinning nodes. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { - // POSITION - if ( this.batchingIdNode === null ) { if ( builder.getDrawIndex() === null ) { @@ -9275,10 +13086,25 @@ class BatchNode extends Node { } +/** + * TSL function for creating a batch node. + * + * @function + * @param {BatchedMesh} batchMesh - A reference to batched mesh. + * @returns {BatchNode} + */ const batch = /*@__PURE__*/ nodeProxy( BatchNode ); +/** @module SkinningNode **/ + const _frameId = new WeakMap(); +/** + * This node implements the vertex transformation shader logic which is required + * for skinning/skeletal animation. + * + * @augments Node + */ class SkinningNode extends Node { static get type() { @@ -9287,18 +13113,52 @@ class SkinningNode extends Node { } + /** + * Constructs a new skinning node. + * + * @param {SkinnedMesh} skinnedMesh - The skinned mesh. + * @param {Boolean} [useReference=false] - Whether to use reference nodes for internal skinned mesh related data or not. + */ constructor( skinnedMesh, useReference = false ) { super( 'void' ); + /** + * The skinned mesh. + * + * @type {SkinnedMesh} + */ this.skinnedMesh = skinnedMesh; + + /** + * Whether to use reference nodes for internal skinned mesh related data or not. + * TODO: Explain the purpose of the property. + * + * @type {Boolean} + */ this.useReference = useReference; + /** + * The update type overwritten since skinning nodes are updated per object. + * + * @type {String} + */ this.updateType = NodeUpdateType.OBJECT; // + /** + * The skin index attribute. + * + * @type {AttributeNode} + */ this.skinIndexNode = attribute( 'skinIndex', 'uvec4' ); + + /** + * The skin weight attribute. + * + * @type {AttributeNode} + */ this.skinWeightNode = attribute( 'skinWeight', 'vec4' ); let bindMatrixNode, bindMatrixInverseNode, boneMatricesNode; @@ -9317,13 +13177,45 @@ class SkinningNode extends Node { } + /** + * The bind matrix node. + * + * @type {Node} + */ this.bindMatrixNode = bindMatrixNode; + + /** + * The bind matrix inverse node. + * + * @type {Node} + */ this.bindMatrixInverseNode = bindMatrixInverseNode; + + /** + * The bind matrices as a uniform buffer node. + * + * @type {Node} + */ this.boneMatricesNode = boneMatricesNode; + + /** + * The previous bind matrices as a uniform buffer node. + * Required for computing motion vectors. + * + * @type {Node?} + * @default null + */ this.previousBoneMatricesNode = null; } + /** + * Transforms the given vertex position via skinning. + * + * @param {Node} [boneMatrices=this.boneMatricesNode] - The bone matrices + * @param {Node} [position=positionLocal] - The vertex position in local space. + * @return {Node} The transformed vertex position. + */ getSkinnedPosition( boneMatrices = this.boneMatricesNode, position = positionLocal ) { const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; @@ -9348,6 +13240,13 @@ class SkinningNode extends Node { } + /** + * Transforms the given vertex normal via skinning. + * + * @param {Node} [boneMatrices=this.boneMatricesNode] - The bone matrices + * @param {Node} [normal=normalLocal] - The vertex normal in local space. + * @return {Node} The transformed vertex normal. + */ getSkinnedNormal( boneMatrices = this.boneMatricesNode, normal = normalLocal ) { const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; @@ -9372,6 +13271,12 @@ class SkinningNode extends Node { } + /** + * Transforms the given vertex normal via skinning. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The skinned position from the previous frame. + */ getPreviousSkinnedPosition( builder ) { const skinnedMesh = builder.object; @@ -9388,14 +13293,25 @@ class SkinningNode extends Node { } + /** + * Returns `true` if bone matrices from the previous frame are required. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Boolean} Whether bone matrices from the previous frame are required or not. + */ needsPreviousBoneMatrices( builder ) { const mrt = builder.renderer.getMRT(); - return mrt && mrt.has( 'velocity' ); + return ( mrt && mrt.has( 'velocity' ) ) || getDataFromObject( builder.object ).useVelocity === true; } + /** + * Setups the skinning node by assigning the transformed vertex data to predefined node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { if ( this.needsPreviousBoneMatrices( builder ) ) { @@ -9425,6 +13341,13 @@ class SkinningNode extends Node { } + /** + * Generates the code snippet of the skinning node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output. + * @return {String} The generated code snippet. + */ generate( builder, output ) { if ( output !== 'void' ) { @@ -9435,6 +13358,11 @@ class SkinningNode extends Node { } + /** + * Updates the state of the skinned mesh by updating the skeleton once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ update( frame ) { const object = this.useReference ? frame.object : this.skinnedMesh; @@ -9452,9 +13380,26 @@ class SkinningNode extends Node { } +/** + * TSL function for creating a skinning node. + * + * @function + * @param {SkinnedMesh} skinnedMesh - The skinned mesh. + * @returns {SkinningNode} + */ const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) ); + +/** + * TSL function for creating a skinning node with reference usage. + * + * @function + * @param {SkinnedMesh} skinnedMesh - The skinned mesh. + * @returns {SkinningNode} + */ const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) ); +/** @module LoopNode **/ + /** * This module offers a variety of ways to implement loops in TSL. In it's basic form it's: * ```js @@ -9468,7 +13413,7 @@ const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinn * * } ); *``` - * Nested loops can be definde in a compacted form: + * Nested loops can be defined in a compacted form: * ```js * Loop( 10, 5, ( { i, j } ) => { * @@ -9698,12 +13643,40 @@ class LoopNode extends Node { } +/** + * TSL function for creating a loop node. + * + * @function + * @param {...Any} params - A list of parameters. + * @returns {LoopNode} + */ const Loop = ( ...params ) => nodeObject( new LoopNode( nodeArray( params, 'int' ) ) ).append(); + +/** + * TSL function for creating a `Continue()` expression. + * + * @function + * @returns {ExpressionNode} + */ const Continue = () => expression( 'continue' ).append(); + +/** + * TSL function for creating a `Break()` expression. + * + * @function + * @returns {ExpressionNode} + */ const Break = () => expression( 'break' ).append(); -// +// deprecated +/** + * @function + * @deprecated since r168. Use {@link Loop} instead. + * + * @param {...any} params + * @returns {LoopNode} + */ const loop = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.LoopNode: loop() has been renamed to Loop().' ); @@ -9711,6 +13684,8 @@ const loop = ( ...params ) => { // @deprecated, r168 }; +/** @module MorphNode **/ + const _morphTextures = /*@__PURE__*/ new WeakMap(); const _morphVec4 = /*@__PURE__*/ new Vector4(); @@ -9853,7 +13828,12 @@ function getEntry( geometry ) { } - +/** + * This node implements the vertex transformation shader logic which is required + * for morph target animation. + * + * @augments Node + */ class MorphNode extends Node { static get type() { @@ -9862,17 +13842,43 @@ class MorphNode extends Node { } + /** + * Constructs a new morph node. + * + * @param {Mesh} mesh - The mesh holding the morph targets. + */ constructor( mesh ) { super( 'void' ); + /** + * The mesh holding the morph targets. + * + * @type {Mesh} + */ this.mesh = mesh; + + /** + * A uniform node which represents the morph base influence value. + * + * @type {UniformNode} + */ this.morphBaseInfluence = uniform( 1 ); + /** + * The update type overwritten since morph nodes are updated per object. + * + * @type {String} + */ this.updateType = NodeUpdateType.OBJECT; } + /** + * Setups the morph node by assigning the transformed vertex data to predefined node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const { geometry } = builder; @@ -9936,7 +13942,12 @@ class MorphNode extends Node { } - update() { + /** + * Updates the state of the morphed mesh by updating the base influence. + * + * @param {NodeFrame} frame - The current node frame. + */ + update( /*frame*/ ) { const morphBaseInfluence = this.morphBaseInfluence; @@ -9954,6 +13965,13 @@ class MorphNode extends Node { } +/** + * TSL function for creating a morph node. + * + * @function + * @param {Mesh} mesh - The mesh holding the morph targets. + * @returns {MorphNode} + */ const morphReference = /*@__PURE__*/ nodeProxy( MorphNode ); /** @@ -10007,7 +14025,7 @@ class AONode extends LightingNode { /** * Constructs a new AO node. * - * @param {Node} aoNode - The ambient occlusion node. + * @param {Node?} [aoNode=null] - The ambient occlusion node. */ constructor( aoNode = null ) { @@ -10016,7 +14034,8 @@ class AONode extends LightingNode { /** * The ambient occlusion node. * - * @type {Node} + * @type {Node?} + * @default null */ this.aoNode = aoNode; @@ -10031,7 +14050,7 @@ class AONode extends LightingNode { } /** - * `LightingContextNode` represents an extension of the {@link ContextNode} module + * `LightingContextNode` represents an extension of the {@link module:ContextNode~ContextNode} module * by adding lighting specific context data. It represents the runtime context of * {@link LightsNode}. * @@ -10049,9 +14068,9 @@ class LightingContextNode extends ContextNode { * Constructs a new lighting context node. * * @param {LightsNode} node - The lights node. - * @param {LightingModel} [lightingModel=null] - The current lighting model. - * @param {Node} [backdropNode=null] - A backdrop node. - * @param {Node} [backdropAlphaNode=null] - A backdrop alpha node. + * @param {LightingModel?} [lightingModel=null] - The current lighting model. + * @param {Node?} [backdropNode=null] - A backdrop node. + * @param {Node?} [backdropAlphaNode=null] - A backdrop alpha node. */ constructor( node, lightingModel = null, backdropNode = null, backdropAlphaNode = null ) { @@ -10060,7 +14079,7 @@ class LightingContextNode extends ContextNode { /** * The current lighting model. * - * @type {LightingModel} + * @type {LightingModel?} * @default null */ this.lightingModel = lightingModel; @@ -10068,7 +14087,7 @@ class LightingContextNode extends ContextNode { /** * A backdrop node. * - * @type {Node} + * @type {Node?} * @default null */ this.backdropNode = backdropNode; @@ -10076,7 +14095,7 @@ class LightingContextNode extends ContextNode { /** * A backdrop alpha node. * - * @type {Node} + * @type {Node?} * @default null */ this.backdropAlphaNode = backdropAlphaNode; @@ -10182,11 +14201,13 @@ class IrradianceNode extends LightingNode { } +/** @module ScreenNode **/ + let screenSizeVec, viewportVec; /** * This node provides a collection of screen related metrics. - * Depending on {@link ScreenNode#scope}, the nodes can represent + * Depending on {@link module:ScreenNode~ScreenNode#scope}, the nodes can represent * resolution or viewport data as well as fragment or uv coordinates. * * @augments Node @@ -10214,7 +14235,7 @@ class ScreenNode extends Node { * - `ScreenNode.COORDINATE`: Window-relative coordinates of the current fragment according to WebGPU standards. * - `ScreenNode.VIEWPORT`: The current viewport defined as a four-dimensional vector. * - `ScreenNode.SIZE`: The dimensions of the current bound framebuffer. - * - `ScreenNode.UV`: Normalized screen coordinates. + * - `ScreenNode.UV`: Normalized coordinates. * * @type {('coordinate'|'viewport'|'size'|'uv')} */ @@ -10362,19 +14383,62 @@ ScreenNode.UV = 'uv'; // Screen +/** + * TSL object that represents normalized screen coordinates, unitless in `[0, 1]`. + * + * @type {ScreenNode} + */ const screenUV = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.UV ); + +/** + * TSL object that represents the screen resolution in physical pixel units. + * + * @type {ScreenNode} + */ const screenSize = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.SIZE ); + +/** + * TSL object that represents the current `x`/`y` pixel position on the screen in physical pixel units. + * + * @type {ScreenNode} + */ const screenCoordinate = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.COORDINATE ); // Viewport +/** + * TSL object that represents the viewport rectangle as `x`, `y`, `width` and `height` in physical pixel units. + * + * @type {ScreenNode} + */ const viewport = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.VIEWPORT ); + +/** + * TSL object that represents the viewport resolution in physical pixel units. + * + * @type {ScreenNode} + */ const viewportSize = viewport.zw; + +/** + * TSL object that represents the current `x`/`y` pixel position on the viewport in physical pixel units. + * + * @type {ScreenNode} + */ const viewportCoordinate = /*@__PURE__*/ screenCoordinate.sub( viewport.xy ); + +/** + * TSL object that represents normalized viewport coordinates, unitless in `[0, 1]`. + * + * @type {ScreenNode} + */ const viewportUV = /*@__PURE__*/ viewportCoordinate.div( viewportSize ); // Deprecated +/** + * @deprecated since r169. Use {@link screenSize} instead. + */ const viewportResolution = /*@__PURE__*/ ( Fn( () => { // @deprecated, r169 console.warn( 'TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.' ); @@ -10383,6 +14447,9 @@ const viewportResolution = /*@__PURE__*/ ( Fn( () => { // @deprecated, r169 }, 'vec2' ).once() )(); +/** + * @deprecated since r168. Use {@link screenUV} instead. + */ const viewportTopLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 console.warn( 'TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.' ); @@ -10391,6 +14458,9 @@ const viewportTopLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 }, 'vec2' ).once() )(); +/** + * @deprecated since r168. Use `screenUV.flipY()` instead. + */ const viewportBottomLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 console.warn( 'TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.' ); @@ -10399,6 +14469,8 @@ const viewportBottomLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 }, 'vec2' ).once() )(); +/** @module ViewportTextureNode **/ + const _size$4 = /*@__PURE__*/ new Vector2(); /** @@ -10408,7 +14480,7 @@ const _size$4 = /*@__PURE__*/ new Vector2(); * (which is good for performance). `ViewportTextureNode` can be used as an input for a * variety of effects like refractive or transmissive materials. * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class ViewportTextureNode extends TextureNode { @@ -10503,9 +14575,30 @@ class ViewportTextureNode extends TextureNode { } +/** + * TSL function for creating a viewport texture node. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Texture?} [framebufferTexture=null] - A framebuffer texture holding the viewport data. If not provided, a framebuffer texture is created automatically. + * @returns {ViewportTextureNode} + */ const viewportTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode ); + +/** + * TSL function for creating a viewport texture node with enabled mipmap generation. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Texture?} [framebufferTexture=null] - A framebuffer texture holding the viewport data. If not provided, a framebuffer texture is created automatically. + * @returns {ViewportTextureNode} + */ const viewportMipTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode, null, null, { generateMipmaps: true } ); +/** @module ViewportDepthTextureNode **/ + let sharedDepthbuffer = null; /** @@ -10513,7 +14606,7 @@ let sharedDepthbuffer = null; * can be used in combination with viewport texture to achieve effects * that require depth evaluation. * - * @augments ViewportTextureNode + * @augments module:ViewportTextureNode~ViewportTextureNode */ class ViewportDepthTextureNode extends ViewportTextureNode { @@ -10524,7 +14617,7 @@ class ViewportDepthTextureNode extends ViewportTextureNode { } /** - * Constructs a new viewport shared texture node. + * Constructs a new viewport depth texture node. * * @param {Node} [uvNode=screenUV] - The uv node. * @param {Node?} [levelNode=null] - The level node. @@ -10543,8 +14636,18 @@ class ViewportDepthTextureNode extends ViewportTextureNode { } +/** + * TSL function for a viewport depth texture node. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @returns {ViewportDepthTextureNode} + */ const viewportDepthTexture = /*@__PURE__*/ nodeProxy( ViewportDepthTextureNode ); +/** @module ViewportDepthNode **/ + /** * This node offers a collection of features in context of the depth logic in the fragment shader. * Depending on {@link ViewportDepthNode#scope}, it can be used to define a depth value for the current @@ -10586,7 +14689,7 @@ class ViewportDepthNode extends Node { * Can be used to define a custom depth value. * The property is ignored in the `ViewportDepthNode.DEPTH` scope. * - * @type {Node} + * @type {Node?} * @default null */ this.valueNode = valueNode; @@ -10679,21 +14782,61 @@ 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 +/** + * TSL function for converting a viewZ value to an orthographic depth value. + * + * @function + * @param {Node} viewZ - The viewZ node. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const viewZToOrthographicDepth = ( viewZ, near, far ) => viewZ.add( near ).div( near.sub( far ) ); -// maps orthographic depth in [ 0, 1 ] to viewZ +/** + * TSL function for converting an orthographic depth value to a viewZ value. + * + * @function + * @param {Node} depth - The orthographic depth. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ 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 +/** + * TSL function for converting a viewZ value to a perspective depth value. + * + * Note: {link https://twitter.com/gonnavis/status/1377183786949959682}. + * + * @function + * @param {Node} viewZ - The viewZ node. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( far.sub( near ).mul( viewZ ) ); -// maps perspective depth in [ 0, 1 ] to viewZ +/** + * TSL function for converting a perspective depth value to a viewZ value. + * + * @function + * @param {Node} depth - The perspective depth. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) ); -// -near maps to 0; -far maps to 1 +/** + * TSL function for converting a viewZ value to a logarithmic depth value. + * + * @function + * @param {Node} viewZ - The viewZ node. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const viewZToLogarithmicDepth = ( viewZ, near, far ) => { // NOTE: viewZ must be negative--see explanation at the end of this comment block. @@ -10729,7 +14872,15 @@ const viewZToLogarithmicDepth = ( viewZ, near, far ) => { }; -// maps logarithmic depth in [ 0, 1 ] to viewZ +/** + * TSL function for converting a logarithmic depth value to a viewZ value. + * + * @function + * @param {Node} depth - The logarithmic depth. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ const logarithmicDepthToViewZ = ( depth, near, far ) => { // NOTE: we add a 'negate()' call to the return value here to maintain consistency with @@ -10740,26 +14891,83 @@ const logarithmicDepthToViewZ = ( depth, near, far ) => { }; +/** + * TSL function for defining a value for the current fragment's depth. + * + * @function + * @param {Node} value - The depth value to set. + * @returns {ViewportDepthNode} + */ const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE ); +/** + * TSL object that represents the depth value for the current fragment. + * + * @type {ViewportDepthNode} + */ const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH ); + +/** + * TSL function for converting a perspective depth value to linear depth. + * + * @function + * @param {Node} value - The perspective depth. + * @returns {ViewportDepthNode} + */ const linearDepth = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.LINEAR_DEPTH ); + +/** + * TSL object that represents the linear (orthographic) depth value of the current fragment + * + * @type {ViewportDepthNode} + */ const viewportLinearDepth = /*@__PURE__*/ linearDepth( viewportDepthTexture() ); depth.assign = ( value ) => depthBase( value ); +/** @module BuiltinNode **/ + +/** + * The node allows to set values for built-in shader variables. That is + * required for features like hardware-accelerated vertex clipping. + * + * @augments Node + */ class BuiltinNode extends Node { + /** + * Constructs a new builtin node. + * + * @param {String} name - The name of the built-in shader variable. + */ constructor( name ) { super( 'float' ); + /** + * The name of the built-in shader variable. + * + * @type {String} + */ this.name = name; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBuiltinNode = true; } + /** + * Generates the code snippet of the builtin node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( /* builder */ ) { return this.name; @@ -10768,8 +14976,25 @@ class BuiltinNode extends Node { } +/** + * TSL function for creating a builtin node. + * + * @function + * @param {String} name - The name of the built-in shader variable. + * @returns {BuiltinNode} + */ const builtin = nodeProxy( BuiltinNode ); +/** @module ClippingNode **/ + +/** + * ``` + * This node is used in {@link NodeMaterial} to setup the clipping + * which can happen hardware-accelerated (if supported) and optionally + * use alpha-to-coverage for anti-aliasing clipped edges. + * ``` + * @augments Node + */ class ClippingNode extends Node { static get type() { @@ -10778,14 +15003,32 @@ class ClippingNode extends Node { } + /** + * Constructs a new clipping node. + * + * @param {('default'|'hardware'|'alphaToCoverage')} [scope='default'] - The node's scope. Similar to other nodes, + * the selected scope influences the behavior of the node and what type of code is generated. + */ constructor( scope = ClippingNode.DEFAULT ) { super(); + /** + * The node's scope. Similar to other nodes, the selected scope influences + * the behavior of the node and what type of code is generated. + * + * @type {('default'|'hardware'|'alphaToCoverage')} + */ this.scope = scope; } + /** + * Setups the node depending on the selected scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The result node. + */ setup( builder ) { super.setup( builder ); @@ -10811,6 +15054,13 @@ class ClippingNode extends Node { } + /** + * Setups alpha to coverage. + * + * @param {Array} intersectionPlanes - The intersection planes. + * @param {Array} unionPlanes - The union planes. + * @return {Node} The result node. + */ setupAlphaToCoverage( intersectionPlanes, unionPlanes ) { return Fn( () => { @@ -10822,7 +15072,7 @@ class ClippingNode extends Node { const numUnionPlanes = unionPlanes.length; - if ( ! this.hardwareClipping && numUnionPlanes > 0 ) { + if ( this.hardwareClipping === false && numUnionPlanes > 0 ) { const clippingPlanes = uniformArray( unionPlanes ); @@ -10869,13 +15119,20 @@ class ClippingNode extends Node { } + /** + * Setups the default clipping. + * + * @param {Array} intersectionPlanes - The intersection planes. + * @param {Array} unionPlanes - The union planes. + * @return {Node} The result node. + */ setupDefault( intersectionPlanes, unionPlanes ) { return Fn( () => { const numUnionPlanes = unionPlanes.length; - if ( ! this.hardwareClipping && numUnionPlanes > 0 ) { + if ( this.hardwareClipping === false && numUnionPlanes > 0 ) { const clippingPlanes = uniformArray( unionPlanes ); @@ -10910,6 +15167,13 @@ class ClippingNode extends Node { } + /** + * Setups hardware clipping. + * + * @param {Array} unionPlanes - The union planes. + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The result node. + */ setupHardwareClipping( unionPlanes, builder ) { const numUnionPlanes = unionPlanes.length; @@ -10940,8 +15204,28 @@ ClippingNode.ALPHA_TO_COVERAGE = 'alphaToCoverage'; ClippingNode.DEFAULT = 'default'; ClippingNode.HARDWARE = 'hardware'; +/** + * TSL function for setting up the default clipping logic. + * + * @function + * @returns {ClippingNode} + */ const clipping = () => nodeObject( new ClippingNode() ); + +/** + * TSL function for setting up alpha to coverage. + * + * @function + * @returns {ClippingNode} + */ const clippingAlpha = () => nodeObject( new ClippingNode( ClippingNode.ALPHA_TO_COVERAGE ) ); + +/** + * TSL function for setting up hardware-based clipping. + * + * @function + * @returns {ClippingNode} + */ const hardwareClipping = () => nodeObject( new ClippingNode( ClippingNode.HARDWARE ) ); // See: https://casual-effects.com/research/Wyman2017Hashed/index.html @@ -11009,6 +15293,11 @@ const getAlphaHashThreshold = /*@__PURE__*/ Fn( ( [ position ] ) => { ] } ); +/** + * Base class for all node materials. + * + * @augments Material + */ class NodeMaterial extends Material { static get type() { @@ -11017,6 +15306,11 @@ class NodeMaterial extends Material { } + /** + * Represents the type of the node material. + * + * @type {String} + */ get type() { return this.constructor.type; @@ -11025,66 +15319,364 @@ class NodeMaterial extends Material { set type( _value ) { /* */ } + /** + * Constructs a new node material. + */ constructor() { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isNodeMaterial = true; - this.forceSinglePass = false; - + /** + * Whether this material is affected by fog or not. + * + * @type {Boolean} + * @default true + */ this.fog = true; + + /** + * Whether this material is affected by lights or not. + * + * @type {Boolean} + * @default false + */ this.lights = false; + + /** + * Whether this material uses hardware clipping or not. + * This property is managed by the engine and should not be + * modified by apps. + * + * @type {Boolean} + * @default false + */ this.hardwareClipping = false; + /** + * Node materials which set their `lights` property to `true` + * are affected by all lights of the scene. Sometimes selective + * lighting is wanted which means only _some_ lights in the scene + * affect a material. This can be achieved by creating an instance + * of {@link module:LightsNode~LightsNode} with a list of selective + * lights and assign the node to this property. + * + * ```js + * const customLightsNode = lights( [ light1, light2 ] ); + * material.lightsNode = customLightsNode; + * ``` + * + * @type {LightsNode?} + * @default null + */ this.lightsNode = null; + + /** + * The environment of node materials can be defined by an environment + * map assigned to the `envMap` property or by `Scene.environment` + * if the node material is a PBR material. This node property allows to overwrite + * the default behavior and define the environment with a custom node. + * + * ```js + * material.envNode = pmremTexture( renderTarget.texture ); + * ``` + * + * @type {Node?} + * @default null + */ this.envNode = null; + + /** + * The lighting of node materials might be influenced by ambient occlusion. + * The default AO is inferred from an ambient occlusion map assigned to `aoMap` + * and the respective `aoMapIntensity`. This node property allows to overwrite + * the default and define the ambient occlusion with a custom node instead. + * + * If you don't want to overwrite the diffuse color but modify the existing + * values instead, use {@link module:MaterialNode.materialAO}. + * + * @type {Node?} + * @default null + */ this.aoNode = null; + /** + * The diffuse color of node materials is by default inferred from the + * `color` and `map` properties. This node property allows to overwrite the default + * and define the diffuse color with a node instead. + * + * ```js + * material.colorNode = color( 0xff0000 ); // define red color + * ``` + * + * If you don't want to overwrite the diffuse color but modify the existing + * values instead, use {@link module:MaterialNode.materialColor}. + * + * ```js + * material.colorNode = materialColor.mul( color( 0xff0000 ) ); // give diffuse colors a red tint + * ``` + * + * @type {Node?} + * @default null + */ this.colorNode = null; + + /** + * The normals of node materials are by default inferred from the `normalMap`/`normalScale` + * or `bumpMap`/`bumpScale` properties. This node property allows to overwrite the default + * and define the normals with a node instead. + * + * If you don't want to overwrite the normals but modify the existing values instead, + * use {@link module:MaterialNode.materialNormal}. + * + * @type {Node?} + * @default null + */ this.normalNode = null; + + /** + * The opacity of node materials is by default inferred from the `opacity` + * and `alphaMap` properties. This node property allows to overwrite the default + * and define the opacity with a node instead. + * + * If you don't want to overwrite the normals but modify the existing + * value instead, use {@link module:MaterialNode.materialOpacity}. + * + * @type {Node?} + * @default null + */ this.opacityNode = null; + + /** + * This node can be used to to implement a variety of filter-like effects. The idea is + * to store the current rendering into a texture e.g. via `viewportSharedTexture()`, use it + * to create an arbitrary effect and then assign the node composition to this property. + * Everything behind the object using this material will now be affected by a filter. + * + * ```js + * const material = new NodeMaterial() + * material.transparent = true; + * + * // everything behind the object will be monochromatic + * material.backdropNode = viewportSharedTexture().rgb.saturation( 0 ); + * ``` + * + * Backdrop computations are part of the lighting so only lit materials can use this property. + * + * @type {Node?} + * @default null + */ this.backdropNode = null; + + /** + * This node allows to modulate the influence of `backdropNode` to the outgoing light. + * + * @type {Node?} + * @default null + */ this.backdropAlphaNode = null; + + /** + * The alpha test of node materials is by default inferred from the `alphaTest` + * property. This node property allows to overwrite the default and define the + * alpha test with a node instead. + * + * If you don't want to overwrite the alpha test but modify the existing + * value instead, use {@link module:MaterialNode.materialAlphaTest}. + * + * @type {Node?} + * @default null + */ this.alphaTestNode = null; + /** + * The local vertex positions are computed based on multiple factors like the + * attribute data, morphing or skinning. This node property allows to overwrite + * the default and define local vertex positions with nodes instead. + * + * If you don't want to overwrite the vertex positions but modify the existing + * values instead, use {@link module:Position.positionLocal}. + * + *```js + * material.positionNode = positionLocal.add( displace ); + * ``` + * + * @type {Node?} + * @default null + */ this.positionNode = null; + + /** + * This node property is intended for logic which modifies geometry data once or per animation step. + * Apps usually place such logic randomly in initialization routines or in the animation loop. + * `geometryNode` is intended as a dedicated API so there is an intended spot where geometry modifications + * can be implemented. + * + * The idea is to assign a `Fn` definition that holds the geometry modification logic. A typical example + * would be a GPU based particle system that provides a node material for usage on app level. The particle + * simulation would be implemented as compute shaders and managed inside a `Fn` function. This function is + * eventually assigned to `geometryNode`. + * + * @type {Function} + * @default null + */ this.geometryNode = null; + /** + * Allows to overwrite depth values in the fragment shader. + * + * @type {Node?} + * @default null + */ this.depthNode = null; + + /** + * Allows to overwrite the position used for shadow map rendering which + * is by default {@link module:Position.positionWorld}, the vertex position + * in world space. + * + * @type {Node?} + * @default null + */ this.shadowPositionNode = null; + + /** + * This node can be used to influence how an object using this node material + * receive shadows. + * + * ```js + * const totalShadows = float( 1 ).toVar(); + * material.receivedShadowNode = Fn( ( [ shadow ] ) => { + * totalShadows.mulAssign( shadow ); + * //return float( 1 ); // bypass received shadows + * return shadow.mix( color( 0xff0000 ), 1 ); // modify shadow color + * } ); + * + * @type {Node?} + * @default null + */ this.receivedShadowNode = null; + + /** + * This node can be used to influence how an object using this node material + * casts shadows. To apply a color to shadows, you can simply do: + * + * ```js + * material.castShadowNode = vec4( 1, 0, 0, 1 ); + * ``` + * + * Which can be nice to fake colored shadows of semi-transparent objects. It + * is also common to use the property with `Fn` function so checks are performed + * per fragment. + * + * ```js + * materialCustomShadow.castShadowNode = Fn( () => { + * hash( vertexIndex ).greaterThan( 0.5 ).discard(); + * return materialColor; + * } )(); + * ``` + * + * @type {Node?} + * @default null + */ this.castShadowNode = null; + /** + * This node can be used to define the final output of the material. + * + * TODO: Explain the differences to `fragmentNode`. + * + * @type {Node?} + * @default null + */ this.outputNode = null; + + /** + * MRT configuration is done on renderer or pass level. This node allows to + * overwrite what values are written into MRT targets on material level. This + * can be useful for implementing selective FX features that should only affect + * specific objects. + * + * @type {MRTNode?} + * @default null + */ this.mrtNode = null; + /** + * This node property can be used if you need complete freedom in implementing + * the fragment shader. Assigning a node will replace the built-in material + * logic used in the fragment stage. + * + * @type {Node?} + * @default null + */ this.fragmentNode = null; + + /** + * This node property can be used if you need complete freedom in implementing + * the vertex shader. Assigning a node will replace the built-in material logic + * used in the vertex stage. + * + * @type {Node?} + * @default null + */ this.vertexNode = null; } + /** + * Allows to define a custom cache key that influence the material key computation + * for render objects. + * + * @return {String} The custom cache key. + */ customProgramCacheKey() { return this.type + getCacheKey$1( this ); } + /** + * Builds this material with the given node builder. + * + * @param {NodeBuilder} builder - The current node builder. + */ build( builder ) { this.setup( builder ); } + /** + * Setups a node material observer with the given builder. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {NodeMaterialObserver} The node material observer. + */ setupObserver( builder ) { return new NodeMaterialObserver( builder ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { builder.context.setupNormal = () => this.setupNormal( builder ); + builder.context.setupPositionView = () => this.setupPositionView( builder ); + builder.context.setupModelViewProjection = () => this.setupModelViewProjection( builder ); const renderer = builder.renderer; const renderTarget = renderer.getRenderTarget(); @@ -11093,7 +15685,11 @@ class NodeMaterial extends Material { builder.addStack(); - builder.stack.outputNode = this.vertexNode || this.setupPosition( builder ); + const vertexNode = this.vertexNode || this.setupVertex( builder ); + + builder.stack.outputNode = vertexNode; + + this.setupHardwareClipping( builder ); if ( this.geometryNode !== null ) { @@ -11111,7 +15707,7 @@ class NodeMaterial extends Material { const clippingNode = this.setupClipping( builder ); - if ( this.depthWrite === true ) { + if ( this.depthWrite === true || this.depthTest === true ) { // only write depth if depth buffer is configured @@ -11199,6 +15795,12 @@ class NodeMaterial extends Material { } + /** + * Setups the clipping node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ClippingNode} The clipping node. + */ setupClipping( builder ) { if ( builder.clippingContext === null ) return null; @@ -11228,6 +15830,11 @@ class NodeMaterial extends Material { } + /** + * Setups the hardware clipping if available on the current device. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupHardwareClipping( builder ) { this.hardwareClipping = false; @@ -11250,6 +15857,11 @@ class NodeMaterial extends Material { } + /** + * Setups the depth of this material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupDepth( builder ) { const { renderer, camera } = builder; @@ -11290,14 +15902,58 @@ class NodeMaterial extends Material { } - setupPosition( builder ) { + /** + * Setups the position node in view space. This method exists + * so derived node materials can modify the implementation e.g. sprite materials. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in view space. + */ + setupPositionView( /*builder*/ ) { - const { object } = builder; - const geometry = object.geometry; + return modelViewMatrix.mul( positionLocal ).xyz; + + } + + /** + * Setups the position in clip space. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in view space. + */ + setupModelViewProjection( /*builder*/ ) { + + return cameraProjectionMatrix.mul( positionView ); + + } + + /** + * Setups the logic for the vertex stage. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in clip space. + */ + setupVertex( builder ) { builder.addStack(); - // Vertex + this.setupPosition( builder ); + + builder.context.vertex = builder.removeStack(); + + return modelViewProjection; + + } + + /** + * Setups the computation of the position in local space. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in local space. + */ + setupPosition( builder ) { + + const { object, geometry } = builder; if ( geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color ) { @@ -11335,21 +15991,20 @@ class NodeMaterial extends Material { if ( this.positionNode !== null ) { - positionLocal.assign( this.positionNode ); + positionLocal.assign( this.positionNode.context( { isPositionNodeInput: true } ) ); } - this.setupHardwareClipping( builder ); - - const mvp = modelViewProjection(); - - builder.context.vertex = builder.removeStack(); - builder.context.mvp = mvp; - - return mvp; + return positionLocal; } + /** + * Setups the computation of the material's diffuse color. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {BufferGeometry} geometry - The geometry. + */ setupDiffuseColor( { object, geometry } ) { let colorNode = this.colorNode ? vec4( this.colorNode ) : materialColor; @@ -11416,24 +16071,47 @@ class NodeMaterial extends Material { } + /** + * Abstract interface method that can be implemented by derived materials + * to setup material-specific node variables. + * + * @abstract + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( /*builder*/ ) { // Interface function. } + /** + * Setups the outgoing light node variable + * + * @return {Node} The outgoing light node. + */ setupOutgoingLight() { return ( this.lights === true ) ? vec3( 0 ) : diffuseColor.rgb; } + /** + * Setups the normal node from the material. + * + * @return {Node} The normal node. + */ setupNormal() { return this.normalNode ? vec3( this.normalNode ) : materialNormal; } + /** + * Setups the environment node from the material. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The environment node. + */ setupEnvironment( /*builder*/ ) { let node = null; @@ -11452,6 +16130,12 @@ class NodeMaterial extends Material { } + /** + * Setups the light map node from the material. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The light map node. + */ setupLightMap( builder ) { let node = null; @@ -11466,6 +16150,12 @@ class NodeMaterial extends Material { } + /** + * Setups the lights node based on the scene, environment and material. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {LightsNode} The lights node. + */ setupLights( builder ) { const materialLightsNode = []; @@ -11490,7 +16180,7 @@ class NodeMaterial extends Material { if ( this.aoNode !== null || builder.material.aoMap ) { - const aoNode = this.aoNode !== null ? this.aoNode : materialAOMap; + const aoNode = this.aoNode !== null ? this.aoNode : materialAO; materialLightsNode.push( new AONode( aoNode ) ); @@ -11508,12 +16198,26 @@ class NodeMaterial extends Material { } + /** + * This method should be implemented by most derived materials + * since it defines the material's lighting model. + * + * @abstract + * @param {NodeBuilder} builder - The current node builder. + * @return {LightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { // Interface function. } + /** + * Setups the outgoing light node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The outgoing light node. + */ setupLighting( builder ) { const { material } = builder; @@ -11553,6 +16257,13 @@ class NodeMaterial extends Material { } + /** + * Setups the output node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} outputNode - The existing output node. + * @return {Node} The output node. + */ setupOutput( builder, outputNode ) { // FOG @@ -11561,7 +16272,13 @@ class NodeMaterial extends Material { const fogNode = builder.fogNode; - if ( fogNode ) outputNode = vec4( fogNode.mix( outputNode.rgb, fogNode.colorNode ), outputNode.a ); + if ( fogNode ) { + + output.assign( outputNode ); + + outputNode = vec4( fogNode ); + + } } @@ -11569,6 +16286,13 @@ class NodeMaterial extends Material { } + /** + * Most classic material types have a node pendant e.g. for `MeshBasicMaterial` + * there is `MeshBasicNodeMaterial`. This utility method is intended for + * defining all material properties of the classic type in the node type. + * + * @param {Material} material - The material to copy properties with their values to this node material. + */ setDefaultValues( material ) { // This approach is to reuse the native refreshUniforms* @@ -11603,6 +16327,12 @@ class NodeMaterial extends Material { } + /** + * Serializes this material to JSON. + * + * @param {(Object|String)?} meta - The meta information for serialization. + * @return {Object} The serialized node. + */ toJSON( meta ) { const isRoot = ( meta === undefined || typeof meta === 'string' ); @@ -11662,6 +16392,12 @@ class NodeMaterial extends Material { } + /** + * Copies the properties of the given node material to this instance. + * + * @param {NodeMaterial} source - The material to copy. + * @return {NodeMaterial} A reference to this node material. + */ copy( source ) { this.lightsNode = source.lightsNode; @@ -11694,150 +16430,13 @@ class NodeMaterial extends Material { } -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(); +/** + * Node material version of `LineBasicMaterial`. + * + * @augments NodeMaterial + */ class LineBasicNodeMaterial extends NodeMaterial { static get type() { @@ -11846,14 +16445,24 @@ class LineBasicNodeMaterial extends NodeMaterial { } + /** + * Constructs a new line basic node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isLineBasicNodeMaterial = true; - this.lights = false; - this.setDefaultValues( _defaultValues$d ); this.setValues( parameters ); @@ -11864,6 +16473,11 @@ class LineBasicNodeMaterial extends NodeMaterial { const _defaultValues$c = /*@__PURE__*/ new LineDashedMaterial(); +/** + * Node material version of `LineDashedMaterial`. + * + * @augments NodeMaterial + */ class LineDashedNodeMaterial extends NodeMaterial { static get type() { @@ -11872,33 +16486,101 @@ class LineDashedNodeMaterial extends NodeMaterial { } + /** + * Constructs a new line dashed node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isLineDashedNodeMaterial = true; - this.lights = false; - this.setDefaultValues( _defaultValues$c ); + /** + * The dash offset. + * + * @type {Number} + * @default 0 + */ this.dashOffset = 0; + /** + * The offset of dash materials is by default inferred from the `dashOffset` + * property. This node property allows to overwrite the default + * and define the offset with a node instead. + * + * If you don't want to overwrite the offset but modify the existing + * value instead, use {@link module:MaterialNode.materialLineDashOffset}. + * + * @type {Node?} + * @default null + */ this.offsetNode = null; + + /** + * The scale of dash materials is by default inferred from the `scale` + * property. This node property allows to overwrite the default + * and define the scale with a node instead. + * + * If you don't want to overwrite the scale but modify the existing + * value instead, use {@link module:MaterialNode.materialLineScale}. + * + * @type {Node?} + * @default null + */ this.dashScaleNode = null; + + /** + * The dash size of dash materials is by default inferred from the `dashSize` + * property. This node property allows to overwrite the default + * and define the dash size with a node instead. + * + * If you don't want to overwrite the dash size but modify the existing + * value instead, use {@link module:MaterialNode.materialLineDashSize}. + * + * @type {Node?} + * @default null + */ this.dashSizeNode = null; + + /** + * The gap size of dash materials is by default inferred from the `gapSize` + * property. This node property allows to overwrite the default + * and define the gap size with a node instead. + * + * If you don't want to overwrite the gap size but modify the existing + * value instead, use {@link module:MaterialNode.materialLineGapSize}. + * + * @type {Node?} + * @default null + */ this.gapSizeNode = null; this.setValues( parameters ); } - setupVariants() { + /** + * Setups the dash specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ + setupVariants( /* builder */ ) { - const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset; + const offsetNode = this.offsetNode ? float( this.offsetNode ) : 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; + const gapSizeNode = this.gapSizeNode ? float( this.gapSizeNode ) : materialLineGapSize; dashSize.assign( dashSizeNode ); gapSize.assign( gapSizeNode ); @@ -11912,6 +16594,8 @@ class LineDashedNodeMaterial extends NodeMaterial { } +/** @module ViewportSharedTextureNode **/ + let _sharedFramebuffer = null; /** @@ -11919,7 +16603,7 @@ let _sharedFramebuffer = null; * shares a texture across all instances of `ViewportSharedTextureNode`. It should * be the first choice when using data of the default/screen framebuffer for performance reasons. * - * @augments ViewportTextureNode + * @augments module:ViewportTextureNode~ViewportTextureNode */ class ViewportSharedTextureNode extends ViewportTextureNode { @@ -11955,10 +16639,24 @@ class ViewportSharedTextureNode extends ViewportTextureNode { } +/** + * TSL function for creating a shared viewport texture node. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @returns {ViewportSharedTextureNode} + */ const viewportSharedTexture = /*@__PURE__*/ nodeProxy( ViewportSharedTextureNode ); const _defaultValues$b = /*@__PURE__*/ new LineDashedMaterial(); +/** + * This node material can be used to render lines with a size larger than one + * by representing them as instanced meshes. + * + * @augments NodeMaterial + */ class Line2NodeMaterial extends NodeMaterial { static get type() { @@ -11967,49 +16665,120 @@ class Line2NodeMaterial extends NodeMaterial { } - constructor( params = {} ) { + /** + * Constructs a new node material for wide line rendering. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters = {} ) { super(); - this.lights = false; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isLine2NodeMaterial = true; this.setDefaultValues( _defaultValues$b ); - this.useAlphaToCoverage = true; - this.useColor = params.vertexColors; - this.useDash = params.dashed; - this.useWorldUnits = false; + /** + * Whether vertex colors should be used or not. + * + * @type {Boolean} + * @default false + */ + this.useColor = parameters.vertexColors; + /** + * The dash offset. + * + * @type {Number} + * @default 0 + */ this.dashOffset = 0; + + /** + * The line width. + * + * @type {Number} + * @default 0 + */ this.lineWidth = 1; + /** + * Defines the lines color. + * + * @type {Node?} + * @default null + */ this.lineColorNode = null; + /** + * Defines the offset. + * + * @type {Node?} + * @default null + */ this.offsetNode = null; + + /** + * Defines the dash scale. + * + * @type {Node?} + * @default null + */ this.dashScaleNode = null; + + /** + * Defines the dash size. + * + * @type {Node?} + * @default null + */ this.dashSizeNode = null; + + /** + * Defines the gap size. + * + * @type {Node?} + * @default null + */ this.gapSizeNode = null; + /** + * Blending is set to `NoBlending` since transparency + * is not supported, yet. + * + * @type {Number} + * @default 0 + */ this.blending = NoBlending; - this.setValues( params ); + this._useDash = parameters.dashed; + this._useAlphaToCoverage = true; + this._useWorldUnits = false; + + this.setValues( parameters ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { - this.setupShaders( builder ); - - super.setup( builder ); - - } - - setupShaders( { renderer } ) { + const { renderer } = builder; - const useAlphaToCoverage = this.alphaToCoverage; + const useAlphaToCoverage = this._useAlphaToCoverage; const useColor = this.useColor; - const useDash = this.dashed; - const useWorldUnits = this.worldUnits; + const useDash = this._useDash; + const useWorldUnits = this._useWorldUnits; const trimSegment = Fn( ( { start, end } ) => { @@ -12043,7 +16812,7 @@ class Line2NodeMaterial extends NodeMaterial { if ( useDash ) { const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale; - const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset; + const offsetNode = this.offsetNode ? float( this.offsetNode ) : materialLineDashOffset; const instanceDistanceStart = attribute( 'instanceDistanceStart' ); const instanceDistanceEnd = attribute( 'instanceDistanceEnd' ); @@ -12220,7 +16989,7 @@ class Line2NodeMaterial extends NodeMaterial { if ( useDash ) { const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize; - const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize; + const gapSizeNode = this.gapSizeNode ? float( this.gapSizeNode ) : materialLineGapSize; dashSize.assign( dashSizeNode ); gapSize.assign( gapSizeNode ); @@ -12337,56 +17106,74 @@ class Line2NodeMaterial extends NodeMaterial { } - } + super.setup( builder ); + } + /** + * Whether the lines should sized in world units or not. + * When set to `false` the unit is pixel. + * + * @type {Boolean} + * @default false + */ get worldUnits() { - return this.useWorldUnits; + return this._useWorldUnits; } set worldUnits( value ) { - if ( this.useWorldUnits !== value ) { + if ( this._useWorldUnits !== value ) { - this.useWorldUnits = value; + this._useWorldUnits = value; this.needsUpdate = true; } } - + /** + * Whether the lines should be dashed or not. + * + * @type {Boolean} + * @default false + */ get dashed() { - return this.useDash; + return this._useDash; } set dashed( value ) { - if ( this.useDash !== value ) { + if ( this._useDash !== value ) { - this.useDash = value; + this._useDash = value; this.needsUpdate = true; } } - + /** + * Whether alpha to coverage should be used or not. + * + * @type {Boolean} + * @default true + */ get alphaToCoverage() { - return this.useAlphaToCoverage; + return this._useAlphaToCoverage; } set alphaToCoverage( value ) { - if ( this.useAlphaToCoverage !== value ) { + if ( this._useAlphaToCoverage !== value ) { - this.useAlphaToCoverage = value; + this._useAlphaToCoverage = value; this.needsUpdate = true; } @@ -12417,6 +17204,11 @@ const colorToDirection = ( node ) => nodeObject( node ).mul( 2.0 ).sub( 1 ); const _defaultValues$a = /*@__PURE__*/ new MeshNormalMaterial(); +/** + * Node material version of `MeshNormalMaterial`. + * + * @augments NodeMaterial + */ class MeshNormalNodeMaterial extends NodeMaterial { static get type() { @@ -12425,12 +17217,22 @@ class MeshNormalNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh normal node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); - this.lights = false; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshNormalNodeMaterial = true; this.setDefaultValues( _defaultValues$a ); @@ -12439,6 +17241,10 @@ class MeshNormalNodeMaterial extends NodeMaterial { } + /** + * Overwrites the default implementation by computing the diffuse color + * based on the normal data. + */ setupDiffuseColor() { const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity; @@ -12449,6 +17255,8 @@ class MeshNormalNodeMaterial extends NodeMaterial { } +/** @module EquirectUVNode **/ + /** * Can be used to compute texture coordinates for projecting an * equirectangular texture onto a mesh for using it as the scene's @@ -12471,7 +17279,7 @@ class EquirectUVNode extends TempNode { /** * Constructs a new equirect uv node. * - * @param {Node} [dirNode=positionWorldDirection] - A direction vector for sampling why is by default `positionWorldDirection`. + * @param {Node} [dirNode=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`. */ constructor( dirNode = positionWorldDirection ) { @@ -12490,7 +17298,7 @@ class EquirectUVNode extends TempNode { const dir = this.dirNode; - const u = dir.z.atan2( dir.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 ); + const u = dir.z.atan( 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 ); @@ -12499,10 +17307,23 @@ class EquirectUVNode extends TempNode { } +/** + * TSL function for creating an equirect uv node. + * + * @function + * @param {Node} [dirNode=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`. + * @returns {EquirectUVNode} + */ const equirectUV = /*@__PURE__*/ nodeProxy( EquirectUVNode ); // @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget +/** + * This class represents a cube render target. It is a special version + * of `WebGLCubeRenderTarget` which is compatible with `WebGPURenderer`. + * + * @augments WebGLCubeRenderTarget + */ class CubeRenderTarget extends WebGLCubeRenderTarget { constructor( size = 1, options = {} ) { @@ -12513,6 +17334,13 @@ class CubeRenderTarget extends WebGLCubeRenderTarget { } + /** + * Converts the given equirectangular texture to a cube map. + * + * @param {Renderer} renderer - The renderer. + * @param {Texture} texture - The equirectangular texture. + * @return {CubeRenderTarget} A reference to this cube render target. + */ fromEquirectangularTexture( renderer, texture$1 ) { const currentMinFilter = texture$1.minFilter; @@ -12565,6 +17393,8 @@ class CubeRenderTarget extends WebGLCubeRenderTarget { } +/** @module CubeMapNode **/ + const _cache$1 = new WeakMap(); /** @@ -12783,11 +17613,18 @@ function mapTextureMapping( texture, mapping ) { } +/** + * TSL function for creating a cube map node. + * + * @function + * @param {Node} envNode - The node representing the environment map. + * @returns {CubeMapNode} + */ const cubeMapNode = /*@__PURE__*/ nodeProxy( CubeMapNode ); /** * Represents a basic model for Image-based lighting (IBL). The environment - * is defined via environment maps in the equirectanular or cube map format. + * is defined via environment maps in the equirectangular or cube map format. * `BasicEnvironmentNode` is intended for non-PBR materials like {@link MeshBasicNodeMaterial} * or {@link MeshPhongNodeMaterial}. * @@ -12848,7 +17685,7 @@ class BasicLightMapNode extends LightingNode { /** * Constructs a new basic light map node. * - * @param {Node} lightMapNode - The light map node. + * @param {Node?} [lightMapNode=null] - The light map node. */ constructor( lightMapNode = null ) { @@ -12857,7 +17694,7 @@ class BasicLightMapNode extends LightingNode { /** * The light map node. * - * @type {Node} + * @type {Node?} */ this.lightMapNode = lightMapNode; @@ -13047,6 +17884,11 @@ class BasicLightingModel extends LightingModel { const _defaultValues$9 = /*@__PURE__*/ new MeshBasicMaterial(); +/** + * Node material version of `MeshBasicMaterial`. + * + * @augments NodeMaterial + */ class MeshBasicNodeMaterial extends NodeMaterial { static get type() { @@ -13055,12 +17897,32 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh basic node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshBasicNodeMaterial = true; + /** + * Although the basic material is by definition unlit, we set + * this property to `true` since we use a lighting model to compute + * the outgoing light of the fragment shader. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues$9 ); @@ -13069,12 +17931,25 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * Basic materials are not affected by normal and bump maps so we + * return by default {@link module:Normal.normalView}. + * + * @return {Node} The normal node. + */ setupNormal() { return normalView; // see #28839 } + /** + * Overwritten since this type of material uses {@link BasicEnvironmentNode} + * to implement the default environment mapping. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicEnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { const envNode = super.setupEnvironment( builder ); @@ -13083,6 +17958,13 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * This method must be overwritten since light maps are evaluated + * with a special scaling factor for basic materials. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicLightMapNode?} The light map node. + */ setupLightMap( builder ) { let node = null; @@ -13097,12 +17979,23 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * The material overwrites this method because `lights` is set to `true` but + * we still want to return the diffuse color as the outgoing light. + * + * @return {Node} The outgoing light node. + */ setupOutgoingLight() { return diffuseColor.rgb; } + /** + * Setups the lighting model. + * + * @return {BasicLightingModel} The lighting model. + */ setupLightingModel() { return new BasicLightingModel(); @@ -13156,7 +18049,7 @@ const BRDF_BlinnPhong = /*@__PURE__*/ Fn( ( { lightDirection } ) => { /** * Represents the lighting model for a phong material. Used in {@link MeshPhongNodeMaterial}. * - * @augments LightingModel + * @augments BasicLightingModel */ class PhongLightingModel extends BasicLightingModel { @@ -13171,7 +18064,7 @@ class PhongLightingModel extends BasicLightingModel { /** * Whether specular is supported or not. Set this to `false` if you are - * lookking for a Lambert-like material meaning a material for non-shiny + * looking for a Lambert-like material meaning a material for non-shiny * surfaces, without specular highlights. * * @type {Boolean} @@ -13223,6 +18116,11 @@ class PhongLightingModel extends BasicLightingModel { const _defaultValues$8 = /*@__PURE__*/ new MeshLambertMaterial(); +/** + * Node material version of `MeshLambertMaterial`. + * + * @augments NodeMaterial + */ class MeshLambertNodeMaterial extends NodeMaterial { static get type() { @@ -13231,12 +18129,30 @@ class MeshLambertNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh lambert node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshLambertNodeMaterial = true; + /** + * Set to `true` because lambert materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues$8 ); @@ -13245,6 +18161,13 @@ class MeshLambertNodeMaterial extends NodeMaterial { } + /** + * Overwritten since this type of material uses {@link BasicEnvironmentNode} + * to implement the default environment mapping. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicEnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { const envNode = super.setupEnvironment( builder ); @@ -13253,6 +18176,11 @@ class MeshLambertNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhongLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhongLightingModel( false ); // ( specular ) -> force lambert @@ -13263,6 +18191,11 @@ class MeshLambertNodeMaterial extends NodeMaterial { const _defaultValues$7 = /*@__PURE__*/ new MeshPhongMaterial(); +/** + * Node material version of `MeshPhongMaterial`. + * + * @augments NodeMaterial + */ class MeshPhongNodeMaterial extends NodeMaterial { static get type() { @@ -13271,15 +18204,56 @@ class MeshPhongNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh lambert node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshPhongNodeMaterial = true; + /** + * Set to `true` because phong materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; + /** + * The shininess of phong materials is by default inferred from the `shininess` + * property. This node property allows to overwrite the default + * and define the shininess with a node instead. + * + * If you don't want to overwrite the shininess but modify the existing + * value instead, use {@link module:MaterialNode.materialShininess}. + * + * @type {Node?} + * @default null + */ this.shininessNode = null; + + /** + * The specular color of phong materials is by default inferred from the + * `specular` property. This node property allows to overwrite the default + * and define the specular color with a node instead. + * + * If you don't want to overwrite the specular color but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecular}. + * + * @type {Node?} + * @default null + */ this.specularNode = null; this.setDefaultValues( _defaultValues$7 ); @@ -13288,6 +18262,13 @@ class MeshPhongNodeMaterial extends NodeMaterial { } + /** + * Overwritten since this type of material uses {@link BasicEnvironmentNode} + * to implement the default environment mapping. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicEnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { const envNode = super.setupEnvironment( builder ); @@ -13296,13 +18277,23 @@ class MeshPhongNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhongLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhongLightingModel(); } - setupVariants() { + /** + * Setups the phong specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ + setupVariants( /*builder*/ ) { // SHININESS @@ -13728,6 +18719,8 @@ const LTC_Evaluate = /*@__PURE__*/ Fn( ( { N, V, P, mInv, p0, p1, p2, p3 } ) => ] } ); +/** @module TextureBicubic **/ + // Mipped Bicubic Texture Filtering by N8 // https://www.shadertoy.com/view/Dl2SDW @@ -13777,6 +18770,14 @@ const bicubic = ( textureNode, texelSize, lod ) => { }; +/** + * Applies mipped bicubic texture filtering to the given texture node. + * + * @method + * @param {TextureNode} textureNode - The texture node that should be filtered. + * @param {Node} [lodNode=float(3)] - Defines the LOD to sample from. + * @return {Node} The filtered texture sample. + */ const textureBicubic = /*@__PURE__*/ Fn( ( [ textureNode, lodNode = float( 3 ) ] ) => { const fLodSize = vec2( textureNode.size( int( lodNode ) ) ); @@ -14846,6 +19847,8 @@ const blur = /*@__PURE__*/ Fn( ( { n, latitudinal, poleAxis, outputDirection, we } ); +/** @module PMREMNode **/ + let _generator = null; const _cache = new WeakMap(); @@ -15195,13 +20198,22 @@ function isEquirectangularMapReady( image ) { } +/** + * TSL function for creating a PMREM node. + * + * @function + * @param {Texture} value - The input texture. + * @param {Node} [uvNode=null] - The uv node. + * @param {Node} [levelNode=null] - The level node. + * @returns {PMREMNode} + */ const pmremTexture = /*@__PURE__*/ nodeProxy( PMREMNode ); const _envNodeCache = new WeakMap(); /** * Represents a physical model for Image-based lighting (IBL). The environment - * is defined via environment maps in the equirectanular, cube map or cubeUV (PMREM) format. + * is defined via environment maps in the equirectangular, cube map or cubeUV (PMREM) format. * `EnvironmentNode` is intended for PBR materials like {@link MeshStandardNodeMaterial}. * * @augments LightingNode @@ -15226,7 +20238,7 @@ class EnvironmentNode extends LightingNode { /** * A node representing the environment. * - * @type {Node} + * @type {Node?} * @default null */ this.envNode = envNode; @@ -15343,6 +20355,11 @@ const createIrradianceContext = ( normalWorldNode ) => { const _defaultValues$6 = /*@__PURE__*/ new MeshStandardMaterial(); +/** + * Node material version of `MeshStandardMaterial`. + * + * @augments NodeMaterial + */ class MeshStandardNodeMaterial extends NodeMaterial { static get type() { @@ -15351,17 +20368,69 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh standard node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshStandardNodeMaterial = true; + /** + * Set to `true` because standard materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; + /** + * The emissive color of standard materials is by default inferred from the `emissive`, + * `emissiveIntensity` and `emissiveMap` properties. This node property allows to + * overwrite the default and define the emissive color with a node instead. + * + * If you don't want to overwrite the emissive color but modify the existing + * value instead, use {@link module:MaterialNode.materialEmissive}. + * + * @type {Node?} + * @default null + */ this.emissiveNode = null; + /** + * The metalness of standard materials is by default inferred from the `metalness`, + * and `metalnessMap` properties. This node property allows to + * overwrite the default and define the metalness with a node instead. + * + * If you don't want to overwrite the metalness but modify the existing + * value instead, use {@link module:MaterialNode.materialMetalness}. + * + * @type {Node?} + * @default null + */ this.metalnessNode = null; + + /** + * The roughness of standard materials is by default inferred from the `roughness`, + * and `roughnessMap` properties. This node property allows to + * overwrite the default and define the roughness with a node instead. + * + * If you don't want to overwrite the roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialRoughness}. + * + * @type {Node?} + * @default null + */ this.roughnessNode = null; this.setDefaultValues( _defaultValues$6 ); @@ -15370,6 +20439,14 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Overwritten since this type of material uses {@link EnvironmentNode} + * to implement the PBR (PMREM based) environment mapping. Besides, the + * method honors `Scene.environment`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {EnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { let envNode = super.setupEnvironment( builder ); @@ -15384,12 +20461,20 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhysicalLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhysicalLightingModel(); } + /** + * Setups the specular related node variables. + */ setupSpecular() { const specularColorNode = mix( vec3( 0.04 ), diffuseColor.rgb, metalness ); @@ -15399,6 +20484,11 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Setups the standard specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants() { // METALNESS @@ -15439,6 +20529,11 @@ class MeshStandardNodeMaterial extends NodeMaterial { const _defaultValues$5 = /*@__PURE__*/ new MeshPhysicalMaterial(); +/** + * Node material version of `MeshPhysicalMaterial`. + * + * @augments MeshStandardNodeMaterial + */ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { static get type() { @@ -15447,33 +20542,243 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Constructs a new mesh physical node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshPhysicalNodeMaterial = true; + /** + * The clearcoat of physical materials is by default inferred from the `clearcoat` + * and `clearcoatMap` properties. This node property allows to overwrite the default + * and define the clearcoat with a node instead. + * + * If you don't want to overwrite the clearcoat but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoat}. + * + * @type {Node?} + * @default null + */ this.clearcoatNode = null; + + /** + * The clearcoat roughness of physical materials is by default inferred from the `clearcoatRoughness` + * and `clearcoatRoughnessMap` properties. This node property allows to overwrite the default + * and define the clearcoat roughness with a node instead. + * + * If you don't want to overwrite the clearcoat roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoatRoughness}. + * + * @type {Node?} + * @default null + */ this.clearcoatRoughnessNode = null; + + /** + * The clearcoat normal of physical materials is by default inferred from the `clearcoatNormalMap` + * property. This node property allows to overwrite the default + * and define the clearcoat normal with a node instead. + * + * If you don't want to overwrite the clearcoat normal but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoatNormal}. + * + * @type {Node?} + * @default null + */ this.clearcoatNormalNode = null; + /** + * The sheen of physical materials is by default inferred from the `sheen`, `sheenColor` + * and `sheenColorMap` properties. This node property allows to overwrite the default + * and define the sheen with a node instead. + * + * If you don't want to overwrite the sheen but modify the existing + * value instead, use {@link module:MaterialNode.materialSheen}. + * + * @type {Node?} + * @default null + */ this.sheenNode = null; + + /** + * The sheen roughness of physical materials is by default inferred from the `sheenRoughness` and + * `sheenRoughnessMap` properties. This node property allows to overwrite the default + * and define the sheen roughness with a node instead. + * + * If you don't want to overwrite the sheen roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialSheenRoughness}. + * + * @type {Node?} + * @default null + */ this.sheenRoughnessNode = null; + /** + * The iridescence of physical materials is by default inferred from the `iridescence` + * property. This node property allows to overwrite the default + * and define the iridescence with a node instead. + * + * If you don't want to overwrite the iridescence but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescence}. + * + * @type {Node?} + * @default null + */ this.iridescenceNode = null; + + /** + * The iridescence IOR of physical materials is by default inferred from the `iridescenceIOR` + * property. This node property allows to overwrite the default + * and define the iridescence IOR with a node instead. + * + * If you don't want to overwrite the iridescence IOR but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescenceIOR}. + * + * @type {Node?} + * @default null + */ this.iridescenceIORNode = null; + + /** + * The iridescence thickness of physical materials is by default inferred from the `iridescenceThicknessRange` + * and `iridescenceThicknessMap` properties. This node property allows to overwrite the default + * and define the iridescence thickness with a node instead. + * + * If you don't want to overwrite the iridescence thickness but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescenceThickness}. + * + * @type {Node?} + * @default null + */ this.iridescenceThicknessNode = null; + /** + * The specular intensity of physical materials is by default inferred from the `specularIntensity` + * and `specularIntensityMap` properties. This node property allows to overwrite the default + * and define the specular intensity with a node instead. + * + * If you don't want to overwrite the specular intensity but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecularIntensity}. + * + * @type {Node?} + * @default null + */ this.specularIntensityNode = null; + + /** + * The specular color of physical materials is by default inferred from the `specularColor` + * and `specularColorMap` properties. This node property allows to overwrite the default + * and define the specular color with a node instead. + * + * If you don't want to overwrite the specular color but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecularColor}. + * + * @type {Node?} + * @default null + */ this.specularColorNode = null; + /** + * The ior of physical materials is by default inferred from the `ior` + * property. This node property allows to overwrite the default + * and define the ior with a node instead. + * + * If you don't want to overwrite the ior but modify the existing + * value instead, use {@link module:MaterialNode.materialIOR}. + * + * @type {Node?} + * @default null + */ this.iorNode = null; + + /** + * The transmission of physical materials is by default inferred from the `transmission` and + * `transmissionMap` properties. This node property allows to overwrite the default + * and define the transmission with a node instead. + * + * If you don't want to overwrite the transmission but modify the existing + * value instead, use {@link module:MaterialNode.materialTransmission}. + * + * @type {Node?} + * @default null + */ this.transmissionNode = null; + + /** + * The thickness of physical materials is by default inferred from the `thickness` and + * `thicknessMap` properties. This node property allows to overwrite the default + * and define the thickness with a node instead. + * + * If you don't want to overwrite the thickness but modify the existing + * value instead, use {@link module:MaterialNode.materialThickness}. + * + * @type {Node?} + * @default null + */ this.thicknessNode = null; + + /** + * The attenuation distance of physical materials is by default inferred from the + * `attenuationDistance` property. This node property allows to overwrite the default + * and define the attenuation distance with a node instead. + * + * If you don't want to overwrite the attenuation distance but modify the existing + * value instead, use {@link module:MaterialNode.materialAttenuationDistance}. + * + * @type {Node?} + * @default null + */ this.attenuationDistanceNode = null; + + /** + * The attenuation color of physical materials is by default inferred from the + * `attenuationColor` property. This node property allows to overwrite the default + * and define the attenuation color with a node instead. + * + * If you don't want to overwrite the attenuation color but modify the existing + * value instead, use {@link module:MaterialNode.materialAttenuationColor}. + * + * @type {Node?} + * @default null + */ this.attenuationColorNode = null; + + /** + * The dispersion of physical materials is by default inferred from the + * `dispersion` property. This node property allows to overwrite the default + * and define the dispersion with a node instead. + * + * If you don't want to overwrite the dispersion but modify the existing + * value instead, use {@link module:MaterialNode.materialDispersion}. + * + * @type {Node?} + * @default null + */ this.dispersionNode = null; + /** + * The anisotropy of physical materials is by default inferred from the + * `anisotropy` property. This node property allows to overwrite the default + * and define the anisotropy with a node instead. + * + * If you don't want to overwrite the anisotropy but modify the existing + * value instead, use {@link module:MaterialNode.materialAnisotropy}. + * + * @type {Node?} + * @default null + */ this.anisotropyNode = null; this.setDefaultValues( _defaultValues$5 ); @@ -15482,42 +20787,81 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Whether the lighting model should use clearcoat or not. + * + * @type {Boolean} + * @default true + */ get useClearcoat() { return this.clearcoat > 0 || this.clearcoatNode !== null; } + /** + * Whether the lighting model should use iridescence or not. + * + * @type {Boolean} + * @default true + */ get useIridescence() { return this.iridescence > 0 || this.iridescenceNode !== null; } + /** + * Whether the lighting model should use sheen or not. + * + * @type {Boolean} + * @default true + */ get useSheen() { return this.sheen > 0 || this.sheenNode !== null; } + /** + * Whether the lighting model should use anisotropy or not. + * + * @type {Boolean} + * @default true + */ get useAnisotropy() { return this.anisotropy > 0 || this.anisotropyNode !== null; } + /** + * Whether the lighting model should use transmission or not. + * + * @type {Boolean} + * @default true + */ get useTransmission() { return this.transmission > 0 || this.transmissionNode !== null; } + /** + * Whether the lighting model should use dispersion or not. + * + * @type {Boolean} + * @default true + */ get useDispersion() { return this.dispersion > 0 || this.dispersionNode !== null; } + /** + * Setups the specular related node variables. + */ setupSpecular() { const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; @@ -15528,12 +20872,22 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhysicalLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhysicalLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion ); } + /** + * Setups the physical specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( builder ) { super.setupVariants( builder ); @@ -15629,6 +20983,11 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Setups the clearcoat normal node. + * + * @return {Node} The clearcoat normal. + */ setupClearcoatNormal() { return this.clearcoatNormalNode ? vec3( this.clearcoatNormalNode ) : materialClearcoatNormal; @@ -15673,16 +21032,49 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } +/** @module MeshSSSNodeMaterial **/ + +/** + * Represents the lighting model for {@link MeshSSSNodeMaterial}. + * + * @augments PhysicalLightingModel + */ class SSSLightingModel extends PhysicalLightingModel { - constructor( useClearcoat, useSheen, useIridescence, useSSS ) { + /** + * Constructs a new physical lighting model. + * + * @param {Boolean} [clearcoat=false] - Whether clearcoat is supported or not. + * @param {Boolean} [sheen=false] - Whether sheen is supported or not. + * @param {Boolean} [iridescence=false] - Whether iridescence is supported or not. + * @param {Boolean} [anisotropy=false] - Whether anisotropy is supported or not. + * @param {Boolean} [transmission=false] - Whether transmission is supported or not. + * @param {Boolean} [dispersion=false] - Whether dispersion is supported or not. + * @param {Boolean} [sss=false] - Whether SSS is supported or not. + */ + constructor( clearcoat = false, sheen = false, iridescence = false, anisotropy = false, transmission = false, dispersion = false, sss = false ) { - super( useClearcoat, useSheen, useIridescence ); + super( clearcoat, sheen, iridescence, anisotropy, transmission, dispersion ); - this.useSSS = useSSS; + /** + * Whether the lighting model should use SSS or not. + * + * @type {Boolean} + * @default false + */ + this.useSSS = sss; } + /** + * Extends the default implementation with a SSS term. + * + * Reference: [Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look]{@link https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/} + * + * @param {Object} input - The input data. + * @param {StackNode} stack - The current stack. + * @param {NodeBuilder} builder - The current node builder. + */ direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { if ( this.useSSS === true ) { @@ -15705,6 +21097,12 @@ class SSSLightingModel extends PhysicalLightingModel { } +/** + * This node material is an experimental extension of {@link MeshPhysicalNodeMaterial} + * that implements a Subsurface scattering (SSS) term. + * + * @augments MeshPhysicalNodeMaterial + */ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { static get type() { @@ -15713,28 +21111,80 @@ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { } + /** + * Constructs a new mesh SSS node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super( parameters ); + /** + * Represents the thickness color. + * + * @type {Node?} + * @default null + */ this.thicknessColorNode = null; + + /** + * Represents the distortion factor. + * + * @type {Node?} + */ this.thicknessDistortionNode = float( 0.1 ); + + /** + * Represents the thickness ambient factor. + * + * @type {Node?} + */ this.thicknessAmbientNode = float( 0.0 ); + + /** + * Represents the thickness attenuation. + * + * @type {Node?} + */ this.thicknessAttenuationNode = float( .1 ); + + /** + * Represents the thickness power. + * + * @type {Node?} + */ this.thicknessPowerNode = float( 2.0 ); + + /** + * Represents the thickness scale. + * + * @type {Node?} + */ this.thicknessScaleNode = float( 10.0 ); } + /** + * Whether the lighting model should use SSS or not. + * + * @type {Boolean} + * @default true + */ get useSSS() { return this.thicknessColorNode !== null; } + /** + * Setups the lighting model. + * + * @return {SSSLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { - return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useSSS ); + return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion, this.useSSS ); } @@ -15817,6 +21267,11 @@ class ToonLightingModel extends LightingModel { const _defaultValues$4 = /*@__PURE__*/ new MeshToonMaterial(); +/** + * Node material version of `MeshToonMaterial`. + * + * @augments NodeMaterial + */ class MeshToonNodeMaterial extends NodeMaterial { static get type() { @@ -15825,12 +21280,30 @@ class MeshToonNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh toon node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshToonNodeMaterial = true; + /** + * Set to `true` because toon materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues$4 ); @@ -15839,6 +21312,11 @@ class MeshToonNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {ToonLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new ToonLightingModel(); @@ -15847,6 +21325,8 @@ class MeshToonNodeMaterial extends NodeMaterial { } +/** @module MatcapUVNode **/ + /** * Can be used to compute texture coordinates for projecting a * matcap onto a mesh. Used by {@link MeshMatcapNodeMaterial}. @@ -15881,10 +21361,21 @@ class MatcapUVNode extends TempNode { } +/** + * TSL function for creating a matcap uv node. + * + * @function + * @returns {MatcapUVNode} + */ const matcapUV = /*@__PURE__*/ nodeImmutable( MatcapUVNode ); const _defaultValues$3 = /*@__PURE__*/ new MeshMatcapMaterial(); +/** + * Node material version of `MeshMatcapMaterial`. + * + * @augments NodeMaterial + */ class MeshMatcapNodeMaterial extends NodeMaterial { static get type() { @@ -15893,12 +21384,22 @@ class MeshMatcapNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh normal node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); - this.lights = false; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshMatcapNodeMaterial = true; this.setDefaultValues( _defaultValues$3 ); @@ -15907,6 +21408,11 @@ class MeshMatcapNodeMaterial extends NodeMaterial { } + /** + * Setups the matcap specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( builder ) { const uv = matcapUV; @@ -15929,42 +21435,7 @@ class MeshMatcapNodeMaterial extends NodeMaterial { } -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 ); - - } - -} +/** @module RotateNode **/ /** * Applies a rotation to the given position node. @@ -16052,10 +21523,24 @@ class RotateNode extends TempNode { } +/** + * TSL function for creating a rotate node. + * + * @function + * @param {Node} positionNode - The position node. + * @param {Node} rotationNode - Represents the rotation that is applied to the position node. Depending + * on whether the position data are 2D or 3D, the rotation is expressed a single float value or an Euler value. + * @returns {RotateNode} + */ const rotate = /*@__PURE__*/ nodeProxy( RotateNode ); -const _defaultValues$1 = /*@__PURE__*/ new SpriteMaterial(); +const _defaultValues$2 = /*@__PURE__*/ new SpriteMaterial(); +/** + * Node material version of `SpriteMaterial`. + * + * @augments NodeMaterial + */ class SpriteNodeMaterial extends NodeMaterial { static get type() { @@ -16064,47 +21549,100 @@ class SpriteNodeMaterial extends NodeMaterial { } + /** + * Constructs a new sprite node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSpriteNodeMaterial = true; - this.lights = false; this._useSizeAttenuation = true; + /** + * This property makes it possible to define the position of the sprite with a + * node. That can be useful when the material is used with instanced rendering + * and node data are defined with an instanced attribute node: + * ```js + * const positionAttribute = new InstancedBufferAttribute( new Float32Array( positions ), 3 ); + * material.positionNode = instancedBufferAttribute( positionAttribute ); + * ``` + * Another possibility is to compute the instanced data with a compute shader: + * ```js + * const positionBuffer = instancedArray( particleCount, 'vec3' ); + * particleMaterial.positionNode = positionBuffer.toAttribute(); + * ``` + * + * @type {Node?} + * @default null + */ this.positionNode = null; + + /** + * The rotation of sprite materials is by default inferred from the `rotation`, + * property. This node property allows to overwrite the default and define + * the rotation with a node instead. + * + * If you don't want to overwrite the rotation but modify the existing + * value instead, use {@link module:MaterialNode.materialRotation}. + * + * @type {Node?} + * @default null + */ this.rotationNode = null; + + /** + * This node property provides an additional way to scale sprites next to + * `Object3D.scale`. The scale transformation based in `Object3D.scale` + * is multiplied with the scale value of this node in the vertex shader. + * + * @type {Node?} + * @default null + */ this.scaleNode = null; - this.setDefaultValues( _defaultValues$1 ); + this.setDefaultValues( _defaultValues$2 ); this.setValues( parameters ); } - setupPosition( { object, camera, context } ) { + /** + * Setups the position node in view space. This method implements + * the sprite specific vertex shader. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in view space. + */ + setupPositionView( builder ) { + + const { object, camera } = builder; const sizeAttenuation = this.sizeAttenuation; - // < VERTEX STAGE > - const { positionNode, rotationNode, scaleNode } = this; - const vertex = positionLocal; - - let mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) ); + const mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) ); let scale = vec2( modelWorldMatrix[ 0 ].xyz.length(), modelWorldMatrix[ 1 ].xyz.length() ); if ( scaleNode !== null ) { - scale = scale.mul( scaleNode ); + scale = scale.mul( float( scaleNode ) ); } - - if ( ! sizeAttenuation ) { + if ( sizeAttenuation === false ) { if ( camera.isPerspectiveCamera ) { @@ -16119,11 +21657,11 @@ class SpriteNodeMaterial extends NodeMaterial { } - let alignedPosition = vertex.xy; + let alignedPosition = positionGeometry.xy; if ( object.center && object.center.isVector2 === true ) { - const center = reference$1( 'center', 'vec2' ); + const center = reference$1( 'center', 'vec2', object ); alignedPosition = alignedPosition.sub( center.sub( 0.5 ) ); @@ -16135,13 +21673,7 @@ class SpriteNodeMaterial extends NodeMaterial { const rotatedPosition = rotate( alignedPosition, rotation ); - mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw ); - - const modelViewProjection = cameraProjectionMatrix.mul( mvPosition ); - - context.vertex = vertex; - - return modelViewProjection; + return vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw ); } @@ -16155,6 +21687,12 @@ class SpriteNodeMaterial extends NodeMaterial { } + /** + * Whether to use size attenuation or not. + * + * @type {Boolean} + * @default true + */ get sizeAttenuation() { return this._useSizeAttenuation; @@ -16174,6 +21712,148 @@ class SpriteNodeMaterial extends NodeMaterial { } +const _defaultValues$1 = /*@__PURE__*/ new PointsMaterial(); + +/** + * Node material version of `PointsMaterial`. + * + * @augments NodeMaterial + */ +class PointsNodeMaterial extends SpriteNodeMaterial { + + static get type() { + + return 'PointsNodeMaterial'; + + } + + /** + * Constructs a new points node material. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters ) { + + super(); + + /** + * This node property provides an additional way to set the point size. + * + * @type {Node?} + * @default null + */ + this.sizeNode = null; + + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isPointsNodeMaterial = true; + + this.setDefaultValues( _defaultValues$1 ); + + this.setValues( parameters ); + + } + + setupPositionView() { + + const { positionNode } = this; + + return modelViewMatrix.mul( vec3( positionNode || positionLocal ) ).xyz; + + } + + setupVertex( builder ) { + + const mvp = super.setupVertex( builder ); + + // skip further processing if the material is not a node material + + if ( builder.material.isNodeMaterial !== true ) { + + return mvp; + + } + + // ndc space + + const { rotationNode, scaleNode, sizeNode } = this; + + const alignedPosition = positionGeometry.xy.toVar(); + const aspect = viewport.z.div( viewport.w ); + + // rotation + + if ( rotationNode && rotationNode.isNode ) { + + const rotation = float( rotationNode ); + + alignedPosition.assign( rotate( alignedPosition, rotation ) ); + + } + + // point size + + let pointSize = sizeNode !== null ? vec2( sizeNode ) : materialPointSize; + + if ( this.sizeAttenuation === true ) { + + pointSize = pointSize.mul( pointSize.div( positionView.z.negate() ) ); + + } + + // scale + + if ( scaleNode && scaleNode.isNode ) { + + pointSize = pointSize.mul( vec2( scaleNode ) ); + + } + + alignedPosition.mulAssign( pointSize.mul( 2 ) ); + + alignedPosition.assign( alignedPosition.div( viewport.z ) ); + alignedPosition.y.assign( alignedPosition.y.mul( aspect ) ); + + // back to clip space + alignedPosition.assign( alignedPosition.mul( mvp.w ) ); + + //clipPos.xy += offset; + mvp.addAssign( vec4( alignedPosition, 0, 0 ) ); + + return mvp; + + } + + /** + * Whether alpha to coverage should be used or not. + * + * @type {Boolean} + * @default true + */ + get alphaToCoverage() { + + return this._useAlphaToCoverage; + + } + + set alphaToCoverage( value ) { + + if ( this._useAlphaToCoverage !== value ) { + + this._useAlphaToCoverage = value; + this.needsUpdate = true; + + } + + } + +} + /** * Represents lighting model for a shadow material. Used in {@link ShadowNodeMaterial}. * @@ -16225,6 +21905,11 @@ class ShadowMaskModel extends LightingModel { const _defaultValues = /*@__PURE__*/ new ShadowMaterial(); +/** + * Node material version of `ShadowMaterial`. + * + * @augments NodeMaterial + */ class ShadowNodeMaterial extends NodeMaterial { static get type() { @@ -16233,12 +21918,31 @@ class ShadowNodeMaterial extends NodeMaterial { } + /** + * Constructs a new shadow node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isShadowNodeMaterial = true; + /** + * Set to `true` because so it's possible to implement + * the shadow mask effect. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues ); @@ -16247,6 +21951,11 @@ class ShadowNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {ShadowMaskModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new ShadowMaskModel(); @@ -16255,6 +21964,8 @@ class ShadowNodeMaterial extends NodeMaterial { } +/** @module Texture3DNode **/ + const normal = Fn( ( { texture, uv } ) => { const epsilon = 0.0001; @@ -16301,7 +22012,11 @@ const normal = Fn( ( { texture, uv } ) => { } ); - +/** + * This type of uniform node represents a 3D texture. + * + * @augments module:TextureNode~TextureNode + */ class Texture3DNode extends TextureNode { static get type() { @@ -16310,40 +22025,108 @@ class Texture3DNode extends TextureNode { } + /** + * Constructs a new 3D texture node. + * + * @param {Data3DTexture} value - The 3D texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + */ constructor( value, uvNode = null, levelNode = null ) { super( value, uvNode, levelNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isTexture3DNode = true; } + /** + * Overwrites the default implementation to return a fixed value `'texture3D'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'texture3D'; } + /** + * Returns a default uv node which is in context of 3D textures a three-dimensional + * uv node. + * + * @return {Node} The default uv node. + */ getDefaultUV() { return vec3( 0.5, 0.5, 0.5 ); } + /** + * Overwritten with an empty implementation since the `updateMatrix` flag is ignored + * for 3D textures. The uv transformation matrix is not applied to 3D textures. + * + * @param {Boolean} value - The update toggle. + */ setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for 3d TextureNode + /** + * Overwrites the default implementation to return the unmodified uv node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to setup. + * @return {Node} The unmodified uv node. + */ setupUV( builder, uvNode ) { + const texture = this.value; + + if ( builder.isFlipY() && ( texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true ) ) { + + if ( this.sampler ) { + + uvNode = uvNode.flipY(); + + } else { + + uvNode = uvNode.setY( int( textureSize( this, this.levelNode ).y ).sub( uvNode.y ).sub( 1 ) ); + + } + + } + return uvNode; } + /** + * Generates the uv code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to generate code for. + * @return {String} The generated code snippet. + */ generateUV( builder, uvNode ) { return uvNode.build( builder, 'vec3' ); } + /** + * TODO. + * + * @param {Node} uvNode - The uv node . + * @return {Node} TODO. + */ normal( uvNode ) { return normal( { texture: this, uv: uvNode } ); @@ -16352,8 +22135,25 @@ class Texture3DNode extends TextureNode { } +/** + * TSL function for creating a 3D texture node. + * + * @function + * @param {Data3DTexture} value - The 3D texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @returns {Texture3DNode} + */ const texture3D = /*@__PURE__*/ nodeProxy( Texture3DNode ); +/** @module VolumeNodeMaterial **/ + +/** + * Node material intended for volume rendering. The volumetric data are + * defined with an instance of {@link Data3DTexture}. + * + * @augments NodeMaterial + */ class VolumeNodeMaterial extends NodeMaterial { static get type() { @@ -16362,18 +22162,85 @@ class VolumeNodeMaterial extends NodeMaterial { } - constructor( params = {} ) { + /** + * Constructs a new volume node material. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters ) { super(); - this.lights = false; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVolumeNodeMaterial = true; + + /** + * The base color of the volume. + * + * @type {Color} + * @default 100 + */ + this.base = new Color( 0xffffff ); + + /** + * A 3D data texture holding the volumetric data. + * + * @type {Data3DTexture?} + * @default null + */ + this.map = null; + + /** + * This number of samples for each ray that hits the mesh's surface + * and travels through the volume. + * + * @type {Number} + * @default 100 + */ + this.steps = 100; + + /** + * Callback for {@link VolumeNodeMaterial#testNode}. + * + * @callback testNodeCallback + * @param {Data3DTexture} map - The 3D texture. + * @param {Node} mapValue - The sampled value inside the volume. + * @param {Node} probe - The probe which is the entry point of the ray on the mesh's surface. + * @param {Node} finalColor - The final color. + */ + + /** + * The volume rendering of this material works by shooting rays + * from the camera position through each fragment of the mesh's + * surface and sample the inner volume in a raymarching fashion + * multiple times. + * + * This node can be used to assign a callback function of type `Fn` + * that will be executed per sample. The callback receives the + * texture, the sampled texture value as well as position on the surface + * where the rays enters the volume. The last parameter is a color + * that allows the callback to determine the final color. + * + * @type {testNodeCallback?} + * @default null + */ this.testNode = null; - this.setValues( params ); + this.setValues( parameters ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const map = texture3D( this.map, null, 0 ); @@ -16450,19 +22317,65 @@ class VolumeNodeMaterial extends NodeMaterial { } +/** + * This module manages the internal animation loop of the renderer. + * + * @private + */ class Animation { + /** + * Constructs a new animation loop management component. + * + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( nodes, info ) { + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; + /** + * A reference to the context from `requestAnimationFrame()` can + * be called (usually `window`). + * + * @type {Window|XRSession} + */ this._context = self; + + /** + * The user-defined animation loop. + * + * @type {Function?} + * @default null + */ this._animationLoop = null; + + /** + * The requestId which is returned from the `requestAnimationFrame()` call. + * Can be used to cancel the stop the animation loop. + * + * @type {Number?} + * @default null + */ this._requestId = null; } + /** + * Starts the internal animation loop. + */ start() { const update = ( time, frame ) => { @@ -16483,6 +22396,9 @@ class Animation { } + /** + * Stops the internal animation loop. + */ stop() { this._context.cancelAnimationFrame( this._requestId ); @@ -16491,18 +22407,31 @@ class Animation { } + /** + * Defines the user-level animation loop. + * + * @param {Function} callback - The animation loop. + */ setAnimationLoop( callback ) { this._animationLoop = callback; } + /** + * Defines the context in which `requestAnimationFrame()` is executed. + * + * @param {Window|XRSession} context - The context to set. + */ setContext( context ) { this._context = context; } + /** + * Frees all internal resources and stops the animation loop. + */ dispose() { this.stop(); @@ -16511,19 +22440,41 @@ class Animation { } +/** + * Data structure for the renderer. It allows defining values + * with chained, hierarchical keys. Keys are meant to be + * objects since the module internally works with Weak Maps + * for performance reasons. + * + * @private + */ class ChainMap { + /** + * Constructs a new Chain Map. + */ constructor() { + /** + * The root Weak Map. + * + * @type {WeakMap} + */ this.weakMap = new WeakMap(); } + /** + * Returns the value for the given array of keys. + * + * @param {Array} keys - List of keys. + * @return {Any} The value. Returns `undefined` if no value was found. + */ get( keys ) { let map = this.weakMap; - for ( let i = 0; i < keys.length; i ++ ) { + for ( let i = 0; i < keys.length - 1; i ++ ) { map = map.get( keys[ i ] ); @@ -16535,11 +22486,18 @@ class ChainMap { } + /** + * Sets the value for the given keys. + * + * @param {Array} keys - List of keys. + * @param {Any} value - The value to set. + * @return {ChainMap} A reference to this Chain Map. + */ set( keys, value ) { let map = this.weakMap; - for ( let i = 0; i < keys.length; i ++ ) { + for ( let i = 0; i < keys.length - 1; i ++ ) { const key = keys[ i ]; @@ -16549,15 +22507,23 @@ class ChainMap { } - return map.set( keys[ keys.length - 1 ], value ); + map.set( keys[ keys.length - 1 ], value ); + + return this; } + /** + * Deletes a value for the given keys. + * + * @param {Array} keys - The keys. + * @return {Boolean} Returns `true` if the value has been removed successfully and `false` if the value has not be found. + */ delete( keys ) { let map = this.weakMap; - for ( let i = 0; i < keys.length; i ++ ) { + for ( let i = 0; i < keys.length - 1; i ++ ) { map = map.get( keys[ i ] ); @@ -16571,7 +22537,7 @@ class ChainMap { } -let _id$8 = 0; +let _id$9 = 0; function getKeys( obj ) { @@ -16607,49 +22573,264 @@ function getKeys( obj ) { } +/** + * A render object is the renderer's representation of single entity that gets drawn + * with a draw command. There is no unique mapping of render objects to 3D objects in the + * scene since render objects also depend from the used material, the current render context + * and the current scene's lighting. + * + * In general, the basic process of the renderer is: + * + * - Analyze the 3D objects in the scene and generate render lists containing render items. + * - Process the render lists by calling one or more render commands for each render item. + * - For each render command, request a render object and perform the draw. + * + * The module provides an interface to get data required for the draw command like the actual + * draw parameters or vertex buffers. It also holds a series of caching related methods since + * creating render objects should only be done when necessary. + * + * @private + */ class RenderObject { + /** + * Constructs a new render object. + * + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Geometries} geometries - Renderer component for managing geometries. + * @param {Renderer} renderer - The renderer. + * @param {Object3D} object - The 3D object. + * @param {Material} material - The 3D object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The lights node. + * @param {RenderContext} renderContext - The render context. + * @param {ClippingContext} clippingContext - The clipping context. + */ constructor( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext ) { + this.id = _id$9 ++; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + * @private + */ this._nodes = nodes; - this._geometries = geometries; - this.id = _id$8 ++; + /** + * Renderer component for managing geometries. + * + * @type {Geometries} + * @private + */ + this._geometries = geometries; + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * The 3D object. + * + * @type {Object3D} + */ this.object = object; + + /** + * The 3D object's material. + * + * @type {Material} + */ this.material = material; + + /** + * The scene the 3D object belongs to. + * + * @type {Scene} + */ this.scene = scene; + + /** + * The camera the 3D object should be rendered with. + * + * @type {Camera} + */ this.camera = camera; + + /** + * The lights node. + * + * @type {LightsNode} + */ this.lightsNode = lightsNode; + + /** + * The render context. + * + * @type {RenderContext} + */ this.context = renderContext; + /** + * The 3D object's geometry. + * + * @type {BufferGeometry} + */ this.geometry = object.geometry; + + /** + * The render object's version. + * + * @type {Number} + */ this.version = material.version; + /** + * The draw range of the geometry. + * + * @type {Object?} + * @default null + */ this.drawRange = null; + /** + * An array holding the buffer attributes + * of the render object. This entails attribute + * definitions on geometry and node level. + * + * @type {Array?} + * @default null + */ this.attributes = null; + + /** + * A reference to a render pipeline the render + * object is processed with. + * + * @type {RenderPipeline} + * @default null + */ this.pipeline = null; + + /** + * Only relevant for objects using + * multiple materials. This represents a group entry + * from the respective `BufferGeometry`. + * + * @type {{start: Number, count: Number}?} + * @default null + */ + this.group = null; + + /** + * An array holding the vertex buffers which can + * be buffer attributes but also interleaved buffers. + * + * @type {Array?} + * @default null + */ this.vertexBuffers = null; + + /** + * The parameters for the draw command. + * + * @type {Object?} + * @default null + */ this.drawParams = null; + /** + * If this render object is used inside a render bundle, + * this property points to the respective bundle group. + * + * @type {BundleGroup?} + * @default null + */ this.bundle = null; + /** + * The clipping context. + * + * @type {ClippingContext} + */ this.clippingContext = clippingContext; + + /** + * The clipping context's cache key. + * + * @type {String} + */ this.clippingContextCacheKey = clippingContext !== null ? clippingContext.cacheKey : ''; + /** + * The initial node cache key. + * + * @type {Number} + */ this.initialNodesCacheKey = this.getDynamicCacheKey(); + + /** + * The initial cache key. + * + * @type {Number} + */ this.initialCacheKey = this.getCacheKey(); + /** + * The node builder state. + * + * @type {NodeBuilderState?} + * @private + * @default null + */ this._nodeBuilderState = null; + + /** + * An array of bindings. + * + * @type {Array?} + * @private + * @default null + */ this._bindings = null; + + /** + * Reference to the node material observer. + * + * @type {NodeMaterialObserver?} + * @private + * @default null + */ this._monitor = null; + /** + * An event listener which is defined by `RenderObjects`. It performs + * clean up tasks when `dispose()` on this render object. + * + * @method + */ this.onDispose = null; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isRenderObject = true; + /** + * An event listener which is executed when `dispose()` is called on + * the render object's material. + * + * @method + */ this.onMaterialDispose = () => { this.dispose(); @@ -16660,12 +22841,23 @@ class RenderObject { } - updateClipping( parent ) { + /** + * Updates the clipping context. + * + * @param {ClippingContext} context - The clipping context to set. + */ + updateClipping( context ) { - this.clippingContext = parent; + this.clippingContext = context; } + /** + * Whether the clipping requires an update or not. + * + * @type {Boolean} + * @readonly + */ get clippingNeedsUpdate() { if ( this.clippingContext === null || this.clippingContext.cacheKey === this.clippingContextCacheKey ) return false; @@ -16676,48 +22868,90 @@ class RenderObject { } + /** + * The number of clipping planes defined in context of hardware clipping. + * + * @type {Number} + * @readonly + */ get hardwareClippingPlanes() { return this.material.hardwareClipping === true ? this.clippingContext.unionClippingCount : 0; } + /** + * Returns the node builder state of this render object. + * + * @return {NodeBuilderState} The node builder state. + */ getNodeBuilderState() { return this._nodeBuilderState || ( this._nodeBuilderState = this._nodes.getForRender( this ) ); } + /** + * Returns the node material observer of this render object. + * + * @return {NodeMaterialObserver} The node material observer. + */ getMonitor() { return this._monitor || ( this._monitor = this.getNodeBuilderState().monitor ); } + /** + * Returns an array of bind groups of this render object. + * + * @return {Array} The bindings. + */ getBindings() { return this._bindings || ( this._bindings = this.getNodeBuilderState().createBindings() ); } + /** + * Returns the index of the render object's geometry. + * + * @return {BufferAttribute?} The index. Returns `null` for non-indexed geometries. + */ getIndex() { return this._geometries.getIndex( this ); } + /** + * Returns the indirect buffer attribute. + * + * @return {BufferAttribute?} The indirect attribute. `null` if no indirect drawing is used. + */ getIndirect() { return this._geometries.getIndirect( this ); } + /** + * Returns an array that acts as a key for identifying the render object in a chain map. + * + * @return {Array} An array with object references. + */ getChainArray() { return [ this.object, this.material, this.context, this.lightsNode ]; } + /** + * This method is used when the geometry of a 3D object has been exchanged and the + * respective render object now requires an update. + * + * @param {BufferGeometry} geometry - The geometry to set. + */ setGeometry( geometry ) { this.geometry = geometry; @@ -16725,6 +22959,12 @@ class RenderObject { } + /** + * Returns the buffer attributes of the render object. The returned array holds + * attribute definitions on geometry and node level. + * + * @return {Array} An array with buffer attributes. + */ getAttributes() { if ( this.attributes !== null ) return this.attributes; @@ -16755,6 +22995,11 @@ class RenderObject { } + /** + * Returns the vertex buffers of the render object. + * + * @return {Array} An array with buffer attribute or interleaved buffers. + */ getVertexBuffers() { if ( this.vertexBuffers === null ) this.getAttributes(); @@ -16763,6 +23008,11 @@ class RenderObject { } + /** + * Returns the draw parameters for the render object. + * + * @return {{vertexCount: Number, firstVertex: Number, instanceCount: Number, firstInstance: Number}} The draw parameters. + */ getDrawParameters() { const { object, material, geometry, group, drawRange } = this; @@ -16829,6 +23079,13 @@ class RenderObject { } + /** + * Returns the render object's geometry cache key. + * + * The geometry cache key is part of the material cache key. + * + * @return {String} The geometry cache key. + */ getGeometryCacheKey() { const { geometry } = this; @@ -16848,6 +23105,26 @@ class RenderObject { } + // structural equality isn't sufficient for morph targets since the + // data are maintained in textures. only if the targets are all equal + // the texture and thus the instance of `MorphNode` can be shared. + + for ( const name of Object.keys( geometry.morphAttributes ).sort() ) { + + const targets = geometry.morphAttributes[ name ]; + + cacheKey += 'morph-' + name + ','; + + for ( let i = 0, l = targets.length; i < l; i ++ ) { + + const attribute = targets[ i ]; + + cacheKey += attribute.id + ','; + + } + + } + if ( geometry.index ) { cacheKey += 'index,'; @@ -16858,6 +23135,13 @@ class RenderObject { } + /** + * Returns the render object's material cache key. + * + * The material cache key is part of the render object cache key. + * + * @return {Number} The material cache key. + */ getMaterialCacheKey() { const { object, material } = this; @@ -16924,12 +23208,6 @@ class RenderObject { } - if ( object.morphTargetInfluences ) { - - cacheKey += object.morphTargetInfluences.length + ','; - - } - if ( object.isBatchedMesh ) { cacheKey += object._matricesTexture.uuid + ','; @@ -16956,23 +23234,58 @@ class RenderObject { } + /** + * Whether the geometry requires an update or not. + * + * @type {Boolean} + * @readonly + */ get needsGeometryUpdate() { return this.geometry.id !== this.object.geometry.id; } + /** + * Whether the render object requires an update or not. + * + * Note: There are two distinct places where render objects are checked for an update. + * + * 1. In `RenderObjects.get()` which is executed when the render object is request. This + * method checks the `needsUpdate` flag and recreates the render object if necessary. + * 2. In `Renderer._renderObjectDirect()` right after getting the render object via + * `RenderObjects.get()`. The render object's NodeMaterialObserver is then used to detect + * a need for a refresh due to material, geometry or object related value changes. + * + * TODO: Investigate if it's possible to merge both steps so there is only a single place + * that performs the 'needsUpdate' check. + * + * @type {Boolean} + * @readonly + */ get needsUpdate() { return /*this.object.static !== true &&*/ ( this.initialNodesCacheKey !== this.getDynamicCacheKey() || this.clippingNeedsUpdate ); } + /** + * Returns the dynamic cache key which represents a key that is computed per draw command. + * + * @return {Number} The cache key. + */ getDynamicCacheKey() { - // Environment Nodes Cache Key + let cacheKey = 0; - let cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); + // `Nodes.getCacheKey()` returns an environment cache key which is not relevant when + // the renderer is inside a shadow pass. + + if ( this.material.isShadowPassMaterial !== true ) { + + cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); + + } if ( this.object.receiveShadow ) { @@ -16984,12 +23297,20 @@ class RenderObject { } + /** + * Returns the render object's cache key. + * + * @return {Number} The cache key. + */ getCacheKey() { return this.getMaterialCacheKey() + this.getDynamicCacheKey(); } + /** + * Frees internal resources. + */ dispose() { this.material.removeEventListener( 'dispose', this.onMaterialDispose ); @@ -17000,40 +23321,109 @@ class RenderObject { } -const chainArray = []; +const _chainKeys$5 = []; +/** + * This module manages the render objects of the renderer. + * + * @private + */ class RenderObjects { + /** + * Constructs a new render object management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Geometries} geometries - Renderer component for managing geometries. + * @param {Pipelines} pipelines - Renderer component for managing pipelines. + * @param {Bindings} bindings - Renderer component for managing bindings. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( renderer, nodes, geometries, pipelines, bindings, info ) { + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; + + /** + * Renderer component for managing geometries. + * + * @type {Geometries} + */ this.geometries = geometries; + + /** + * Renderer component for managing pipelines. + * + * @type {Pipelines} + */ this.pipelines = pipelines; + + /** + * Renderer component for managing bindings. + * + * @type {Bindings} + */ this.bindings = bindings; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; + /** + * A dictionary that manages render contexts in chain maps + * for each pass ID. + * + * @type {Object} + */ this.chainMaps = {}; } + /** + * Returns a render object for the given object and state data. + * + * @param {Object3D} object - The 3D object. + * @param {Material} material - The 3D object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the 3D object should be rendered with. + * @param {LightsNode} lightsNode - The lights node. + * @param {RenderContext} renderContext - The render context. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} passId - An optional ID for identifying the pass. + * @return {RenderObject} The render object. + */ get( object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ) { const chainMap = this.getChainMap( passId ); // reuse chainArray - chainArray[ 0 ] = object; - chainArray[ 1 ] = material; - chainArray[ 2 ] = renderContext; - chainArray[ 3 ] = lightsNode; + _chainKeys$5[ 0 ] = object; + _chainKeys$5[ 1 ] = material; + _chainKeys$5[ 2 ] = renderContext; + _chainKeys$5[ 3 ] = lightsNode; - let renderObject = chainMap.get( chainArray ); + let renderObject = chainMap.get( _chainKeys$5 ); if ( renderObject === undefined ) { renderObject = this.createRenderObject( this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ); - chainMap.set( chainArray, renderObject ); + chainMap.set( _chainKeys$5, renderObject ); } else { @@ -17063,22 +23453,49 @@ class RenderObjects { } + _chainKeys$5.length = 0; + return renderObject; } + /** + * Returns a chain map for the given pass ID. + * + * @param {String} [passId='default'] - The pass ID. + * @return {ChainMap} The chain map. + */ getChainMap( passId = 'default' ) { return this.chainMaps[ passId ] || ( this.chainMaps[ passId ] = new ChainMap() ); } + /** + * Frees internal resources. + */ dispose() { this.chainMaps = {}; } + /** + * Factory method for creating render objects with the given list of parameters. + * + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Geometries} geometries - Renderer component for managing geometries. + * @param {Renderer} renderer - The renderer. + * @param {Object3D} object - The 3D object. + * @param {Material} material - The object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The lights node. + * @param {RenderContext} renderContext - The render context. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} passId - An optional ID for identifying the pass. + * @return {RenderObject} The render object. + */ createRenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ) { const chainMap = this.getChainMap( passId ); @@ -17102,14 +23519,35 @@ class RenderObjects { } +/** + * Data structure for the renderer. It is intended to manage + * data of objects in dictionaries. + * + * @private + */ class DataMap { + /** + * Constructs a new data map. + */ constructor() { + /** + * `DataMap` internally uses a weak map + * to manage its data. + * + * @type {WeakMap} + */ this.data = new WeakMap(); } + /** + * Returns the dictionary for the given object. + * + * @param {Object} object - The object. + * @return {Object} The dictionary. + */ get( object ) { let map = this.data.get( object ); @@ -17125,9 +23563,15 @@ class DataMap { } + /** + * Deletes the dictionary for the given object. + * + * @param {Object} object - The object. + * @return {Object?} The deleted dictionary. + */ delete( object ) { - let map; + let map = null; if ( this.data.has( object ) ) { @@ -17141,12 +23585,21 @@ class DataMap { } + /** + * Returns `true` if the given object has a dictionary defined. + * + * @param {Object} object - The object to test. + * @return {Boolean} Whether a dictionary is defined or not. + */ has( object ) { return this.data.has( object ); } + /** + * Frees internal resources. + */ dispose() { this.data = new WeakMap(); @@ -17171,16 +23624,38 @@ const GPU_CHUNK_BYTES = 16; const BlendColorFactor = 211; const OneMinusBlendColorFactor = 212; +/** + * This renderer module manages geometry attributes. + * + * @private + * @augments DataMap + */ class Attributes extends DataMap { + /** + * Constructs a new attribute management component. + * + * @param {Backend} backend - The renderer's backend. + */ constructor( backend ) { super(); + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; } + /** + * Deletes the data for the given attribute. + * + * @param {BufferAttribute} attribute - The attribute. + * @return {Object} The deleted attribute data. + */ delete( attribute ) { const attributeData = super.delete( attribute ); @@ -17195,6 +23670,13 @@ class Attributes extends DataMap { } + /** + * Updates the given attribute. This method creates attribute buffers + * for new attributes and updates data for existing ones. + * + * @param {BufferAttribute} attribute - The attribute to update. + * @param {Number} type - The attribute type. + */ update( attribute, type ) { const data = this.get( attribute ); @@ -17237,6 +23719,13 @@ class Attributes extends DataMap { } + /** + * Utility method for handling interleaved buffer attributes correctly. + * To process them, their `InterleavedBuffer` is returned. + * + * @param {BufferAttribute} attribute - The attribute. + * @return {BufferAttribute|InterleavedBuffer} + */ _getBufferAttribute( attribute ) { if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; @@ -17247,6 +23736,14 @@ class Attributes extends DataMap { } +/** + * Returns `true` if the given array has values that require an Uint32 array type. + * + * @private + * @function + * @param {Array} array - The array to test. + * @return {Boolean} Whether the given array has values that require an Uint32 array type or not. + */ function arrayNeedsUint32( array ) { // assumes larger values usually on last @@ -17261,12 +23758,28 @@ function arrayNeedsUint32( array ) { } +/** + * Returns the wireframe version for the given geometry. + * + * @private + * @function + * @param {BufferGeometry} geometry - The geometry. + * @return {Number} The version. + */ function getWireframeVersion( geometry ) { return ( geometry.index !== null ) ? geometry.index.version : geometry.attributes.position.version; } +/** + * Returns a wireframe index attribute for the given geometry. + * + * @private + * @function + * @param {BufferGeometry} geometry - The geometry. + * @return {BufferAttribute} The wireframe index attribute. + */ function getWireframeIndex( geometry ) { const indices = []; @@ -17311,21 +23824,61 @@ function getWireframeIndex( geometry ) { } +/** + * This renderer module manages geometries. + * + * @private + * @augments DataMap + */ class Geometries extends DataMap { + /** + * Constructs a new geometry management component. + * + * @param {Attributes} attributes - Renderer component for managing attributes. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( attributes, info ) { super(); + /** + * Renderer component for managing attributes. + * + * @type {Attributes} + */ this.attributes = attributes; - this.info = info; - this.wireframes = new WeakMap(); + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ + this.info = info; + /** + * Weak Map for managing attributes for wireframe rendering. + * + * @type {WeakMap} + */ + this.wireframes = new WeakMap(); + + /** + * This Weak Map is used to make sure buffer attributes are + * updated only once per render call. + * + * @type {WeakMap} + */ this.attributeCall = new WeakMap(); } + /** + * Returns `true` if the given render object has an initialized geometry. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether if the given render object has an initialized geometry or not. + */ has( renderObject ) { const geometry = renderObject.geometry; @@ -17334,6 +23887,11 @@ class Geometries extends DataMap { } + /** + * Prepares the geometry of the given render object for rendering. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { if ( this.has( renderObject ) === false ) this.initGeometry( renderObject ); @@ -17342,6 +23900,11 @@ class Geometries extends DataMap { } + /** + * Initializes the geometry of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ initGeometry( renderObject ) { const geometry = renderObject.geometry; @@ -17386,6 +23949,11 @@ class Geometries extends DataMap { } + /** + * Updates the geometry attributes of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateAttributes( renderObject ) { // attributes @@ -17428,6 +23996,12 @@ class Geometries extends DataMap { } + /** + * Updates the given attribute. + * + * @param {BufferAttribute} attribute - The attribute to update. + * @param {Number} type - The attribute type. + */ updateAttribute( attribute, type ) { const callId = this.info.render.calls; @@ -17464,12 +24038,25 @@ class Geometries extends DataMap { } + /** + * Returns the indirect buffer attribute of the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {BufferAttribute?} The indirect attribute. `null` if no indirect drawing is used. + */ getIndirect( renderObject ) { return renderObject.geometry.indirect; } + /** + * Returns the index of the given render object's geometry. This is implemented + * in a method to return a wireframe index if necessary. + * + * @param {RenderObject} renderObject - The render object. + * @return {BufferAttribute?} The index. Returns `null` for non-indexed geometries. + */ getIndex( renderObject ) { const { geometry, material } = renderObject; @@ -17508,15 +24095,64 @@ class Geometries extends DataMap { } +/** + * This renderer module provides a series of statistical information + * about the GPU memory and the rendering process. Useful for debugging + * and monitoring. + */ class Info { + /** + * Constructs a new info component. + */ constructor() { + /** + * Whether frame related metrics should automatically + * be resetted or not. This property should be set to `false` + * by apps which manage their own animation loop. They must + * then call `renderer.info.reset()` once per frame manually. + * + * @type {Boolean} + * @default true + */ this.autoReset = true; + /** + * The current frame ID. This ID is managed + * by `NodeFrame`. + * + * @type {Number} + * @readonly + * @default 0 + */ this.frame = 0; + + /** + * The number of render calls since the + * app has been started. + * + * @type {Number} + * @readonly + * @default 0 + */ this.calls = 0; + /** + * Render related metrics. + * + * @type {Object} + * @readonly + * @property {Number} calls - The number of render calls since the app has been started. + * @property {Number} frameCalls - The number of render calls of the current frame. + * @property {Number} drawCalls - The number of draw calls of the current frame. + * @property {Number} triangles - The number of rendered triangle primitives of the current frame. + * @property {Number} points - The number of rendered point primitives of the current frame. + * @property {Number} lines - The number of rendered line primitives of the current frame. + * @property {Number} previousFrameCalls - The number of render calls of the previous frame. + * @property {Number} timestamp - The timestamp of the frame when using `renderer.renderAsync()`. + * @property {Number} timestampCalls - The number of render calls using `renderer.renderAsync()`. + */ this.render = { calls: 0, frameCalls: 0, @@ -17529,6 +24165,17 @@ class Info { timestampCalls: 0 }; + /** + * Compute related metrics. + * + * @type {Object} + * @readonly + * @property {Number} calls - The number of compute calls since the app has been started. + * @property {Number} frameCalls - The number of compute calls of the current frame. + * @property {Number} previousFrameCalls - The number of compute calls of the previous frame. + * @property {Number} timestamp - The timestamp of the frame when using `renderer.computeAsync()`. + * @property {Number} timestampCalls - The number of render calls using `renderer.computeAsync()`. + */ this.compute = { calls: 0, frameCalls: 0, @@ -17537,6 +24184,14 @@ class Info { timestampCalls: 0 }; + /** + * Memory related metrics. + * + * @type {Object} + * @readonly + * @property {Number} geometries - The number of active geometries. + * @property {Number} frameCalls - The number of active textures. + */ this.memory = { geometries: 0, textures: 0 @@ -17544,6 +24199,13 @@ class Info { } + /** + * This method should be executed per draw call and updates the corresponding metrics. + * + * @param {Object3D} object - The 3D object that is going to be rendered. + * @param {Number} count - The vertex or index count. + * @param {Number} instanceCount - The instance count. + */ update( object, count, instanceCount ) { this.render.drawCalls ++; @@ -17572,6 +24234,12 @@ class Info { } + /** + * Used by async render methods to updated timestamp metrics. + * + * @param {('render'|'compute')} type - The type of render call. + * @param {Number} time - The duration of the compute/render call in milliseconds. + */ updateTimestamp( type, time ) { if ( this[ type ].timestampCalls === 0 ) { @@ -17595,6 +24263,9 @@ class Info { } + /** + * Resets frame related metrics. + */ reset() { const previousRenderFrameCalls = this.render.frameCalls; @@ -17615,6 +24286,9 @@ class Info { } + /** + * Performs a complete reset of the object. + */ dispose() { this.reset(); @@ -17633,76 +24307,249 @@ class Info { } +/** + * Abstract class for representing pipelines. + * + * @private + * @abstract + */ class Pipeline { + /** + * Constructs a new pipeline. + * + * @param {String} cacheKey - The pipeline's cache key. + */ constructor( cacheKey ) { + /** + * The pipeline's cache key. + * + * @type {String} + */ this.cacheKey = cacheKey; + /** + * How often the pipeline is currently in use. + * + * @type {Number} + * @default 0 + */ this.usedTimes = 0; } } +/** + * Class for representing render pipelines. + * + * @private + * @augments Pipeline + */ class RenderPipeline extends Pipeline { + /** + * Constructs a new render pipeline. + * + * @param {String} cacheKey - The pipeline's cache key. + * @param {ProgrammableStage} vertexProgram - The pipeline's vertex shader. + * @param {ProgrammableStage} fragmentProgram - The pipeline's fragment shader. + */ constructor( cacheKey, vertexProgram, fragmentProgram ) { super( cacheKey ); + /** + * The pipeline's vertex shader. + * + * @type {ProgrammableStage} + */ this.vertexProgram = vertexProgram; + + /** + * The pipeline's fragment shader. + * + * @type {ProgrammableStage} + */ this.fragmentProgram = fragmentProgram; } } +/** + * Class for representing compute pipelines. + * + * @private + * @augments Pipeline + */ class ComputePipeline extends Pipeline { + /** + * Constructs a new render pipeline. + * + * @param {String} cacheKey - The pipeline's cache key. + * @param {ProgrammableStage} computeProgram - The pipeline's compute shader. + */ constructor( cacheKey, computeProgram ) { super( cacheKey ); + /** + * The pipeline's compute shader. + * + * @type {ProgrammableStage} + */ this.computeProgram = computeProgram; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isComputePipeline = true; } } -let _id$7 = 0; +let _id$8 = 0; +/** + * Class for representing programmable stages which are vertex, + * fragment or compute shaders. Unlike fixed-function states (like blending), + * they represent the programmable part of a pipeline. + * + * @private + */ class ProgrammableStage { - constructor( code, type, transforms = null, attributes = null ) { + /** + * Constructs a new programmable stage. + * + * @param {String} code - The shader code. + * @param {('vertex'|'fragment'|'compute')} stage - The type of stage. + * @param {String} name - The name of the shader. + * @param {Array?} [transforms=null] - The transforms (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + * @param {Array?} [attributes=null] - The attributes (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + */ + constructor( code, stage, name, transforms = null, attributes = null ) { - this.id = _id$7 ++; + /** + * The id of the programmable stage. + * + * @type {Number} + */ + this.id = _id$8 ++; + /** + * The shader code. + * + * @type {String} + */ this.code = code; - this.stage = type; + + /** + * The type of stage. + * + * @type {String} + */ + this.stage = stage; + + /** + * The name of the stage. + * This is used for debugging purposes. + * + * @type {String} + */ + this.name = name; + + /** + * The transforms (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + * + * @type {Array?} + */ this.transforms = transforms; + + /** + * The attributes (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + * + * @type {Array?} + */ this.attributes = attributes; + /** + * How often the programmable stage is currently in use. + * + * @type {Number} + * @default 0 + */ this.usedTimes = 0; } } +/** + * This renderer module manages the pipelines of the renderer. + * + * @private + * @augments DataMap + */ class Pipelines extends DataMap { + /** + * Constructs a new pipeline management component. + * + * @param {Backend} backend - The renderer's backend. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + */ constructor( backend, nodes ) { super(); + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; - this.bindings = null; // set by the bindings + /** + * A references to the bindings management component. + * This reference will be set inside the `Bindings` + * constructor. + * + * @type {Bindings?} + * @default null + */ + this.bindings = null; + /** + * Internal cache for maintaining pipelines. + * The key of the map is a cache key, the value the pipeline. + * + * @type {Map} + */ this.caches = new Map(); + + /** + * This dictionary maintains for each shader stage type (vertex, + * fragment and compute) the programmable stage objects which + * represent the actual shader code. + * + * @type {Object} + */ this.programs = { vertex: new Map(), fragment: new Map(), @@ -17711,6 +24558,13 @@ class Pipelines extends DataMap { } + /** + * Returns a compute pipeline for the given compute node. + * + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @return {ComputePipeline} The compute pipeline. + */ getForCompute( computeNode, bindings ) { const { backend } = this; @@ -17740,7 +24594,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.computeProgram ); - stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); + stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', computeNode.name, nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); this.programs.compute.set( nodeBuilderState.computeShader, stageCompute ); backend.createProgram( stageCompute ); @@ -17777,6 +24631,13 @@ class Pipelines extends DataMap { } + /** + * Returns a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array?} [promises=null] - An array of compilation promises which is only relevant in context of `Renderer.compileAsync()`. + * @return {RenderPipeline} The render pipeline. + */ getForRender( renderObject, promises = null ) { const { backend } = this; @@ -17799,6 +24660,8 @@ class Pipelines extends DataMap { const nodeBuilderState = renderObject.getNodeBuilderState(); + const name = renderObject.material ? renderObject.material.name : ''; + // programmable stages let stageVertex = this.programs.vertex.get( nodeBuilderState.vertexShader ); @@ -17807,7 +24670,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.vertexProgram ); - stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex' ); + stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex', name ); this.programs.vertex.set( nodeBuilderState.vertexShader, stageVertex ); backend.createProgram( stageVertex ); @@ -17820,7 +24683,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.fragmentProgram ); - stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment' ); + stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment', name ); this.programs.fragment.set( nodeBuilderState.fragmentShader, stageFragment ); backend.createProgram( stageFragment ); @@ -17861,6 +24724,12 @@ class Pipelines extends DataMap { } + /** + * Deletes the pipeline for the given render object. + * + * @param {RenderObject} object - The render object. + * @return {Object?} The deleted dictionary. + */ delete( object ) { const pipeline = this.get( object ).pipeline; @@ -17897,6 +24766,9 @@ class Pipelines extends DataMap { } + /** + * Frees internal resources. + */ dispose() { super.dispose(); @@ -17910,12 +24782,27 @@ class Pipelines extends DataMap { } + /** + * Updates the pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { this.getForRender( renderObject ); } + /** + * Returns a compute pipeline for the given parameters. + * + * @private + * @param {Node} computeNode - The compute node. + * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. + * @param {String} cacheKey - The cache key. + * @param {Array} bindings - The bindings. + * @return {ComputePipeline} The compute pipeline. + */ _getComputePipeline( computeNode, stageCompute, cacheKey, bindings ) { // check for existing pipeline @@ -17938,6 +24825,17 @@ class Pipelines extends DataMap { } + /** + * Returns a render pipeline for the given parameters. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @param {ProgrammableStage} stageVertex - The programmable stage representing the vertex shader. + * @param {ProgrammableStage} stageFragment - The programmable stage representing the fragment shader. + * @param {String} cacheKey - The cache key. + * @param {Array?} promises - An array of compilation promises which is only relevant in context of `Renderer.compileAsync()`. + * @return {ComputePipeline} The compute pipeline. + */ _getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ) { // check for existing pipeline @@ -17954,6 +24852,10 @@ class Pipelines extends DataMap { renderObject.pipeline = pipeline; + // The `promises` array is `null` by default and only set to an empty array when + // `Renderer.compileAsync()` is used. The next call actually fills the array with + // pending promises that resolve when the render pipelines are ready for rendering. + this.backend.createRenderPipeline( renderObject, promises ); } @@ -17962,24 +24864,53 @@ class Pipelines extends DataMap { } + /** + * Computes a cache key representing a compute pipeline. + * + * @private + * @param {Node} computeNode - The compute node. + * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. + * @return {String} The cache key. + */ _getComputeCacheKey( computeNode, stageCompute ) { return computeNode.id + ',' + stageCompute.id; } + /** + * Computes a cache key representing a render pipeline. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @param {ProgrammableStage} stageVertex - The programmable stage representing the vertex shader. + * @param {ProgrammableStage} stageFragment - The programmable stage representing the fragment shader. + * @return {String} The cache key. + */ _getRenderCacheKey( renderObject, stageVertex, stageFragment ) { return stageVertex.id + ',' + stageFragment.id + ',' + this.backend.getRenderCacheKey( renderObject ); } + /** + * Releases the given pipeline. + * + * @private + * @param {Pipeline} pipeline - The pipeline to release. + */ _releasePipeline( pipeline ) { this.caches.delete( pipeline.cacheKey ); } + /** + * Releases the shader program. + * + * @private + * @param {Object} program - The shader program to release. + */ _releaseProgram( program ) { const code = program.code; @@ -17989,6 +24920,13 @@ class Pipelines extends DataMap { } + /** + * Returns `true` if the compute pipeline for the given compute node requires an update. + * + * @private + * @param {Node} computeNode - The compute node. + * @return {Boolean} Whether the compute pipeline for the given compute node requires an update or not. + */ _needsComputeUpdate( computeNode ) { const data = this.get( computeNode ); @@ -17997,6 +24935,13 @@ class Pipelines extends DataMap { } + /** + * Returns `true` if the render pipeline for the given render object requires an update. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render object for the given render object requires an update or not. + */ _needsRenderUpdate( renderObject ) { const data = this.get( renderObject ); @@ -18007,23 +24952,80 @@ class Pipelines extends DataMap { } +/** + * This renderer module manages the bindings of the renderer. + * + * @private + * @augments DataMap + */ class Bindings extends DataMap { + /** + * Constructs a new bindings management component. + * + * @param {Backend} backend - The renderer's backend. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Textures} textures - Renderer component for managing textures. + * @param {Attributes} attributes - Renderer component for managing attributes. + * @param {Pipelines} pipelines - Renderer component for managing pipelines. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( backend, nodes, textures, attributes, pipelines, info ) { super(); + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * Renderer component for managing textures. + * + * @type {Textures} + */ this.textures = textures; + + /** + * Renderer component for managing pipelines. + * + * @type {Pipelines} + */ this.pipelines = pipelines; + + /** + * Renderer component for managing attributes. + * + * @type {Attributes} + */ this.attributes = attributes; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; this.pipelines.bindings = this; // assign bindings to pipelines } + /** + * Returns the bind groups for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Array} The bind groups. + */ getForRender( renderObject ) { const bindings = renderObject.getBindings(); @@ -18050,6 +25052,12 @@ class Bindings extends DataMap { } + /** + * Returns the bind groups for the given compute node. + * + * @param {Node} computeNode - The compute node. + * @return {Array} The bind groups. + */ getForCompute( computeNode ) { const bindings = this.nodes.getForCompute( computeNode ).bindings; @@ -18074,18 +25082,33 @@ class Bindings extends DataMap { } + /** + * Updates the bindings for the given compute node. + * + * @param {Node} computeNode - The compute node. + */ updateForCompute( computeNode ) { this._updateBindings( this.getForCompute( computeNode ) ); } + /** + * Updates the bindings for the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { this._updateBindings( this.getForRender( renderObject ) ); } + /** + * Updates the given array of bindings. + * + * @param {Array} bindings - The bind groups. + */ _updateBindings( bindings ) { for ( const bindGroup of bindings ) { @@ -18096,6 +25119,11 @@ class Bindings extends DataMap { } + /** + * Initializes the given bind group. + * + * @param {BindGroup} bindGroup - The bind group to initialize. + */ _init( bindGroup ) { for ( const binding of bindGroup.bindings ) { @@ -18117,6 +25145,12 @@ class Bindings extends DataMap { } + /** + * Updates the given bind group. + * + * @param {BindGroup} bindGroup - The bind group to update. + * @param {Array} bindings - The bind groups. + */ _update( bindGroup, bindings ) { const { backend } = this; @@ -18134,7 +25168,10 @@ class Bindings extends DataMap { const updated = this.nodes.updateGroup( binding ); - if ( ! updated ) continue; + // every uniforms group is a uniform buffer. So if no update is required, + // we move one with the next binding. Otherwise the next if block will update the group. + + if ( updated === false ) continue; } @@ -18223,6 +25260,15 @@ class Bindings extends DataMap { } +/** + * Default sorting function for opaque render items. + * + * @private + * @function + * @param {Object} a - The first render item. + * @param {Object} b - The second render item. + * @return {Number} A numeric value which defines the sort order. + */ function painterSortStable( a, b ) { if ( a.groupOrder !== b.groupOrder ) { @@ -18249,6 +25295,15 @@ function painterSortStable( a, b ) { } +/** + * Default sorting function for transparent render items. + * + * @private + * @function + * @param {Object} a - The first render item. + * @param {Object} b - The second render item. + * @return {Number} A numeric value which defines the sort order. + */ function reversePainterSortStable( a, b ) { if ( a.groupOrder !== b.groupOrder ) { @@ -18271,6 +25326,14 @@ function reversePainterSortStable( a, b ) { } +/** + * Returns `true` if the given transparent material requires a double pass. + * + * @private + * @function + * @param {Material} material - The transparent material. + * @return {Boolean} Whether the given material requires a double pass or not. + */ function needsDoublePass( material ) { const hasTransmission = material.transmission > 0 || material.transmissionNode; @@ -18279,28 +25342,120 @@ function needsDoublePass( material ) { } +/** + * When the renderer analyzes the scene at the beginning of a render call, + * it stores 3D object for further processing in render lists. Depending on the + * properties of a 3D objects (like their transformation or material state), the + * objects are maintained in ordered lists for the actual rendering. + * + * Render lists are unique per scene and camera combination. + * + * @private + * @augments Pipeline + */ class RenderList { + /** + * Constructs a render list. + * + * @param {Lighting} lighting - The lighting management component. + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera the scene is rendered with. + */ constructor( lighting, scene, camera ) { + /** + * 3D objects are transformed into render items and stored in this array. + * + * @type {Array} + */ this.renderItems = []; + + /** + * The current render items index. + * + * @type {Number} + * @default 0 + */ this.renderItemsIndex = 0; + /** + * A list with opaque render items. + * + * @type {Array} + */ this.opaque = []; + + /** + * A list with transparent render items which require + * double pass rendering (e.g. transmissive objects). + * + * @type {Array} + */ this.transparentDoublePass = []; + + /** + * A list with transparent render items. + * + * @type {Array} + */ this.transparent = []; + + /** + * A list with transparent render bundle data. + * + * @type {Array} + */ this.bundles = []; + /** + * The render list's lights node. This node is later + * relevant for the actual analytical light nodes which + * compute the scene's lighting in the shader. + * + * @type {LightsNode} + */ this.lightsNode = lighting.getNode( scene, camera ); + + /** + * The scene's lights stored in an array. This array + * is used to setup the lights node. + * + * @type {Array} + */ this.lightsArray = []; + /** + * The scene. + * + * @type {Scene} + */ this.scene = scene; + + /** + * The camera the scene is rendered with. + * + * @type {Camera} + */ this.camera = camera; + /** + * How many objects perform occlusion query tests. + * + * @type {Number} + * @default 0 + */ this.occlusionQueryCount = 0; } + /** + * This method is called right at the beginning of a render call + * before the scene is analyzed. It prepares the internal data + * structures for the upcoming render lists generation. + * + * @return {RenderList} A reference to this render list. + */ begin() { this.renderItemsIndex = 0; @@ -18318,6 +25473,22 @@ class RenderList { } + /** + * Returns a render item for the giving render item state. The state is defined + * by a series of object-related parameters. + * + * The method avoids object creation by holding render items and reusing them in + * subsequent render calls (just with different property values). + * + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The 3D object's geometry. + * @param {Material} material - The 3D object's material. + * @param {Number} groupOrder - The current group order. + * @param {Number} z - Th 3D object's depth value (z value in clip space). + * @param {Number?} group - {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The current clipping context. + * @return {Object} The render item. + */ getNextRenderItem( object, geometry, material, groupOrder, z, group, clippingContext ) { let renderItem = this.renderItems[ this.renderItemsIndex ]; @@ -18358,6 +25529,18 @@ class RenderList { } + /** + * Pushes the given object as a render item to the internal render lists. + * The selected lists depend on the object properties. + * + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The 3D object's geometry. + * @param {Material} material - The 3D object's material. + * @param {Number} groupOrder - The current group order. + * @param {Number} z - Th 3D object's depth value (z value in clip space). + * @param {Number?} group - {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The current clipping context. + */ push( object, geometry, material, groupOrder, z, group, clippingContext ) { const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group, clippingContext ); @@ -18378,6 +25561,18 @@ class RenderList { } + /** + * Inserts the given object as a render item at the start of the internal render lists. + * The selected lists depend on the object properties. + * + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The 3D object's geometry. + * @param {Material} material - The 3D object's material. + * @param {Number} groupOrder - The current group order. + * @param {Number} z - Th 3D object's depth value (z value in clip space). + * @param {Number?} group - {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The current clipping context. + */ unshift( object, geometry, material, groupOrder, z, group, clippingContext ) { const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group, clippingContext ); @@ -18396,18 +25591,34 @@ class RenderList { } + /** + * Pushes render bundle group data into the render list. + * + * @param {Object} group - Bundle group data. + */ pushBundle( group ) { this.bundles.push( group ); } + /** + * Pushes a light into the render list. + * + * @param {Light} light - The light. + */ pushLight( light ) { this.lightsArray.push( light ); } + /** + * Sorts the internal render lists. + * + * @param {Function} customOpaqueSort - A custom sort function for opaque objects. + * @param {Function} customTransparentSort - A custom sort function for transparent objects. + */ sort( customOpaqueSort, customTransparentSort ) { if ( this.opaque.length > 1 ) this.opaque.sort( customOpaqueSort || painterSortStable ); @@ -18416,6 +25627,10 @@ class RenderList { } + /** + * This method performs finalizing tasks right after the render lists + * have been generated. + */ finish() { // update lights @@ -18446,34 +25661,71 @@ class RenderList { } +const _chainKeys$4 = []; + +/** + * This renderer module manages the render lists which are unique + * per scene and camera combination. + * + * @private + */ class RenderLists { + /** + * Constructs a render lists management component. + * + * @param {Lighting} lighting - The lighting management component. + */ constructor( lighting ) { + /** + * The lighting management component. + * + * @type {Lighting} + */ this.lighting = lighting; + /** + * The internal chain map which holds the render lists. + * + * @type {ChainMap} + */ this.lists = new ChainMap(); } + /** + * Returns a render list for the given scene and camera. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera. + * @return {RenderList} The render list. + */ get( scene, camera ) { const lists = this.lists; - const keys = [ scene, camera ]; - let list = lists.get( keys ); + _chainKeys$4[ 0 ] = scene; + _chainKeys$4[ 1 ] = camera; + + let list = lists.get( _chainKeys$4 ); if ( list === undefined ) { list = new RenderList( this.lighting, scene, camera ); - lists.set( keys, list ); + lists.set( _chainKeys$4, list ); } + _chainKeys$4.length = 0; + return list; } + /** + * Frees all internal resources. + */ dispose() { this.lists = new ChainMap(); @@ -18482,44 +25734,235 @@ class RenderLists { } -let id = 0; +let _id$7 = 0; +/** + * Any render or compute command is executed in a specific context that defines + * the state of the renderer and its backend. Typical examples for such context + * data are the current clear values or data from the active framebuffer. This + * module is used to represent these contexts as objects. + * + * @private + */ class RenderContext { + /** + * Constructs a new render context. + */ constructor() { - this.id = id ++; + /** + * The context's ID. + * + * @type {Number} + */ + this.id = _id$7 ++; + /** + * Whether the current active framebuffer has a color attachment. + * + * @type {Boolean} + * @default true + */ this.color = true; + + /** + * Whether the color attachment should be cleared or not. + * + * @type {Boolean} + * @default true + */ this.clearColor = true; + + /** + * The clear color value. + * + * @type {Object} + * @default true + */ this.clearColorValue = { r: 0, g: 0, b: 0, a: 1 }; + /** + * Whether the current active framebuffer has a depth attachment. + * + * @type {Boolean} + * @default true + */ this.depth = true; + + /** + * Whether the depth attachment should be cleared or not. + * + * @type {Boolean} + * @default true + */ this.clearDepth = true; + + /** + * The clear depth value. + * + * @type {Number} + * @default 1 + */ this.clearDepthValue = 1; + /** + * Whether the current active framebuffer has a stencil attachment. + * + * @type {Boolean} + * @default false + */ this.stencil = false; + + /** + * Whether the stencil attachment should be cleared or not. + * + * @type {Boolean} + * @default true + */ this.clearStencil = true; + + /** + * The clear stencil value. + * + * @type {Number} + * @default 1 + */ this.clearStencilValue = 1; + /** + * By default the viewport encloses the entire framebuffer If a smaller + * viewport is manually defined, this property is to `true` by the renderer. + * + * @type {Boolean} + * @default false + */ this.viewport = false; + + /** + * The viewport value. This value is in physical pixels meaning it incorporates + * the renderer's pixel ratio. The viewport property of render targets or + * the renderer is in logical pixels. + * + * @type {Vector4} + */ this.viewportValue = new Vector4(); + /** + * When the scissor test is active and scissor rectangle smaller than the + * framebuffers dimensions, this property is to `true` by the renderer. + * + * @type {Boolean} + * @default false + */ this.scissor = false; + + /** + * The scissor rectangle. + * + * @type {Vector4} + */ this.scissorValue = new Vector4(); + /** + * The active render target. + * + * @type {RenderTarget?} + * @default null + */ + this.renderTarget = null; + + /** + * The textures of the active render target. + * `null` when no render target is set. + * + * @type {Array?} + * @default null + */ this.textures = null; + + /** + * The depth texture of the active render target. + * `null` when no render target is set. + * + * @type {DepthTexture?} + * @default null + */ this.depthTexture = null; + + /** + * The active cube face. + * + * @type {Number} + * @default 0 + */ this.activeCubeFace = 0; + + /** + * The active mipmap level. + * + * @type {Number} + * @default 0 + */ + this.activeMipmapLevel = 0; + + /** + * The number of MSAA samples. This value is always `1` when + * MSAA isn't used. + * + * @type {Number} + * @default 1 + */ this.sampleCount = 1; + /** + * The active render target's width in physical pixels. + * + * @type {Number} + * @default 0 + */ this.width = 0; + + /** + * The active render target's height in physical pixels. + * + * @type {Number} + * @default 0 + */ this.height = 0; + /** + * The occlusion query count. + * + * @type {Number} + * @default 0 + */ + this.occlusionQueryCount = 0; + + /** + * The current clipping context. + * + * @type {ClippingContext?} + * @default null + */ + this.clippingContext = null; + + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isRenderContext = true; } + /** + * Returns the cache key of this render context. + * + * @return {Number} The cache key. + */ getCacheKey() { return getCacheKey( this ); @@ -18528,6 +25971,14 @@ class RenderContext { } +/** + * Computes a cache key for the given render context. This key + * should identify the render target state so it is possible to + * configure the correct attachments in the respective backend. + * + * @param {RenderContext} renderContext - The render context. + * @return {Number} The cache key. + */ function getCacheKey( renderContext ) { const { textures, activeCubeFace } = renderContext; @@ -18544,17 +25995,44 @@ function getCacheKey( renderContext ) { } +const _chainKeys$3 = []; +const _defaultScene = /*@__PURE__*/ new Scene(); +const _defaultCamera = /*@__PURE__*/ new Camera(); + +/** + * This module manages the render contexts of the renderer. + * + * @private + */ class RenderContexts { + /** + * Constructs a new render context management component. + */ constructor() { + /** + * A dictionary that manages render contexts in chain maps + * for each attachment state. + * + * @type {Object} + */ this.chainMaps = {}; } + /** + * Returns a render context for the given scene, camera and render target. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera that is used to render the scene. + * @param {RenderTarget?} [renderTarget=null] - The active render target. + * @return {RenderContext} The render context. + */ get( scene, camera, renderTarget = null ) { - const chainKey = [ scene, camera ]; + _chainKeys$3[ 0 ] = scene; + _chainKeys$3[ 1 ] = camera; let attachmentState; @@ -18571,30 +26049,54 @@ class RenderContexts { } - const chainMap = this.getChainMap( attachmentState ); + const chainMap = this._getChainMap( attachmentState ); - let renderState = chainMap.get( chainKey ); + let renderState = chainMap.get( _chainKeys$3 ); if ( renderState === undefined ) { renderState = new RenderContext(); - chainMap.set( chainKey, renderState ); + chainMap.set( _chainKeys$3, renderState ); } + _chainKeys$3.length = 0; + if ( renderTarget !== null ) renderState.sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; return renderState; } - getChainMap( attachmentState ) { + /** + * Returns a render context intended for clear operations. + * + * @param {RenderTarget?} [renderTarget=null] - The active render target. + * @return {RenderContext} The render context. + */ + getForClear( renderTarget = null ) { + + return this.get( _defaultScene, _defaultCamera, renderTarget ); + + } + + /** + * Returns a chain map for the given attachment state. + * + * @private + * @param {String} attachmentState - The attachment state. + * @return {ChainMap} The chain map. + */ + _getChainMap( attachmentState ) { return this.chainMaps[ attachmentState ] || ( this.chainMaps[ attachmentState ] = new ChainMap() ); } + /** + * Frees internal resources. + */ dispose() { this.chainMaps = {}; @@ -18605,18 +26107,55 @@ class RenderContexts { const _size$3 = /*@__PURE__*/ new Vector3(); +/** + * This module manages the textures of the renderer. + * + * @private + * @augments DataMap + */ class Textures extends DataMap { + /** + * Constructs a new texture management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Backend} backend - The renderer's backend. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( renderer, backend, info ) { super(); + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * The backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; } + /** + * Updates the given render target. Based on the given render target configuration, + * it updates the texture states representing the attachments of the framebuffer. + * + * @param {RenderTarget} renderTarget - The render target to update. + * @param {Number} [activeMipmapLevel=0] - The active mipmap level. + */ updateRenderTarget( renderTarget, activeMipmapLevel = 0 ) { const renderTargetData = this.get( renderTarget ); @@ -18738,6 +26277,14 @@ class Textures extends DataMap { } + /** + * Updates the given texture. Depending on the texture state, this method + * triggers the upload of texture data to the GPU memory. If the texture data are + * not yet ready for the upload, it uses default texture data for as a placeholder. + * + * @param {Texture} texture - The texture to update. + * @param {Object} [options={}] - The options. + */ updateTexture( texture, options = {} ) { const textureData = this.get( texture ); @@ -18891,6 +26438,18 @@ class Textures extends DataMap { } + /** + * Computes the size of the given texture and writes the result + * into the target vector. This vector is also returned by the + * method. + * + * If no texture data are available for the compute yet, the method + * returns default size values. + * + * @param {Texture} texture - The texture to compute the size for. + * @param {Vector3} target - The target vector. + * @return {Vector3} The target vector. + */ getSize( texture, target = _size$3 ) { let image = texture.images ? texture.images[ 0 ] : texture.image; @@ -18913,6 +26472,14 @@ class Textures extends DataMap { } + /** + * Computes the number of mipmap levels for the given texture. + * + * @param {Texture} texture - The texture. + * @param {Number} width - The texture's width. + * @param {Number} height - The texture's height. + * @return {Number} The number of mipmap levels. + */ getMipLevels( texture, width, height ) { let mipLevelCount; @@ -18939,12 +26506,24 @@ class Textures extends DataMap { } + /** + * Returns `true` if the given texture requires mipmaps. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether mipmaps are required or not. + */ needsMipmaps( texture ) { return this.isEnvironmentTexture( texture ) || texture.isCompressedTexture === true || texture.generateMipmaps; } + /** + * Returns `true` if the given texture is an environment map. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the given texture is an environment map or not. + */ isEnvironmentTexture( texture ) { const mapping = texture.mapping; @@ -18953,6 +26532,12 @@ class Textures extends DataMap { } + /** + * Frees internal resource when the given texture isn't + * required anymore. + * + * @param {Texture} texture - The texture to destroy. + */ _destroyTexture( texture ) { this.backend.destroySampler( texture ); @@ -18964,8 +26549,24 @@ class Textures extends DataMap { } +/** + * A four-component version of {@link Color} which is internally + * used by the renderer to represents clear color with alpha as + * one object. + * + * @private + * @augments Color + */ class Color4 extends Color { + /** + * Constructs a new four-component color. + * + * @param {Number|String} r - The red value. + * @param {Number} g - The green value. + * @param {Number} b - The blue value. + * @param {Number} [a=1] - The alpha value. + */ constructor( r, g, b, a = 1 ) { super( r, g, b ); @@ -18974,6 +26575,17 @@ class Color4 extends Color { } + /** + * Overwrites the default to honor alpha. + * You can also passed a single THREE.Color, hex or + * string argument to this method. + * + * @param {Number|String} r - The red value. + * @param {Number} g - The green value. + * @param {Number} b - The blue value. + * @param {Number} [a=1] - The alpha value. + * @return {Color4} A reference to this object. + */ set( r, g, b, a = 1 ) { this.a = a; @@ -18982,6 +26594,12 @@ class Color4 extends Color { } + /** + * Overwrites the default to honor alpha. + * + * @param {Color4} color - The color to copy. + * @return {Color4} A reference to this object. + */ copy( color ) { if ( color.a !== undefined ) this.a = color.a; @@ -18990,6 +26608,11 @@ class Color4 extends Color { } + /** + * Overwrites the default to honor alpha. + * + * @return {Color4} The cloned color. + */ clone() { return new this.constructor( this.r, this.g, this.b, this.a ); @@ -18998,6 +26621,8 @@ class Color4 extends Color { } +/** @module ParameterNode **/ + /** * Special version of {@link PropertyNode} which is used for parameters. * @@ -19047,13 +26672,17 @@ class ParameterNode extends PropertyNode { } /** + * TSL function for creating a parameter node. * - * @param {string} type - * @param {string?} [name=null] - * @returns {ShaderNodeObject} + * @function + * @param {String} type - The type of the node. + * @param {String?} name - The name of the parameter in the shader. + * @returns {ParameterNode} */ const parameter = ( type, name ) => nodeObject( new ParameterNode( type, name ) ); +/** @module StackNode **/ + /** * Stack is a helper for Nodes that need to produce stack-based code instead of continuous flow. * They are usually needed in cases like `If`, `Else`. @@ -19207,8 +26836,15 @@ class StackNode extends Node { } - // + // deprecated + /** + * @function + * @deprecated since r168. Use {@link StackNode#Else} instead. + * + * @param {...any} params + * @returns {StackNode} + */ else( ...params ) { // @deprecated, r168 console.warn( 'TSL.StackNode: .else() has been renamed to .Else().' ); @@ -19216,6 +26852,12 @@ class StackNode extends Node { } + /** + * @deprecated since r168. Use {@link StackNode#ElseIf} instead. + * + * @param {...any} params + * @returns {StackNode} + */ elseif( ...params ) { // @deprecated, r168 console.warn( 'TSL.StackNode: .elseif() has been renamed to .ElseIf().' ); @@ -19225,8 +26867,17 @@ class StackNode extends Node { } +/** + * TSL function for creating a stack node. + * + * @function + * @param {StackNode?} [parent=null] - The parent stack node. + * @returns {StackNode} + */ const stack = /*@__PURE__*/ nodeProxy( StackNode ); +/** @module OutputStructNode **/ + /** * This node can be used to define multiple outputs in a shader programs. * @@ -19306,8 +26957,17 @@ class OutputStructNode extends Node { } +/** + * TSL function for creating an output struct node. + * + * @function + * @param {...Node} members - A parameter list of nodes. + * @returns {OutputStructNode} + */ const outputStruct = /*@__PURE__*/ nodeProxy( OutputStructNode ); +/** @module MRTNode **/ + /** * Returns the MRT texture index for the given name. * @@ -19444,6 +27104,13 @@ class MRTNode extends OutputStructNode { } +/** + * TSL function for creating a MRT node. + * + * @function + * @param {Object} outputNodes - The MRT outputs. + * @returns {MRTNode} + */ const mrt = /*@__PURE__*/ nodeProxy( MRTNode ); /** @module Hash **/ @@ -19476,7 +27143,7 @@ const hash = /*@__PURE__*/ Fn( ( [ seed ] ) => { * * @method * @param {Node} x - The value to remap. - * @param {Node} k - Allows to control the remapping functions shape by rising the parabolar to a power `k`. + * @param {Node} k - Allows to control the remapping functions shape by rising the parabola to a power `k`. * @return {Node} The remapped value. */ const parabola = ( x, k ) => pow( mul( 4.0, x.mul( sub( 1.0, x ) ) ), k ); @@ -19488,7 +27155,7 @@ const parabola = ( x, k ) => pow( mul( 4.0, x.mul( sub( 1.0, x ) ) ), k ); * * @method * @param {Node} x - The value to remap. - * @param {Node} k - `k=1` is the identity curve,`k<1` produces the classic `gain()` shape, and `k>1` produces "s" shaped curces. + * @param {Node} k - `k=1` is the identity curve,`k<1` produces the classic `gain()` shape, and `k>1` produces "s" shaped curves. * @return {Node} The remapped value. */ 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 ) ); @@ -19500,8 +27167,8 @@ const gain = ( x, k ) => x.lessThan( 0.5 ) ? parabola( x.mul( 2.0 ), k ).div( 2. * * @method * @param {Node} x - The value to remap. - * @param {Node} a - First control paramter. - * @param {Node} b - Second control paramter. + * @param {Node} a - First control parameter. + * @param {Node} b - Second control parameter. * @return {Node} The remapped value. */ const pcurve = ( x, a, b ) => pow( div( pow( x, a ), add( pow( x, a ), pow( sub( 1.0, x ), b ) ) ), 1.0 / a ); @@ -19546,8 +27213,6 @@ const tri3 = /*@__PURE__*/ Fn( ( [ p ] ) => { ] } ); -/** @module Hash **/ - /** * Generates a noise value from the given position, speed and time parameters. * @@ -19590,6 +27255,8 @@ const triNoise3D = /*@__PURE__*/ Fn( ( [ position, speed, time ] ) => { ] } ); +/** @module FunctionOverloadingNode **/ + /** * This class allows to define multiple overloaded versions * of the same function. Depending on the parameters of the function @@ -19609,7 +27276,7 @@ class FunctionOverloadingNode extends Node { * Constructs a new function overloading node. * * @param {Array} functionNodes - Array of `Fn` function definitions. - * @param {...Node} parametersNodes - A list of paramater nodes. + * @param {...Node} parametersNodes - A list of parameter nodes. */ constructor( functionNodes = [], ...parametersNodes ) { @@ -19623,9 +27290,9 @@ class FunctionOverloadingNode extends Node { this.functionNodes = functionNodes; /** - * A list of paramater nodes. + * A list of parameter nodes. * - * @type {Array} + * @type {Array} */ this.parametersNodes = parametersNodes; @@ -19728,6 +27395,13 @@ class FunctionOverloadingNode extends Node { const overloadingBaseFn = /*@__PURE__*/ nodeProxy( FunctionOverloadingNode ); +/** + * TSL function for creating a function overloading node. + * + * @function + * @param {Array} functionNodes - Array of `Fn` function definitions. + * @returns {FunctionOverloadingNode} + */ const overloadingFn = ( functionNodes ) => ( ...params ) => overloadingBaseFn( functionNodes, ...params ); /** @module Timer **/ @@ -19755,6 +27429,13 @@ const frameId = /*@__PURE__*/ uniform( 0, 'uint' ).setGroup( renderGroup ).onRen // Deprecated +/** + * @function + * @deprecated since r170. Use {@link time} instead. + * + * @param {Number} [timeScale=1] - The time scale. + * @returns {UniformNode} + */ const timerLocal = ( timeScale = 1 ) => { // @deprecated, r170 console.warn( 'TSL: timerLocal() is deprecated. Use "time" instead.' ); @@ -19762,6 +27443,13 @@ const timerLocal = ( timeScale = 1 ) => { // @deprecated, r170 }; +/** + * @function + * @deprecated since r170. Use {@link time} instead. + * + * @param {Number} [timeScale=1] - The time scale. + * @returns {UniformNode} + */ const timerGlobal = ( timeScale = 1 ) => { // @deprecated, r170 console.warn( 'TSL: timerGlobal() is deprecated. Use "time" instead.' ); @@ -19769,6 +27457,13 @@ const timerGlobal = ( timeScale = 1 ) => { // @deprecated, r170 }; +/** + * @function + * @deprecated since r170. Use {@link deltaTime} instead. + * + * @param {Number} [timeScale=1] - The time scale. + * @returns {UniformNode} + */ const timerDelta = ( timeScale = 1 ) => { // @deprecated, r170 console.warn( 'TSL: timerDelta() is deprecated. Use "deltaTime" instead.' ); @@ -19915,7 +27610,7 @@ const billboarding = /*@__PURE__*/ Fn( ( { position = null, horizontal = true, v /** * A special version of a screen uv function that involves a depth comparison - * when computing the final uvs. The function mitigates visual erros when + * when computing the final uvs. The function mitigates visual errors when * using viewport texture nodes for refraction purposes. Without this function * objects in front of a refractive surface might appear on the refractive surface * which is incorrect. @@ -19934,6 +27629,8 @@ const viewportSafeUV = /*@__PURE__*/ Fn( ( [ uv = null ] ) => { } ); +/** @module SpriteSheetUVNode **/ + /** * Can be used to compute texture coordinates for animated sprite sheets. * @@ -20007,8 +27704,19 @@ class SpriteSheetUVNode extends Node { } +/** + * TSL function for creating a sprite sheet uv node. + * + * @function + * @param {Node} countNode - The node that defines the number of sprites in the x and y direction (e.g 6x6). + * @param {Node} [uvNode=uv()] - The uv node. + * @param {Node} [frameNode=float()] - The node that defines the current frame/sprite. + * @returns {SpriteSheetUVNode} + */ const spritesheetUV = /*@__PURE__*/ nodeProxy( SpriteSheetUVNode ); +/** @module TriplanarTexturesNode **/ + /** * Can be used for triplanar texture mapping. * @@ -20119,9 +27827,36 @@ class TriplanarTexturesNode extends Node { } +/** + * TSL function for creating a triplanar textures node. + * + * @function + * @param {Node} textureXNode - First texture node. + * @param {Node?} [textureYNode=null] - Second texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [textureZNode=null] - Third texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [scaleNode=float(1)] - The scale node. + * @param {Node?} [positionNode=positionLocal] - Vertex positions in local space. + * @param {Node?} [normalNode=normalLocal] - Normals in local space. + * @returns {TriplanarTexturesNode} + */ const triplanarTextures = /*@__PURE__*/ nodeProxy( TriplanarTexturesNode ); + +/** + * TSL function for creating a triplanar textures node. + * + * @function + * @param {Node} textureXNode - First texture node. + * @param {Node?} [textureYNode=null] - Second texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [textureZNode=null] - Third texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [scaleNode=float(1)] - The scale node. + * @param {Node?} [positionNode=positionLocal] - Vertex positions in local space. + * @param {Node?} [normalNode=normalLocal] - Normals in local space. + * @returns {TriplanarTexturesNode} + */ const triplanarTexture = ( ...params ) => triplanarTextures( ...params ); +/** @module ReflectorNode **/ + const _reflectorPlane = new Plane(); const _normal = new Vector3(); const _reflectorWorldPosition = new Vector3(); @@ -20154,7 +27889,7 @@ let _inReflector = false; * plane.add( groundReflector.target ); * ``` * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class ReflectorNode extends TextureNode { @@ -20173,6 +27908,8 @@ class ReflectorNode extends TextureNode { * @param {Boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not. * @param {Boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not. * @param {Boolean} [parameters.depth=false] - Whether depth data should be generated or not. + * @param {TextureNode} [parameters.defaultTexture] - The default texture node. + * @param {ReflectorBaseNode} [parameters.reflector] - The reflector base node. */ constructor( parameters = {} ) { @@ -20182,7 +27919,7 @@ class ReflectorNode extends TextureNode { * A reference to the internal reflector base node which holds the actual implementation. * * @private - * @type {Node?} + * @type {ReflectorBaseNode?} * @default null */ this._reflectorBaseNode = parameters.reflector || new ReflectorBaseNode( this, parameters ); @@ -20203,7 +27940,7 @@ class ReflectorNode extends TextureNode { /** * A reference to the internal reflector node. * - * @type {Node} + * @type {ReflectorBaseNode} */ get reflector() { @@ -20272,7 +28009,7 @@ class ReflectorNode extends TextureNode { /** * Holds the actual implementation of the reflector. * - * TOOD: Explain why `ReflectorBaseNode`. Originally the entire logic was implemented + * TODO: Explain why `ReflectorBaseNode`. Originally the entire logic was implemented * in `ReflectorNode`, see #29619. * * @private @@ -20368,7 +28105,7 @@ class ReflectorBaseNode extends Node { /** * Weak map for managing virtual cameras. * - * @type {WeakMap} + * @type {WeakMap} */ this.virtualCameras = new WeakMap(); @@ -20467,7 +28204,7 @@ class ReflectorBaseNode extends Node { updateBefore( frame ) { - if ( this.bounces === false && _inReflector ) return; + if ( this.bounces === false && _inReflector ) return false; _inReflector = true; @@ -20564,14 +28301,17 @@ class ReflectorBaseNode extends Node { const currentRenderTarget = renderer.getRenderTarget(); const currentMRT = renderer.getMRT(); + const currentAutoClear = renderer.autoClear; renderer.setMRT( null ); renderer.setRenderTarget( renderTarget ); + renderer.autoClear = true; renderer.render( scene, virtualCamera ); renderer.setMRT( currentMRT ); renderer.setRenderTarget( currentRenderTarget ); + renderer.autoClear = currentAutoClear; material.visible = true; @@ -20581,16 +28321,39 @@ class ReflectorBaseNode extends Node { } +/** + * TSL function for creating a reflector node. + * + * @function + * @param {Object} [parameters={}] - An object holding configuration parameters. + * @param {Object3D} [parameters.target=new Object3D()] - The 3D object the reflector is linked to. + * @param {Number} [parameters.resolution=1] - The resolution scale. + * @param {Boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not. + * @param {Boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not. + * @param {Boolean} [parameters.depth=false] - Whether depth data should be generated or not. + * @param {TextureNode} [parameters.defaultTexture] - The default texture node. + * @param {ReflectorBaseNode} [parameters.reflector] - The reflector base node. + * @returns {ReflectorNode} + */ 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 - +/** + * The purpose of this special geometry is to fill the entire viewport with a single triangle. + * + * Reference: {@link https://github.com/mrdoob/three.js/pull/21358} + * + * @private + * @augments BufferGeometry + */ class QuadGeometry extends BufferGeometry { + /** + * Constructs a new quad geometry. + * + * @param {Boolean} [flipY=false] - Whether the uv coordinates should be flipped along the vertical axis or not. + */ constructor( flipY = false ) { super(); @@ -20606,24 +28369,64 @@ class QuadGeometry extends BufferGeometry { const _geometry = /*@__PURE__*/ new QuadGeometry(); + +/** + * This module is a helper for passes which need to render a full + * screen effect which is quite common in context of post processing. + * + * The intended usage is to reuse a single quad mesh for rendering + * subsequent passes by just reassigning the `material` reference. + * + * @augments BufferGeometry + */ class QuadMesh extends Mesh { + /** + * Constructs a new quad mesh. + * + * @param {Material?} [material=null] - The material to render the quad mesh with. + */ constructor( material = null ) { super( _geometry, material ); + /** + * The camera to render the quad mesh with. + * + * @type {OrthographicCamera} + * @readonly + */ this.camera = _camera; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isQuadMesh = true; } - renderAsync( renderer ) { + /** + * Async version of `render()`. + * + * @async + * @param {Renderer} renderer - The renderer. + * @return {Promise} A Promise that resolves when the render has been finished. + */ + async renderAsync( renderer ) { return renderer.renderAsync( this, _camera ); } + /** + * Renders the quad mesh + * + * @param {Renderer} renderer - The renderer. + */ render( renderer ) { renderer.render( this, _camera ); @@ -20632,6 +28435,8 @@ class QuadMesh extends Mesh { } +/** @module RTTNode **/ + const _size$1 = /*@__PURE__*/ new Vector2(); /** @@ -20640,7 +28445,7 @@ const _size$1 = /*@__PURE__*/ new Vector2(); * texture input for their effects. With the helper function `convertToTexture()` which is based * on this module, the node system can automatically ensure texture input if required. * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class RTTNode extends TextureNode { @@ -20849,8 +28654,28 @@ class RTTNode extends TextureNode { } +/** + * TSL function for creating a RTT node. + * + * @function + * @param {Node} node - The node to render a texture with. + * @param {Number?} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. + * @param {Number?} [height=null] - The height of the internal render target. + * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @returns {RTTNode} + */ const rtt = ( node, ...params ) => nodeObject( new RTTNode( nodeObject( node ), ...params ) ); +/** + * TSL function for converting nodes to textures nodes. + * + * @function + * @param {Node} node - The node to render a texture with. + * @param {Number?} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. + * @param {Number?} [height=null] - The height of the internal render target. + * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @returns {RTTNode} + */ const convertToTexture = ( node, ...params ) => { if ( node.isTextureNode ) return node; @@ -20950,34 +28775,94 @@ const getNormalFromDepth = /*@__PURE__*/ Fn( ( [ uv, depthTexture, projectionMat } ); +/** + * This special type of instanced buffer attribute is intended for compute shaders. + * In earlier three.js versions it was only possible to update attribute data + * on the CPU via JavaScript and then upload the data to the GPU. With the + * new material system and renderer it is now possible to use compute shaders + * to compute the data for an attribute more efficiently on the GPU. + * + * The idea is to create an instance of this class and provide it as an input + * to {@link module:StorageBufferNode}. + * + * Note: This type of buffer attribute can only be used with `WebGPURenderer`. + * + * @augments InstancedBufferAttribute + */ class StorageInstancedBufferAttribute extends InstancedBufferAttribute { - constructor( array, itemSize, typeClass = Float32Array ) { + /** + * Constructs a new storage instanced buffer attribute. + * + * @param {Number|TypedArray} count - The item count. It is also valid to pass a typed array as an argument. + * The subsequent parameters are then obsolete. + * @param {Number} itemSize - The item size. + * @param {TypedArray.constructor} [typeClass=Float32Array] - A typed array constructor. + */ + constructor( count, itemSize, typeClass = Float32Array ) { - if ( ArrayBuffer.isView( array ) === false ) array = new typeClass( array * itemSize ); + const array = ArrayBuffer.isView( count ) ? count : new typeClass( count * itemSize ); super( array, itemSize ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageInstancedBufferAttribute = true; } } +/** + * This special type of buffer attribute is intended for compute shaders. + * In earlier three.js versions it was only possible to update attribute data + * on the CPU via JavaScript and then upload the data to the GPU. With the + * new material system and renderer it is now possible to use compute shaders + * to compute the data for an attribute more efficiently on the GPU. + * + * The idea is to create an instance of this class and provide it as an input + * to {@link module:StorageBufferNode}. + * + * Note: This type of buffer attribute can only be used with `WebGPURenderer`. + * + * @augments BufferAttribute + */ class StorageBufferAttribute extends BufferAttribute { - constructor( array, itemSize, typeClass = Float32Array ) { + /** + * Constructs a new storage buffer attribute. + * + * @param {Number|TypedArray} count - The item count. It is also valid to pass a typed array as an argument. + * The subsequent parameters are then obsolete. + * @param {Number} itemSize - The item size. + * @param {TypedArray.constructor} [typeClass=Float32Array] - A typed array constructor. + */ + constructor( count, itemSize, typeClass = Float32Array ) { - if ( ArrayBuffer.isView( array ) === false ) array = new typeClass( array * itemSize ); + const array = ArrayBuffer.isView( count ) ? count : new typeClass( count * itemSize ); super( array, itemSize ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageBufferAttribute = true; } } +/** @module StorageArrayElementNode **/ + /** * This class enables element access on instances of {@link StorageBufferNode}. * In most cases, it is indirectly used when accessing elements with the @@ -21092,8 +28977,49 @@ class StorageArrayElementNode extends ArrayElementNode { } +/** + * TSL function for creating a storage element node. + * + * @function + * @param {StorageBufferNode} storageBufferNode - The storage buffer node. + * @param {Node} indexNode - The index node that defines the element access. + * @returns {StorageArrayElementNode} + */ const storageElement = /*@__PURE__*/ nodeProxy( StorageArrayElementNode ); +/** @module StorageBufferNode **/ + +/** + * This node is used in context of compute shaders and allows to define a + * storage buffer for data. A typical workflow is to create instances of + * this node with the convenience functions `attributeArray()` or `instancedArray()`, + * setup up a compute shader that writes into the buffers and then convert + * the storage buffers to attribute nodes for rendering. + * + * ```js + * const positionBuffer = instancedArray( particleCount, 'vec3' ); // the storage buffer node + * + * const computeInit = Fn( () => { // the compute shader + * + * const position = positionBuffer.element( instanceIndex ); + * + * // compute position data + * + * position.x = 1; + * position.y = 1; + * position.z = 1; + * + * } )().compute( particleCount ); + * + * const particleMaterial = new THREE.SpriteNodeMaterial(); + * particleMaterial.positionNode = positionBuffer.toAttribute(); + * + * renderer.computeAsync( computeInit ); + * + * ``` + * + * @augments BufferNode + */ class StorageBufferNode extends BufferNode { static get type() { @@ -21102,6 +29028,13 @@ class StorageBufferNode extends BufferNode { } + /** + * Constructs a new storage buffer node. + * + * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. + * @param {String?} [bufferType=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [bufferCount=0] - The buffer count. + */ constructor( value, bufferType = null, bufferCount = 0 ) { if ( bufferType === null && ( value.isStorageBufferAttribute || value.isStorageInstancedBufferAttribute ) ) { @@ -21113,22 +29046,67 @@ class StorageBufferNode extends BufferNode { super( value, bufferType, bufferCount ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageBufferNode = true; + /** + * The access type of the texture node. + * + * @type {String} + * @default 'readWrite' + */ this.access = NodeAccess.READ_WRITE; + + /** + * Whether the node is atomic or not. + * + * @type {Boolean} + * @default false + */ this.isAtomic = false; - this.isPBO = false; - this.bufferCount = bufferCount; + /** + * Whether the node represents a PBO or not. + * Only relevant for WebGL. + * + * @type {Boolean} + * @default false + */ + this.isPBO = false; + /** + * A reference to the internal buffer attribute node. + * + * @type {BufferAttributeNode?} + * @default null + */ this._attribute = null; + + /** + * A reference to the internal varying node. + * + * @type {VaryingNode?} + * @default null + */ this._varying = null; + /** + * `StorageBufferNode` sets this property to `true` by default. + * + * @type {Boolean} + * @default true + */ 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 + // TODO: 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; @@ -21137,6 +29115,13 @@ class StorageBufferNode extends BufferNode { } + /** + * This method is overwritten since the buffer data might be shared + * and thus the hash should be shared as well. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The hash. + */ getHash( builder ) { if ( this.bufferCount === 0 ) { @@ -21161,18 +29146,36 @@ class StorageBufferNode extends BufferNode { } + /** + * Overwrites the default implementation to return a fixed value `'indirectStorageBuffer'` or `'storageBuffer'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return this.value.isIndirectStorageBufferAttribute ? 'indirectStorageBuffer' : 'storageBuffer'; } + /** + * Enables element access with the given index node. + * + * @param {IndexNode} indexNode - The index node. + * @return {StorageArrayElementNode} A node representing the element access. + */ element( indexNode ) { return storageElement( this, indexNode ); } + /** + * Defines whether this node is a PBO or not. Only relevant for WebGL. + * + * @param {Boolean} value - The value so set. + * @return {StorageBufferNode} A reference to this node. + */ setPBO( value ) { this.isPBO = value; @@ -21181,12 +29184,23 @@ class StorageBufferNode extends BufferNode { } + /** + * Returns the `isPBO` value. + * + * @return {Boolean} Whether the node represents a PBO or not. + */ getPBO() { return this.isPBO; } + /** + * Defines the node access. + * + * @param {String} value - The node access. + * @return {StorageBufferNode} A reference to this node. + */ setAccess( value ) { this.access = value; @@ -21195,12 +29209,23 @@ class StorageBufferNode extends BufferNode { } + /** + * Convenience method for configuring a read-only node access. + * + * @return {StorageBufferNode} A reference to this node. + */ toReadOnly() { return this.setAccess( NodeAccess.READ_ONLY ); } + /** + * Defines whether the node is atomic or not. + * + * @param {Boolean} value - The atomic flag. + * @return {StorageBufferNode} A reference to this node. + */ setAtomic( value ) { this.isAtomic = value; @@ -21209,12 +29234,22 @@ class StorageBufferNode extends BufferNode { } + /** + * Convenience method for making this node atomic. + * + * @return {StorageBufferNode} A reference to this node. + */ toAtomic() { return this.setAtomic( true ); } + /** + * Returns attribute data for this storage buffer node. + * + * @return {{attribute: BufferAttributeNode, varying: VaryingNode}} The attribute data. + */ getAttributeData() { if ( this._attribute === null ) { @@ -21231,6 +29266,13 @@ class StorageBufferNode extends BufferNode { } + /** + * This method is overwritten since the node type from the availability of storage buffers + * and the attribute data. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( builder.isAvailable( 'storageBuffer' ) || builder.isAvailable( 'indirectStorageBuffer' ) ) { @@ -21245,6 +29287,12 @@ class StorageBufferNode extends BufferNode { } + /** + * Generates the code snippet of the storage buffer node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( builder ) { if ( builder.isAvailable( 'storageBuffer' ) || builder.isAvailable( 'indirectStorageBuffer' ) ) { @@ -21265,8 +29313,26 @@ class StorageBufferNode extends BufferNode { } -const storage = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ) ); +/** + * TSL function for creating a storage buffer node. + * + * @function + * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [count=0] - The buffer count. + * @returns {StorageBufferNode} + */ +const storage = ( value, type = null, count = 0 ) => nodeObject( new StorageBufferNode( value, type, count ) ); +/** + * @function + * @deprecated since r171. Use `storage().setPBO( true )` instead. + * + * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. + * @param {String?} type - The buffer type (e.g. `'vec3'`). + * @param {Number} count - The buffer count. + * @returns {StorageBufferNode} + */ const storageObject = ( value, type, count ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.' ); @@ -21275,29 +29341,55 @@ const storageObject = ( value, type, count ) => { // @deprecated, r171 }; +/** @module Arrays **/ + +/** + * TSL function for creating a storage buffer node with a configured `StorageBufferAttribute`. + * + * @function + * @param {Number} count - The data count. + * @param {String} [type='float'] - The data type. + * @returns {StorageBufferNode} + */ const attributeArray = ( count, type = 'float' ) => { const itemSize = getLengthFromType( type ); + const typedArray = getTypedArrayFromType( type ); - const buffer = new StorageBufferAttribute( count, itemSize ); + const buffer = new StorageBufferAttribute( count, itemSize, typedArray ); const node = storage( buffer, type, count ); return node; }; - +/** + * TSL function for creating a storage buffer node with a configured `StorageInstancedBufferAttribute`. + * + * @function + * @param {Number} count - The data count. + * @param {String} [type='float'] - The data type. + * @returns {StorageBufferNode} + */ const instancedArray = ( count, type = 'float' ) => { const itemSize = getLengthFromType( type ); + const typedArray = getTypedArrayFromType( type ); - const buffer = new StorageInstancedBufferAttribute( count, itemSize ); + const buffer = new StorageInstancedBufferAttribute( count, itemSize, typedArray ); const node = storage( buffer, type, count ); return node; }; +/** @module VertexColorNode **/ + +/** + * An attribute node for representing vertex colors. + * + * @augments module:AttributeNode~AttributeNode + */ class VertexColorNode extends AttributeNode { static get type() { @@ -21306,16 +29398,40 @@ class VertexColorNode extends AttributeNode { } + /** + * Constructs a new vertex color node. + * + * @param {Number} [index=0] - The attribute index. + */ constructor( index = 0 ) { super( null, 'vec4' ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVertexColorNode = true; + /** + * The attribute index to enable more than one sets of vertex colors. + * + * @type {Number} + * @default 0 + */ this.index = index; } + /** + * Overwrites the default implementation by honoring the attribute index. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The attribute name. + */ getAttributeName( /*builder*/ ) { const index = this.index; @@ -21364,8 +29480,26 @@ class VertexColorNode extends AttributeNode { } -const vertexColor = ( ...params ) => nodeObject( new VertexColorNode( ...params ) ); +/** + * TSL function for creating a reference node. + * + * @function + * @param {Number} index - The attribute index. + * @returns {VertexColorNode} + */ +const vertexColor = ( index ) => nodeObject( new VertexColorNode( index ) ); +/** @module PointUVNode **/ + +/** + * A node for representing the uv coordinates of points. + * + * Can only be used with a WebGL backend. In WebGPU, point + * primitives always have the size of one pixel and can thus + * can't be used as sprite-like objects that display textures. + * + * @augments Node + */ class PointUVNode extends Node { static get type() { @@ -21374,10 +29508,20 @@ class PointUVNode extends Node { } + /** + * Constructs a new point uv node. + */ constructor() { super( 'vec2' ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isPointUVNode = true; } @@ -21390,11 +29534,28 @@ class PointUVNode extends Node { } +/** + * TSL object that represents the uv coordinates of points. + * + * @type {PointUVNode} + */ const pointUV = /*@__PURE__*/ nodeImmutable( PointUVNode ); const _e1 = /*@__PURE__*/ new Euler(); const _m1 = /*@__PURE__*/ new Matrix4(); +/** @module SceneNode **/ + +/** + * This module allows access to a collection of scene properties. The following predefined TSL objects + * are available for easier use: + * + * - `backgroundBlurriness`: A node that represents the scene's background blurriness. + * - `backgroundIntensity`: A node that represents the scene's background intensity. + * - `backgroundRotation`: A node that represents the scene's background rotation. + * + * @augments Node + */ class SceneNode extends Node { static get type() { @@ -21403,15 +29564,40 @@ class SceneNode extends Node { } + /** + * Constructs a new scene node. + * + * @param {('backgroundBlurriness'|'backgroundIntensity'|'backgroundRotation')} scope - The scope defines the type of scene property that is accessed. + * @param {Scene?} [scene=null] - A reference to the scene. + */ constructor( scope = SceneNode.BACKGROUND_BLURRINESS, scene = null ) { super(); + /** + * The scope defines the type of scene property that is accessed. + * + * @type {('backgroundBlurriness'|'backgroundIntensity'|'backgroundRotation')} + */ this.scope = scope; + + /** + * A reference to the scene that is going to be accessed. + * + * @type {Scene?} + * @default null + */ this.scene = scene; } + /** + * Depending on the scope, the method returns a different type of node that represents + * the respective scene property. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The output node. + */ setup( builder ) { const scope = this.scope; @@ -21468,10 +29654,60 @@ SceneNode.BACKGROUND_BLURRINESS = 'backgroundBlurriness'; SceneNode.BACKGROUND_INTENSITY = 'backgroundIntensity'; SceneNode.BACKGROUND_ROTATION = 'backgroundRotation'; +/** + * TSL object that represents the scene's background blurriness. + * + * @type {SceneNode} + */ const backgroundBlurriness = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_BLURRINESS ); + +/** + * TSL object that represents the scene's background intensity. + * + * @type {SceneNode} + */ const backgroundIntensity = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_INTENSITY ); + +/** + * TSL object that represents the scene's background rotation. + * + * @type {SceneNode} + */ const backgroundRotation = /*@__PURE__*/ nodeImmutable( SceneNode, SceneNode.BACKGROUND_ROTATION ); +/** @module StorageTextureNode **/ + +/** + * This special version of a texture node can be used to + * write data into a storage texture with a compute shader. + * + * ```js + * const storageTexture = new THREE.StorageTexture( width, height ); + * + * const computeTexture = Fn( ( { storageTexture } ) => { + * + * const posX = instanceIndex.modInt( width ); + * const posY = instanceIndex.div( width ); + * const indexUV = uvec2( posX, posY ); + * + * // generate RGB values + * + * const r = 1; + * const g = 1; + * const b = 1; + * + * textureStore( storageTexture, indexUV, vec4( r, g, b, 1 ) ).toWriteOnly(); + * + * } ); + * + * const computeNode = computeTexture( { storageTexture } ).compute( width * height ); + * renderer.computeAsync( computeNode ); + * ``` + * + * This node can only be used with a WebGPU backend. + * + * @augments module:TextureNode~TextureNode + */ class StorageTextureNode extends TextureNode { static get type() { @@ -21480,18 +29716,50 @@ class StorageTextureNode extends TextureNode { } + /** + * Constructs a new storage texture node. + * + * @param {StorageTexture} value - The storage texture. + * @param {Node} uvNode - The uv node. + * @param {Node?} [storeNode=null] - The value node that should be stored in the texture. + */ constructor( value, uvNode, storeNode = null ) { super( value, uvNode ); + /** + * The value node that should be stored in the texture. + * + * @type {Node?} + * @default null + */ this.storeNode = storeNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageTextureNode = true; + /** + * The access type of the texture node. + * + * @type {String} + * @default 'writeOnly' + */ this.access = NodeAccess.WRITE_ONLY; } + /** + * Overwrites the default implementation to return a fixed value `'storageTexture'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'storageTexture'; @@ -21507,6 +29775,12 @@ class StorageTextureNode extends TextureNode { } + /** + * Defines the node access. + * + * @param {String} value - The node access. + * @return {StorageTextureNode} A reference to this node. + */ setAccess( value ) { this.access = value; @@ -21514,6 +29788,14 @@ class StorageTextureNode extends TextureNode { } + /** + * Generates the code snippet of the stroge node. If no `storeNode` + * is defined, the texture node is generated as normal texture. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output. + * @return {String} The generated code snippet. + */ generate( builder, output ) { let snippet; @@ -21532,24 +29814,44 @@ class StorageTextureNode extends TextureNode { } + /** + * Convenience method for configuring a read/write node access. + * + * @return {StorageTextureNode} A reference to this node. + */ toReadWrite() { return this.setAccess( NodeAccess.READ_WRITE ); } + /** + * Convenience method for configuring a read-only node access. + * + * @return {StorageTextureNode} A reference to this node. + */ toReadOnly() { return this.setAccess( NodeAccess.READ_ONLY ); } + /** + * Convenience method for configuring a write-only node access. + * + * @return {StorageTextureNode} A reference to this node. + */ toWriteOnly() { return this.setAccess( NodeAccess.WRITE_ONLY ); } + /** + * Generates the code snippet of the storage texture node. + * + * @param {NodeBuilder} builder - The current node builder. + */ generateStore( builder ) { const properties = builder.getNodeProperties( this ); @@ -21568,8 +29870,27 @@ class StorageTextureNode extends TextureNode { } +/** + * TSL function for creating a storage texture node. + * + * @function + * @param {StorageTexture} value - The storage texture. + * @param {Node} uvNode - The uv node. + * @param {Node?} [storeNode=null] - The value node that should be stored in the texture. + * @returns {StorageTextureNode} + */ const storageTexture = /*@__PURE__*/ nodeProxy( StorageTextureNode ); + +/** + * TODO: Explain difference to `storageTexture()`. + * + * @function + * @param {StorageTexture} value - The storage texture. + * @param {Node} uvNode - The uv node. + * @param {Node?} [storeNode=null] - The value node that should be stored in the texture. + * @returns {StorageTextureNode} + */ const textureStore = ( value, uvNode, storeNode ) => { const node = storageTexture( value, uvNode, storeNode ); @@ -21580,6 +29901,22 @@ const textureStore = ( value, uvNode, storeNode ) => { }; +/** @module UserDataNode **/ + +/** + * A special type of reference node that allows to link values in + * `userData` fields to node objects. + * ```js + * sprite.userData.rotation = 1; // stores individual rotation per sprite + * + * const material = new THREE.SpriteNodeMaterial(); + * material.rotationNode = userData( 'rotation', 'float' ); + * ``` + * Since `UserDataNode` is extended from {@link module:ReferenceNode~ReferenceNode}, the node value + * will automatically be updated when the `rotation` user data field changes. + * + * @augments module:ReferenceNode~ReferenceNode + */ class UserDataNode extends ReferenceNode { static get type() { @@ -21588,14 +29925,35 @@ class UserDataNode extends ReferenceNode { } + /** + * Constructs a new user data node. + * + * @param {String} property - The property name that should be referenced by the node. + * @param {String} inputType - The node data type of the reference. + * @param {Object?} [userData=null] - A reference to the `userData` object. If not provided, the `userData` property of the 3D object that uses the node material is evaluated. + */ constructor( property, inputType, userData = null ) { super( property, inputType, userData ); + /** + * A reference to the `userData` object. If not provided, the `userData` + * property of the 3D object that uses the node material is evaluated. + * + * @type {Object?} + * @default null + */ this.userData = userData; } + /** + * Overwritten to make sure {@link module:ReferenceNode~ReferenceNode#reference} points to the correct + * `userData` field. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state to evaluate. + * @return {Object} A reference to the `userData` field. + */ updateReference( state ) { this.reference = this.userData !== null ? this.userData : state.object.userData; @@ -21606,10 +29964,31 @@ class UserDataNode extends ReferenceNode { } +/** + * TSL function for creating a user data node. + * + * @function + * @param {String} name - The property name that should be referenced by the node. + * @param {String} inputType - The node data type of the reference. + * @param {Object?} userData - A reference to the `userData` object. If not provided, the `userData` property of the 3D object that uses the node material is evaluated. + * @returns {UserDataNode} + */ const userData = ( name, inputType, userData ) => nodeObject( new UserDataNode( name, inputType, userData ) ); const _objectData = new WeakMap(); +/** @module VelocityNode **/ + +/** + * A node for representing motion or velocity vectors. Foundation + * for advanced post processing effects like motion blur or TRAA. + * + * The node keeps track of the model, view and projection matrices + * of the previous frame and uses them to compute offsets in NDC space. + * These offsets represent the final velocity. + * + * @augments TempNode + */ class VelocityNode extends TempNode { static get type() { @@ -21618,27 +29997,81 @@ class VelocityNode extends TempNode { } + /** + * Constructs a new vertex color node. + * + * @param {Number} [index=0] - The attribute index. + */ constructor() { super( 'vec2' ); + /** + * The current projection matrix. + * + * @type {Matrix4?} + * @default null + */ this.projectionMatrix = null; + /** + * Overwritten since velocity nodes are updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; + + /** + * Overwritten since velocity nodes save data after the update. + * + * @type {String} + * @default 'object' + */ this.updateAfterType = NodeUpdateType.OBJECT; + /** + * Uniform node representing the previous model matrix in world space. + * + * @type {UniformNode} + * @default null + */ this.previousModelWorldMatrix = uniform( new Matrix4() ); + + /** + * Uniform node representing the previous projection matrix. + * + * @type {UniformNode} + * @default null + */ this.previousProjectionMatrix = uniform( new Matrix4() ).setGroup( renderGroup ); + + /** + * Uniform node representing the previous view matrix. + * + * @type {UniformNode} + * @default null + */ this.previousCameraViewMatrix = uniform( new Matrix4() ); } + /** + * Sets the given projection matrix. + * + * @param {Matrix4} projectionMatrix - The projection matrix to set. + */ setProjectionMatrix( projectionMatrix ) { this.projectionMatrix = projectionMatrix; } + /** + * Updates velocity specific uniforms. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( { frameId, camera, object } ) { const previousModelMatrix = getPreviousMatrix( object ); @@ -21681,12 +30114,23 @@ class VelocityNode extends TempNode { } + /** + * Overwritten to updated velocity specific uniforms. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ updateAfter( { object } ) { getPreviousMatrix( object ).copy( object.matrixWorld ); } + /** + * Implements the velocity computation based on the previous and current vertex data. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {Node} The motion vector. + */ setup( /*builder*/ ) { const projectionMatrix = ( this.projectionMatrix === null ) ? cameraProjectionMatrix : uniform( this.projectionMatrix ); @@ -21738,6 +30182,11 @@ function getPreviousMatrix( object, index = 0 ) { } +/** + * TSL object that represents the velocity of a render pass. + * + * @type {VelocityNode} + */ const velocity = /*@__PURE__*/ nodeImmutable( VelocityNode ); const blendBurn = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { @@ -21809,6 +30258,13 @@ const blendColor = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { // deprecated +/** + * @function + * @deprecated since r171. Use {@link blendBurn} instead. + * + * @param {...any} params + * @returns {Function} + */ const burn = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "burn" has been renamed. Use "blendBurn" instead.' ); @@ -21816,6 +30272,13 @@ const burn = ( ...params ) => { // @deprecated, r171 }; +/** + * @function + * @deprecated since r171. Use {@link blendDodge} instead. + * + * @param {...any} params + * @returns {Function} + */ const dodge = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "dodge" has been renamed. Use "blendDodge" instead.' ); @@ -21823,6 +30286,13 @@ const dodge = ( ...params ) => { // @deprecated, r171 }; +/** + * @function + * @deprecated since r171. Use {@link blendScreen} instead. + * + * @param {...any} params + * @returns {Function} + */ const screen = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "screen" has been renamed. Use "blendScreen" instead.' ); @@ -21830,6 +30300,13 @@ const screen = ( ...params ) => { // @deprecated, r171 }; +/** + * @function + * @deprecated since r171. Use {@link blendOverlay} instead. + * + * @param {...any} params + * @returns {Function} + */ const overlay = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "overlay" has been renamed. Use "blendOverlay" instead.' ); @@ -21968,6 +30445,8 @@ const cdl = /*@__PURE__*/ Fn( ( [ } ); +/** @module PosterizeNode **/ + /** * Represents a posterize effect which reduces the number of colors * in an image, resulting in a more blocky and stylized appearance. @@ -22018,15 +30497,24 @@ class PosterizeNode extends TempNode { } +/** + * TSL function for creating a posterize node. + * + * @function + * @param {Node} sourceNode - The input color. + * @param {Node} stepsNode - Controls the intensity of the posterization effect. A lower number results in a more blocky appearance. + * @returns {PosterizeNode} + */ const posterize = /*@__PURE__*/ nodeProxy( PosterizeNode ); +/** @module PassNode **/ + const _size = /*@__PURE__*/ new Vector2(); /** * Represents the texture of a pass node. * - * @augments TextureNode - * @private + * @augments module:TextureNode~TextureNode */ class PassTextureNode extends TextureNode { @@ -22077,8 +30565,7 @@ class PassTextureNode extends TextureNode { * An extension of `PassTextureNode` which allows to manage more than one * internal texture. Relevant for the `getPreviousTexture()` related API. * - * @augments PassTextureNode - * @private + * @augments module:PassTextureNode~PassTextureNode */ class PassMultipleTextureNode extends PassTextureNode { @@ -22196,7 +30683,7 @@ class PassNode extends TempNode { /** * A reference to the camera. * - * @type {camera} + * @type {Camera} */ this.camera = camera; @@ -22252,7 +30739,7 @@ class PassNode extends TempNode { * A dictionary holding the internal result textures. * * @private - * @type {Object} + * @type {Object} */ this._textures = { output: renderTarget.texture, @@ -22263,7 +30750,7 @@ class PassNode extends TempNode { * A dictionary holding the internal texture nodes. * * @private - * @type {Object} + * @type {Object} */ this._textureNodes = {}; @@ -22288,7 +30775,7 @@ class PassNode extends TempNode { * Used for computing velocity/motion vectors. * * @private - * @type {Object} + * @type {Object} */ this._previousTextures = {}; @@ -22297,7 +30784,7 @@ class PassNode extends TempNode { * Used for computing velocity/motion vectors. * * @private - * @type {Object} + * @type {Object} */ this._previousTextureNodes = {}; @@ -22646,9 +31133,39 @@ class PassNode extends TempNode { PassNode.COLOR = 'color'; PassNode.DEPTH = 'depth'; +/** + * TSL function for creating a pass node. + * + * @function + * @param {Scene} scene - A reference to the scene. + * @param {Camera} camera - A reference to the camera. + * @param {Object} options - Options for the internal render target. + * @returns {PassNode} + */ const pass = ( scene, camera, options ) => nodeObject( new PassNode( PassNode.COLOR, scene, camera, options ) ); + +/** + * TSL function for creating a pass texture node. + * + * @function + * @param {PassNode} pass - The pass node. + * @param {Texture} texture - The output texture. + * @returns {PassTextureNode} + */ const passTexture = ( pass, texture ) => nodeObject( new PassTextureNode( pass, texture ) ); -const depthPass = ( scene, camera ) => nodeObject( new PassNode( PassNode.DEPTH, scene, camera ) ); + +/** + * TSL function for creating a depth pass node. + * + * @function + * @param {Scene} scene - A reference to the scene. + * @param {Camera} camera - A reference to the camera. + * @param {Object} options - Options for the internal render target. + * @returns {PassNode} + */ +const depthPass = ( scene, camera, options ) => nodeObject( new PassNode( PassNode.DEPTH, scene, camera, options ) ); + +/** @module ToonOutlinePassNode **/ /** * Represents a render pass for producing a toon outline effect on compatible objects. @@ -22783,7 +31300,7 @@ class ToonOutlinePassNode extends PassNode { } /** - * For the given toon material, this method returns a correspoding + * For the given toon material, this method returns a corresponding * outline material. * * @private @@ -22808,6 +31325,17 @@ class ToonOutlinePassNode extends PassNode { } +/** + * TSL function for creating a toon outline pass node. + * + * @function + * @param {Scene} scene - A reference to the scene. + * @param {Camera} camera - A reference to the camera. + * @param {Color} color - Defines the outline's color. + * @param {Number} [thickness=0.003] - Defines the outline's thickness. + * @param {Number} [alpha=1] - Defines the outline's alpha. + * @returns {ToonOutlinePassNode} + */ 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 ) ) ); /** @module ToneMappingFunctions **/ @@ -23044,6 +31572,8 @@ const neutralToneMapping = /*@__PURE__*/ Fn( ( [ color, exposure ] ) => { ] } ); +/** @module CodeNode **/ + /** * This class represents native code sections. It is the base * class for modules like {@link FunctionNode} which allows to implement @@ -23179,10 +31709,45 @@ class CodeNode extends Node { } +/** + * TSL function for creating a code node. + * + * @function + * @param {String} [code=''] - The native code. + * @param {Array} [includes=[]] - An array of includes. + * @param {('js'|'wgsl'|'glsl')} [language=''] - The used language. + * @returns {CodeNode} + */ const code = /*@__PURE__*/ nodeProxy( CodeNode ); +/** + * TSL function for creating a JS code node. + * + * @function + * @param {String} src - The native code. + * @param {Array} includes - An array of includes. + * @returns {CodeNode} + */ const js = ( src, includes ) => code( src, includes, 'js' ); + +/** + * TSL function for creating a WGSL code node. + * + * @function + * @param {String} src - The native code. + * @param {Array} includes - An array of includes. + * @returns {CodeNode} + */ const wgsl = ( src, includes ) => code( src, includes, 'wgsl' ); + +/** + * TSL function for creating a GLSL code node. + * + * @function + * @param {String} src - The native code. + * @param {Array} includes - An array of includes. + * @returns {CodeNode} + */ const glsl = ( src, includes ) => code( src, includes, 'glsl' ); /** @@ -23341,6 +31906,13 @@ const nativeFn = ( code, includes = [], language = '' ) => { const glslFn = ( code, includes ) => nativeFn( code, includes, 'glsl' ); const wgslFn = ( code, includes ) => nativeFn( code, includes, 'wgsl' ); +/** @module ScriptableValueNode **/ + +/** + * `ScriptableNode` uses this class to manage script inputs and outputs. + * + * @augments Node + */ class ScriptableValueNode extends Node { static get type() { @@ -23349,22 +31921,72 @@ class ScriptableValueNode extends Node { } + /** + * Constructs a new scriptable node. + * + * @param {Any} [value=null] - The value. + */ constructor( value = null ) { super(); + /** + * A reference to the value. + * + * @private + * @default null + */ this._value = value; + + /** + * Depending on the type of `_value`, this property might cache parsed data. + * + * @private + * @default null + */ this._cache = null; + /** + * If this node represents an input, this property represents the input type. + * + * @type {String?} + * @default null + */ this.inputType = null; + + /** + * If this node represents an output, this property represents the output type. + * + * @type {String?} + * @default null + */ this.outputType = null; + /** + * An event dispatcher for managing events. + * + * @type {EventDispatcher} + */ this.events = new EventDispatcher(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isScriptableValueNode = true; } + /** + * Whether this node represents an output or not. + * + * @type {Boolean} + * @readonly + * @default true + */ get isScriptableOutputNode() { return this.outputType !== null; @@ -23391,18 +32013,32 @@ class ScriptableValueNode extends Node { } + /** + * The node's value. + * + * @type {Any} + */ get value() { return this._value; } + /** + * Dispatches the `refresh` event. + */ refresh() { this.events.dispatchEvent( { type: 'refresh' } ); } + /** + * The `value` property usually represents a node or even binary data in form of array buffers. + * In this case, this method tries to return the actual value behind the complex type. + * + * @return {Any} The value. + */ getValue() { const value = this.value; @@ -23430,6 +32066,12 @@ class ScriptableValueNode extends Node { } + /** + * Overwritten since the node type is inferred from the value. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { return this.value && this.value.isNode ? this.value.getNodeType( builder ) : 'float'; @@ -23502,8 +32144,22 @@ class ScriptableValueNode extends Node { } +/** + * TSL function for creating a scriptable value node. + * + * @function + * @param {Any} [value=null] - The value. + * @returns {ScriptableValueNode} + */ const scriptableValue = /*@__PURE__*/ nodeProxy( ScriptableValueNode ); +/** @module ScriptableNode **/ + +/** + * A Map-like data structure for managing resources of scriptable nodes. + * + * @augments Map + */ class Resources extends Map { get( key, callback = null, ...params ) { @@ -23559,8 +32215,49 @@ class Parameters { } +/** + * Defines the resources (e.g. namespaces) of scriptable nodes. + * + * @type {Resources} + */ const ScriptableNodeResources = new Resources(); +/** + * This type of node allows to implement nodes with custom scripts. The script + * section is represented as an instance of `CodeNode` written with JavaScript. + * The script itself must adhere to a specific structure. + * + * - main(): Executed once by default and every time `node.needsUpdate` is set. + * - layout: The layout object defines the script's interface (inputs and outputs). + * + * ```js + * ScriptableNodeResources.set( 'TSL', TSL ); + * + * const scriptableNode = scriptable( js( ` + * layout = { + * outputType: 'node', + * elements: [ + * { name: 'source', inputType: 'node' }, + * ] + * }; + * + * const { mul, oscSine } = TSL; + * + * function main() { + * const source = parameters.get( 'source' ) || float(); + * return mul( source, oscSine() ) ); + * } + * + * ` ) ); + * + * scriptableNode.setParameter( 'source', color( 1, 0, 0 ) ); + * + * const material = new THREE.MeshBasicNodeMaterial(); + * material.colorNode = scriptableNode; + * ``` + * + * @augments Node + */ class ScriptableNode extends Node { static get type() { @@ -23569,11 +32266,30 @@ class ScriptableNode extends Node { } + /** + * Constructs a new scriptable node. + * + * @param {CodeNode?} [codeNode=null] - The code node. + * @param {Object} [parameters={}] - The parameters definition. + */ constructor( codeNode = null, parameters = {} ) { super(); + /** + * The code node. + * + * @type {CodeNode?} + * @default null + */ this.codeNode = codeNode; + + /** + * The parameters definition. + * + * @type {Object} + * @default {} + */ this.parameters = parameters; this._local = new Resources(); @@ -23587,34 +32303,68 @@ class ScriptableNode extends Node { this.onRefresh = this.onRefresh.bind( this ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isScriptableNode = true; } + /** + * The source code of the scriptable node. + * + * @type {String} + */ get source() { return this.codeNode ? this.codeNode.code : ''; } + /** + * Sets the reference of a local script variable. + * + * @param {String} name - The variable name. + * @param {Object} value - The reference to set. + * @return {Resources} The resource map + */ setLocal( name, value ) { return this._local.set( name, value ); } + /** + * Gets the value of a local script variable. + * + * @param {String} name - The variable name. + * @return {Object} The value. + */ getLocal( name ) { return this._local.get( name ); } + /** + * Event listener for the `refresh` event. + */ onRefresh() { this._refresh(); } + /** + * Returns an input from the layout with the given id/name. + * + * @param {String} id - The id/name of the input. + * @return {Object} The element entry. + */ getInputLayout( id ) { for ( const element of this.getLayout() ) { @@ -23629,6 +32379,12 @@ class ScriptableNode extends Node { } + /** + * Returns an output from the layout with the given id/name. + * + * @param {String} id - The id/name of the output. + * @return {Object} The element entry. + */ getOutputLayout( id ) { for ( const element of this.getLayout() ) { @@ -23643,6 +32399,13 @@ class ScriptableNode extends Node { } + /** + * Defines a script output for the given name and value. + * + * @param {String} name - The name of the output. + * @param {Node} value - The node value. + * @return {ScriptableNode} A reference to this node. + */ setOutput( name, value ) { const outputs = this._outputs; @@ -23661,18 +32424,37 @@ class ScriptableNode extends Node { } + /** + * Returns a script output for the given name. + * + * @param {String} name - The name of the output. + * @return {ScriptableValueNode} The node value. + */ getOutput( name ) { return this._outputs[ name ]; } + /** + * Returns a parameter for the given name + * + * @param {String} name - The name of the parameter. + * @return {ScriptableValueNode} The node value. + */ getParameter( name ) { return this.parameters[ name ]; } + /** + * Sets a value for the given parameter name. + * + * @param {String} name - The parameter name. + * @param {Any} value - The parameter value. + * @return {ScriptableNode} A reference to this node. + */ setParameter( name, value ) { const parameters = this.parameters; @@ -23706,12 +32488,24 @@ class ScriptableNode extends Node { } + /** + * Returns the value of this node which is the value of + * the default output. + * + * @return {Node} The value. + */ getValue() { return this.getDefaultOutput().getValue(); } + /** + * Deletes a parameter from the script. + * + * @param {String} name - The parameter to remove. + * @return {ScriptableNode} A reference to this node. + */ deleteParameter( name ) { let valueNode = this.parameters[ name ]; @@ -23728,6 +32522,11 @@ class ScriptableNode extends Node { } + /** + * Deletes all parameters from the script. + * + * @return {ScriptableNode} A reference to this node. + */ clearParameters() { for ( const name of Object.keys( this.parameters ) ) { @@ -23742,6 +32541,13 @@ class ScriptableNode extends Node { } + /** + * Calls a function from the script. + * + * @param {String} name - The function name. + * @param {...Any} params - A list of parameters. + * @return {Any} The result of the function call. + */ call( name, ...params ) { const object = this.getObject(); @@ -23755,6 +32561,13 @@ class ScriptableNode extends Node { } + /** + * Asynchronously calls a function from the script. + * + * @param {String} name - The function name. + * @param {...Any} params - A list of parameters. + * @return {Promise} The result of the function call. + */ async callAsync( name, ...params ) { const object = this.getObject(); @@ -23768,12 +32581,23 @@ class ScriptableNode extends Node { } + /** + * Overwritten since the node types is inferred from the script's output. + * + * @param {NodeBuilder} builder - The current node builder + * @return {String} The node type. + */ getNodeType( builder ) { return this.getDefaultOutputNode().getNodeType( builder ); } + /** + * Refreshes the script node. + * + * @param {String?} [output=null] - An optional output. + */ refresh( output = null ) { if ( output !== null ) { @@ -23788,6 +32612,11 @@ class ScriptableNode extends Node { } + /** + * Returns an object representation of the script. + * + * @return {Object} The result object. + */ getObject() { if ( this.needsUpdate ) this.dispose(); @@ -23803,7 +32632,7 @@ class ScriptableNode extends Node { const THREE = ScriptableNodeResources.get( 'THREE' ); const TSL = ScriptableNodeResources.get( 'TSL' ); - const method = this.getMethod( this.codeNode ); + const method = this.getMethod(); const params = [ parameters, this._local, ScriptableNodeResources, refresh, setOutput, THREE, TSL ]; this._object = method( ...params ); @@ -23869,12 +32698,22 @@ class ScriptableNode extends Node { } + /** + * Returns the layout of the script. + * + * @return {Object} The script's layout. + */ getLayout() { return this.getObject().layout; } + /** + * Returns default node output of the script. + * + * @return {Node} The default node output. + */ getDefaultOutputNode() { const output = this.getDefaultOutput().value; @@ -23889,12 +32728,22 @@ class ScriptableNode extends Node { } + /** + * Returns default output of the script. + * + * @return {ScriptableValueNode} The default output. + */ getDefaultOutput() { return this._exec()._output; } + /** + * Returns a function created from the node's script. + * + * @return {Function} The function representing the node's code. + */ getMethod() { if ( this.needsUpdate ) this.dispose(); @@ -23919,6 +32768,9 @@ class ScriptableNode extends Node { } + /** + * Frees all internal resources. + */ dispose() { if ( this._method === null ) return; @@ -23971,6 +32823,12 @@ class ScriptableNode extends Node { } + /** + * Executes the `main` function of the script. + * + * @private + * @return {ScriptableNode} A reference to this node. + */ _exec() { if ( this.codeNode === null ) return this; @@ -23989,6 +32847,11 @@ class ScriptableNode extends Node { } + /** + * Executes the refresh. + * + * @private + */ _refresh() { this.needsUpdate = true; @@ -24001,211 +32864,124 @@ class ScriptableNode extends Node { } -const scriptable = /*@__PURE__*/ nodeProxy( ScriptableNode ); - /** - * This class can be used to configure a fog for the scene. - * Nodes of this type are assigned to `Scene.fogNode`. + * TSL function for creating a scriptable node. * - * @augments Node + * @function + * @param {CodeNode?} [codeNode=null] - The code node. + * @param {Object} [parameters={}] - The parameters definition. + * @returns {ScriptableNode} */ -class FogNode extends Node { - - static get type() { - - return 'FogNode'; - - } - - /** - * Constructs a new fog node. - * - * @param {Node} colorNode - Defines the color of the fog. - * @param {Node} factorNode - Defines how the fog is factored in the scene. - */ - constructor( colorNode, factorNode ) { - - super( 'float' ); - - /** - * This flag can be used for type testing. - * - * @type {Boolean} - * @readonly - * @default true - */ - this.isFogNode = true; - - /** - * Defines the color of the fog. - * - * @type {Node?} - */ - this.colorNode = colorNode; - - /** - * Defines how the fog is factored in the scene. - * - * @type {Node?} - */ - this.factorNode = factorNode; - - } - - /** - * Returns a node that represents the `z` coordinate in view space - * for the current fragment. It's a different representation of the - * default depth value. - * - * This value can be part of a computation that defines how the fog - * density increases when moving away from the camera. - * - * @param {NodeBuilder} builder - The current node builder. - * @return {Node} The viewZ node. - */ - getViewZNode( builder ) { +const scriptable = /*@__PURE__*/ nodeProxy( ScriptableNode ); - let viewZ; +/** @module Fog **/ - const getViewZ = builder.context.getViewZ; +/** + * Returns a node that represents the `z` coordinate in view space + * for the current fragment. It's a different representation of the + * default depth value. + * + * This value can be part of a computation that defines how the fog + * density increases when moving away from the camera. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The viewZ node. + */ +function getViewZNode( builder ) { - if ( getViewZ !== undefined ) { + let viewZ; - viewZ = getViewZ( this ); + const getViewZ = builder.context.getViewZ; - } + if ( getViewZ !== undefined ) { - return ( viewZ || positionView.z ).negate(); + viewZ = getViewZ( this ); } - setup() { - - return this.factorNode; - - } + return ( viewZ || positionView.z ).negate(); } -const fog = /*@__PURE__*/ nodeProxy( FogNode ); - /** - * Represents a range fog. The fog is smoothly interpolated - * between a range defined via near and far values. + * Constructs a new range factor node. * - * @augments FogNode + * @function + * @param {Node} near - Defines the near value. + * @param {Node} far - Defines the far value. */ -class FogRangeNode extends FogNode { - - static get type() { - - return 'FogRangeNode'; - - } - - /** - * Constructs a new range node. - * - * @param {Node} colorNode - Defines the color of the fog. - * @param {Node} nearNode - Defines the near value. - * @param {Node} farNode - Defines the far value. - */ - constructor( colorNode, nearNode, farNode ) { +const rangeFogFactor = Fn( ( [ near, far ], builder ) => { - super( colorNode, null ); + const viewZ = getViewZNode( builder ); - /** - * This flag can be used for type testing. - * - * @type {Boolean} - * @readonly - * @default true - */ - this.isFogRangeNode = true; - - /** - * Defines the near value. - * - * @type {Node} - */ - this.nearNode = nearNode; + return smoothstep( near, far, viewZ ); - /** - * Defines the far value. - * - * @type {Node} - */ - this.farNode = farNode; - - } - - setup( builder ) { - - const viewZ = this.getViewZNode( builder ); - - return smoothstep( this.nearNode, this.farNode, viewZ ); - - } - -} - -const rangeFog = /*@__PURE__*/ nodeProxy( FogRangeNode ); +} ); /** * Represents an exponential squared fog. This type of fog gives * a clear view near the camera and a faster than exponentially * densening fog farther from the camera. * - * @augments FogNode + * @function + * @param {Node} density - Defines the fog density. */ -class FogExp2Node extends FogNode { +const densityFogFactor = Fn( ( [ density ], builder ) => { - static get type() { + const viewZ = getViewZNode( builder ); - return 'FogExp2Node'; + return density.mul( density, viewZ, viewZ ).negate().exp().oneMinus(); - } +} ); - /** - * Constructs a new exponential squared fog node. - * - * @param {Node} colorNode - Defines the color of the fog. - * @param {Node} densityNode - Defines the fog density. - */ - constructor( colorNode, densityNode ) { +/** + * This class can be used to configure a fog for the scene. + * Nodes of this type are assigned to `Scene.fogNode`. + * + * @function + * @param {Node} color - Defines the color of the fog. + * @param {Node} factor - Defines how the fog is factored in the scene. + */ +const fog = Fn( ( [ color, factor ] ) => { - super( colorNode, null ); + return vec4( factor.toFloat().mix( output.rgb, color.toVec3() ), output.a ); - /** - * This flag can be used for type testing. - * - * @type {Boolean} - * @readonly - * @default true - */ - this.isFogExp2Node = true; +} ); - /** - * Defines the fog density. - * - * @type {Node} - */ - this.densityNode = densityNode; +// Deprecated - } +/** + * @function + * @deprecated since r171. Use `fog( color, rangeFogFactor( near, far ) )` instead. + * + * @param {Node} color + * @param {Node} near + * @param {Node} far + * @returns {Function} + */ +function rangeFog( color, near, far ) { // @deprecated, r171 - setup( builder ) { + console.warn( 'THREE.TSL: "rangeFog( color, near, far )" is deprecated. Use "fog( color, rangeFogFactor( near, far ) )" instead.' ); + return fog( color, rangeFogFactor( near, far ) ); - const viewZ = this.getViewZNode( builder ); - const density = this.densityNode; +} - return density.mul( density, viewZ, viewZ ).negate().exp().oneMinus(); +/** + * @function + * @deprecated since r171. Use `fog( color, densityFogFactor( density ) )` instead. + * + * @param {Node} color + * @param {Node} density + * @returns {Function} + */ +function densityFog( color, density ) { // @deprecated, r171 - } + console.warn( 'THREE.TSL: "densityFog( color, density )" is deprecated. Use "fog( color, densityFogFactor( density ) )" instead.' ); + return fog( color, densityFogFactor( density ) ); } -const densityFog = /*@__PURE__*/ nodeProxy( FogExp2Node ); +/** @module RangeNode **/ let min = null; let max = null; @@ -24356,8 +33132,26 @@ class RangeNode extends Node { } +/** + * TSL function for creating a range node. + * + * @function + * @param {Node} [minNode=float()] - A node defining the lower bound of the range. + * @param {Node} [maxNode=float()] - A node defining the upper bound of the range. + * @returns {RangeNode} + */ const range = /*@__PURE__*/ nodeProxy( RangeNode ); +/** @module ComputeBuiltinNode **/ + +/** + * `ComputeBuiltinNode` represents a compute-scope builtin value that expose information + * about the currently running dispatch and/or the device it is running on. + * + * This node can only be used with a WebGPU backend. + * + * @augments Node + */ class ComputeBuiltinNode extends Node { static get type() { @@ -24366,26 +33160,56 @@ class ComputeBuiltinNode extends Node { } + /** + * Constructs a new compute builtin node. + * + * @param {String} builtinName - The built-in name. + * @param {String} nodeType - The node type. + */ constructor( builtinName, nodeType ) { super( nodeType ); + /** + * The built-in name. + * + * @private + * @type {String} + */ this._builtinName = builtinName; } + /** + * This method is overwritten since hash is derived from the built-in name. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The hash. + */ getHash( builder ) { return this.getBuiltinName( builder ); } + /** + * This method is overwritten since the node type is simply derived from `nodeType`.. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( /*builder*/ ) { return this.nodeType; } + /** + * Sets the builtin name. + * + * @param {String} builtinName - The built-in name. + * @return {ComputeBuiltinNode} A reference to this node. + */ setBuiltinName( builtinName ) { this._builtinName = builtinName; @@ -24394,12 +33218,23 @@ class ComputeBuiltinNode extends Node { } + /** + * Returns the builtin name. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The builtin name. + */ getBuiltinName( /*builder*/ ) { return this._builtinName; } + /** + * Whether the current node builder has the builtin or not. + * + * @param {NodeBuilder} builder - The current node builder. + */ hasBuiltin( builder ) { builder.hasBuiltin( this._builtinName ); @@ -24444,15 +33279,112 @@ class ComputeBuiltinNode extends Node { } +/** + * TSL function for creating a compute builtin node. + * + * @function + * @param {String} name - The built-in name. + * @param {String} nodeType - The node type. + * @returns {ComputeBuiltinNode} + */ const computeBuiltin = ( name, nodeType ) => nodeObject( new ComputeBuiltinNode( name, nodeType ) ); +/** + * TSL function for creating a `numWorkgroups` builtin node. + * Represents the number of workgroups dispatched by the compute shader. + * ```js + * // Run 512 invocations/threads with a workgroup size of 128. + * const computeFn = Fn(() => { + * + * // numWorkgroups.x = 4 + * storageBuffer.element(0).assign(numWorkgroups.x) + * + * })().compute(512, [128]); + * + * // Run 512 invocations/threads with the default workgroup size of 64. + * const computeFn = Fn(() => { + * + * // numWorkgroups.x = 8 + * storageBuffer.element(0).assign(numWorkgroups.x) + * + * })().compute(512); + * ``` + * + * @function + * @returns {ComputeBuiltinNode} + */ const numWorkgroups = /*@__PURE__*/ computeBuiltin( 'numWorkgroups', 'uvec3' ); + +/** + * TSL function for creating a `workgroupId` builtin node. + * Represents the 3-dimensional index of the workgroup the current compute invocation belongs to. + * ```js + * // Execute 12 compute threads with a workgroup size of 3. + * const computeFn = Fn( () => { + * + * If( workgroupId.x.modInt( 2 ).equal( 0 ), () => { + * + * storageBuffer.element( instanceIndex ).assign( instanceIndex ); + * + * } ).Else( () => { + * + * storageBuffer.element( instanceIndex ).assign( 0 ); + * + * } ); + * + * } )().compute( 12, [ 3 ] ); + * + * // workgroupId.x = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]; + * // Buffer Output = [0, 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0]; + * ``` + * + * @function + * @returns {ComputeBuiltinNode} + */ const workgroupId = /*@__PURE__*/ computeBuiltin( 'workgroupId', 'uvec3' ); + +/** + * TSL function for creating a `globalId` builtin node. A non-linearized 3-dimensional + * representation of the current invocation's position within a 3D global grid. + * + * @function + * @returns {ComputeBuiltinNode} + */ +const globalId = /*@__PURE__*/ computeBuiltin( 'globalId', 'uvec3' ); +/** + * TSL function for creating a `localId` builtin node. A non-linearized 3-dimensional + * representation of the current invocation's position within a 3D workgroup grid. + * + * @function + * @returns {ComputeBuiltinNode} + */ const localId = /*@__PURE__*/ computeBuiltin( 'localId', 'uvec3' ); + +/** + * TSL function for creating a `subgroupSize` builtin node. A device dependent variable + * that exposes the size of the current invocation's subgroup. + * + * @function + * @returns {ComputeBuiltinNode} + */ const subgroupSize = /*@__PURE__*/ computeBuiltin( 'subgroupSize', 'uint' ); +/** @module BarrierNode **/ + +/** + * Represents a GPU control barrier that synchronizes compute operations within a given scope. + * + * This node can only be used with a WebGPU backend. + * + * @augments Node + */ class BarrierNode extends Node { + /** + * Constructs a new barrier node. + * + * @param {String} scope - The scope defines the behavior of the node. + */ constructor( scope ) { super(); @@ -24480,18 +33412,71 @@ class BarrierNode extends Node { } +/** + * TSL function for creating a barrier node. + * + * @function + * @param {String} scope - The scope defines the behavior of the node.. + * @returns {BarrierNode} + */ const barrier = nodeProxy( BarrierNode ); +/** + * TSL function for creating a workgroup barrier. All compute shader + * invocations must wait for each invocation within a workgroup to + * complete before the barrier can be surpassed. + * + * @function + * @returns {BarrierNode} + */ const workgroupBarrier = () => barrier( 'workgroup' ).append(); + +/** + * TSL function for creating a storage barrier. All invocations must + * wait for each access to variables within the 'storage' address space + * to complete before the barrier can be passed. + * + * @function + * @returns {BarrierNode} + */ const storageBarrier = () => barrier( 'storage' ).append(); + +/** + * TSL function for creating a texture barrier. All invocations must + * wait for each access to variables within the 'texture' address space + * to complete before the barrier can be passed. + * + * @function + * @returns {BarrierNode} + */ const textureBarrier = () => barrier( 'texture' ).append(); +/** @module WorkgroupInfoNode **/ + +/** + * Represents an element of a 'workgroup' scoped buffer. + * + * @augments ArrayElementNode + */ class WorkgroupInfoElementNode extends ArrayElementNode { + /** + * Constructs a new workgroup info element node. + * + * @param {Node} workgroupInfoNode - The workgroup info node. + * @param {Node} indexNode - The index node that defines the element access. + */ constructor( workgroupInfoNode, indexNode ) { super( workgroupInfoNode, indexNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWorkgroupInfoElementNode = true; } @@ -24519,22 +33504,77 @@ class WorkgroupInfoElementNode extends ArrayElementNode { } - +/** + * A node allowing the user to create a 'workgroup' scoped buffer within the + * context of a compute shader. Typically, workgroup scoped buffers are + * created to hold data that is transferred from a global storage scope into + * a local workgroup scope. For invocations within a workgroup, data + * access speeds on 'workgroup' scoped buffers can be significantly faster + * than similar access operations on globally accessible storage buffers. + * + * This node can only be used with a WebGPU backend. + * + * @augments Node + */ class WorkgroupInfoNode extends Node { + /** + * Constructs a new buffer scoped to type scope. + * + * @param {String} scope - TODO. + * @param {String} bufferType - The data type of a 'workgroup' scoped buffer element. + * @param {Number} [bufferCount=0] - The number of elements in the buffer. + */ constructor( scope, bufferType, bufferCount = 0 ) { super( bufferType ); + /** + * The buffer type. + * + * @type {String} + */ this.bufferType = bufferType; + + /** + * The buffer count. + * + * @type {Number} + * @default 0 + */ this.bufferCount = bufferCount; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWorkgroupInfoNode = true; + /** + * The data type of the array buffer. + * + * @type {String} + */ + this.elementType = bufferType; + + /** + * TODO. + * + * @type {String} + */ this.scope = scope; } + /** + * Sets the name/label of this node. + * + * @param {String} name - The name to set. + * @return {WorkgroupInfoNode} A reference to this node. + */ label( name ) { this.name = name; @@ -24543,26 +33583,51 @@ class WorkgroupInfoNode extends Node { } - getHash() { + /** + * Sets the scope of this node. + * + * @param {String} scope - The scope to set. + * @return {WorkgroupInfoNode} A reference to this node. + */ + setScope( scope ) { - return this.uuid; + this.scope = scope; + + return this; } - setScope( scope ) { - this.scope = scope; + /** + * The data type of the array buffer. + * + * @return {String} The element type. + */ + getElementType() { - return this; + return this.elementType; } + /** + * Overwrites the default implementation since the input type + * is inferred from the scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return `${this.scope}Array`; } + /** + * This method can be used to access elements via an index node. + * + * @param {IndexNode} indexNode - indexNode. + * @return {WorkgroupInfoElementNode} A reference to an element. + */ element( indexNode ) { return nodeObject( new WorkgroupInfoElementNode( this, indexNode ) ); @@ -24577,8 +33642,30 @@ class WorkgroupInfoNode extends Node { } +/** + * TSL function for creating a workgroup info node. + * Creates a new 'workgroup' scoped array buffer. + * + * @function + * @param {String} type - The data type of a 'workgroup' scoped buffer element. + * @param {Number} [count=0] - The number of elements in the buffer. + * @returns {WorkgroupInfoNode} + */ const workgroupArray = ( type, count ) => nodeObject( new WorkgroupInfoNode( 'Workgroup', type, count ) ); +/** @module AtomicFunctionNode **/ + +/** + * `AtomicFunctionNode` represents any function that can operate on atomic variable types + * within a shader. In an atomic function, any modification to an atomic variable will + * occur as an indivisible step with a defined order relative to other modifications. + * Accordingly, even if multiple atomic functions are modifying an atomic variable at once + * atomic operations will not interfere with each other. + * + * This node can only be used with a WebGPU backend. + * + * @augments TempNode + */ class AtomicFunctionNode extends TempNode { static get type() { @@ -24587,24 +33674,68 @@ class AtomicFunctionNode extends TempNode { } + /** + * Constructs a new atomic function node. + * + * @param {String} method - The signature of the atomic function to construct. + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + */ constructor( method, pointerNode, valueNode, storeNode = null ) { super( 'uint' ); + /** + * The signature of the atomic function to construct. + * + * @type {String} + */ this.method = method; + /** + * An atomic variable or element of an atomic buffer. + * + * @type {Node} + */ this.pointerNode = pointerNode; + + /** + * A value that modifies the atomic variable. + * + * @type {Node} + */ this.valueNode = valueNode; + + /** + * A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * + * @type {Node?} + * @default null + */ this.storeNode = storeNode; } + /** + * Overwrites the default implementation to return the type of + * the pointer node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( builder ) { return this.pointerNode.getNodeType( builder ); } + /** + * Overwritten since the node type is inferred from the input type. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { return this.getInputType( builder ); @@ -24654,9 +33785,29 @@ AtomicFunctionNode.ATOMIC_AND = 'atomicAnd'; AtomicFunctionNode.ATOMIC_OR = 'atomicOr'; AtomicFunctionNode.ATOMIC_XOR = 'atomicXor'; +/** + * TSL function for creating an atomic function node. + * + * @function + * @param {String} method - The signature of the atomic function to construct. + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicNode = nodeProxy( AtomicFunctionNode ); -const atomicFunc = ( method, pointerNode, valueNode, storeNode ) => { +/** + * TSL function for appending an atomic function call into the programmatic flow of a compute shader. + * + * @function + * @param {String} method - The signature of the atomic function to construct. + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ +const atomicFunc = ( method, pointerNode, valueNode, storeNode = null ) => { const node = atomicNode( method, pointerNode, valueNode, storeNode ); node.append(); @@ -24665,15 +33816,96 @@ const atomicFunc = ( method, pointerNode, valueNode, storeNode ) => { }; +/** + * Stores a value in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicStore = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_STORE, pointerNode, valueNode, storeNode ); + +/** + * Increments the value stored in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicAdd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_ADD, pointerNode, valueNode, storeNode ); + +/** + * Decrements the value stored in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicSub = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_SUB, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the maximum between its current value and a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicMax = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MAX, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the minimum between its current value and a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicMin = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MIN, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the bitwise AND of its value with a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicAnd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_AND, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the bitwise OR of its value with a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicOr = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_OR, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the bitwise XOR of its value with a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicXor = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_XOR, pointerNode, valueNode, storeNode ); +/** @module Lights **/ + let uniformsLib; function getLightData( light ) { @@ -24688,6 +33920,13 @@ function getLightData( light ) { } +/** + * TSL function for getting a shadow matrix uniform node for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The shadow matrix uniform node. + */ function lightShadowMatrix( light ) { const data = getLightData( light ); @@ -24706,6 +33945,14 @@ function lightShadowMatrix( light ) { } +/** + * TSL function for getting projected uv coordinates for the given light. + * Relevant when using maps with spot lights. + * + * @function + * @param {Light} light -The light source. + * @returns {Node} The projected uvs. + */ function lightProjectionUV( light ) { const data = getLightData( light ); @@ -24723,6 +33970,13 @@ function lightProjectionUV( light ) { } +/** + * TSL function for getting the position in world space for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The light's position in world space. + */ function lightPosition( light ) { const data = getLightData( light ); @@ -24731,6 +33985,13 @@ function lightPosition( light ) { } +/** + * TSL function for getting the light target position in world space for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The light target position in world space. + */ function lightTargetPosition( light ) { const data = getLightData( light ); @@ -24739,6 +34000,13 @@ function lightTargetPosition( light ) { } +/** + * TSL function for getting the position in view space for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The light's position in view space. + */ function lightViewPosition( light ) { const data = getLightData( light ); @@ -24754,8 +34022,17 @@ function lightViewPosition( light ) { } +/** + * TSL function for getting the light target direction for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {Node} The light's target direction. + */ const lightTargetDirection = ( light ) => cameraViewMatrix.transformDirection( lightPosition( light ).sub( lightTargetPosition( light ) ) ); +/** @module LightsNode **/ + const sortLights = ( lights ) => { return lights.sort( ( a, b ) => a.id - b.id ); @@ -24780,6 +34057,13 @@ const getLightNodeById = ( id, lightNodes ) => { const _lightsNodeRef = /*@__PURE__*/ new WeakMap(); +/** + * This node represents the scene's lighting and manages the lighting model's life cycle + * for the current build 3D object. It is responsible for computing the total outgoing + * light in a given lighting context. + * + * @augments Node + */ class LightsNode extends Node { static get type() { @@ -24788,33 +34072,81 @@ class LightsNode extends Node { } + /** + * Constructs a new lights node. + */ constructor() { super( 'vec3' ); + /** + * A node representing the total diffuse light. + * + * @type {Node} + */ this.totalDiffuseNode = vec3().toVar( 'totalDiffuse' ); + + /** + * A node representing the total specular light. + * + * @type {Node} + */ this.totalSpecularNode = vec3().toVar( 'totalSpecular' ); + /** + * A node representing the outgoing light. + * + * @type {Node} + */ this.outgoingLightNode = vec3().toVar( 'outgoingLight' ); + /** + * An array representing the lights in the scene. + * + * @private + * @type {Array} + */ this._lights = []; + /** + * For each light in the scene, this node will create a + * corresponding light node. + * + * @private + * @type {Array?} + * @default null + */ this._lightNodes = null; + + /** + * A hash for identifying the current light nodes setup. + * + * @private + * @type {String?} + * @default null + */ this._lightNodesHash = null; + /** + * `LightsNode` sets this property to `true` by default. + * + * @type {Boolean} + * @default true + */ this.global = true; } /** - * Overwrites the default `customCacheKey()` implementation by including the + * Overwrites the default {@link Node#customCacheKey} implementation by including the * light IDs into the cache key. * - * @return {Number} The hash. + * @return {Number} The custom cache key. */ customCacheKey() { const lightIDs = []; + const lights = this._lights; for ( let i = 0; i < lights.length; i ++ ) { @@ -24826,6 +34158,12 @@ class LightsNode extends Node { } + /** + * Computes a hash value for identifying the current light nodes setup. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {String} The computed hash. + */ getHash( builder ) { if ( this._lightNodesHash === null ) { @@ -24860,6 +34198,12 @@ class LightsNode extends Node { } + /** + * Creates lighting nodes for each scene light. This makes it possible to further + * process lights in the node system. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + */ setupLightsNode( builder ) { const lightNodes = []; @@ -24887,6 +34231,8 @@ class LightsNode extends Node { if ( lightNode === null ) { + // find the corresponding node type for a given light + const lightNodeClass = nodeLibrary.getLightNodeClass( light.constructor ); if ( lightNodeClass === null ) { @@ -24921,6 +34267,13 @@ class LightsNode extends Node { } + /** + * Setups the internal lights by building all respective + * light nodes. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Array} lightNodes - An array of lighting nodes. + */ setupLights( builder, lightNodes ) { for ( const lightNode of lightNodes ) { @@ -24931,6 +34284,14 @@ class LightsNode extends Node { } + /** + * The implementation makes sure that for each light in the scene + * there is a corresponding light node. By building the light nodes + * and evaluating the lighting model the outgoing light is computed. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {Node} A node representing the outgoing light. + */ setup( builder ) { if ( this._lightNodes === null ) this.setupLightsNode( builder ); @@ -25007,6 +34368,12 @@ class LightsNode extends Node { } + /** + * Configures this node with an array of lights. + * + * @param {Array} lights - An array of lights. + * @return {LightsNode} A reference to this node. + */ setLights( lights ) { this._lights = lights; @@ -25018,12 +34385,22 @@ class LightsNode extends Node { } + /** + * Returns an array of the scene's lights. + * + * @return {Array} The scene's lights. + */ getLights() { return this._lights; } + /** + * Whether the scene has lights or not. + * + * @type {Boolean} + */ get hasLights() { return this._lights.length > 0; @@ -25032,8 +34409,27 @@ class LightsNode extends Node { } +/** + * TSL function for creating an instance of `LightsNode` and configuring + * it with the given array of lights. + * + * @function + * @param {Array} lights - An array of lights. + * @return {LightsNode} The created lights node. + */ const lights = ( lights = [] ) => nodeObject( new LightsNode() ).setLights( lights ); +/** @module ShadowBaseNode **/ + +/** + * Base class for all shadow nodes. + * + * Shadow nodes encapsulate shadow related logic and are always coupled to lighting nodes. + * Lighting nodes might share the same shadow node type or use specific ones depending on + * their requirements. + * + * @augments Node + */ class ShadowBaseNode extends Node { static get type() { @@ -25042,25 +34438,59 @@ class ShadowBaseNode extends Node { } + /** + * Constructs a new shadow base node. + * + * @param {Light} light - The shadow casting light. + */ constructor( light ) { super(); + /** + * The shadow casting light. + * + * @type {Light} + */ this.light = light; + + /** + * Overwritten since shadows are updated by default per render. + * + * @type {String} + * @default 'render' + */ this.updateBeforeType = NodeUpdateType.RENDER; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isShadowBaseNode = true; } + /** + * Setups the shadow position node which is by default the predefined TSL node object `shadowPositionWorld`. + * + * @param {(NodeBuilder|{Material})} object - A configuration object that must at least hold a material reference. + */ setupShadowPosition( { material } ) { // Use assign inside an Fn() - shadowWorldPosition.assign( material.shadowPositionNode || positionWorld ); + shadowPositionWorld.assign( material.shadowPositionNode || positionWorld ); } + /** + * Can be called when the shadow isn't required anymore. That can happen when + * a lighting node stops casting shadows by setting {@link Object3D#castShadow} + * to `false`. + */ dispose() { this.updateBeforeType = NodeUpdateType.NONE; @@ -25069,7 +34499,219 @@ class ShadowBaseNode extends Node { } -const shadowWorldPosition = /*@__PURE__*/ vec3().toVar( 'shadowWorldPosition' ); +/** + * TSL object that represents the vertex position in world space during the shadow pass. + * + * @type {Node} + */ +const shadowPositionWorld = /*@__PURE__*/ vec3().toVar( 'shadowPositionWorld' ); + +/** @module RendererUtils **/ + +/** + * Saves the state of the given renderer and stores it into the given state object. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function saveRendererState( renderer, state = {} ) { + + state.toneMapping = renderer.toneMapping; + state.toneMappingExposure = renderer.toneMappingExposure; + state.outputColorSpace = renderer.outputColorSpace; + state.renderTarget = renderer.getRenderTarget(); + state.activeCubeFace = renderer.getActiveCubeFace(); + state.activeMipmapLevel = renderer.getActiveMipmapLevel(); + state.renderObjectFunction = renderer.getRenderObjectFunction(); + state.pixelRatio = renderer.getPixelRatio(); + state.mrt = renderer.getMRT(); + state.clearColor = renderer.getClearColor( state.clearColor || new Color() ); + state.clearAlpha = renderer.getClearAlpha(); + state.autoClear = renderer.autoClear; + state.scissorTest = renderer.getScissorTest(); + + return state; + +} + +/** + * Saves the state of the given renderer and stores it into the given state object. + * Besides, the function also resets the state of the renderer to its default values. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function resetRendererState( renderer, state ) { + + state = saveRendererState( renderer, state ); + + renderer.setMRT( null ); + renderer.setRenderObjectFunction( null ); + renderer.setClearColor( 0x000000, 1 ); + renderer.autoClear = true; + + return state; + +} + +/** + * Restores the state of the given renderer from the given state object. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Object} state - The state to restore. + */ +function restoreRendererState( renderer, state ) { + + renderer.toneMapping = state.toneMapping; + renderer.toneMappingExposure = state.toneMappingExposure; + renderer.outputColorSpace = state.outputColorSpace; + renderer.setRenderTarget( state.renderTarget, state.activeCubeFace, state.activeMipmapLevel ); + renderer.setRenderObjectFunction( state.renderObjectFunction ); + renderer.setPixelRatio( state.pixelRatio ); + renderer.setMRT( state.mrt ); + renderer.setClearColor( state.clearColor, state.clearAlpha ); + renderer.autoClear = state.autoClear; + renderer.setScissorTest( state.scissorTest ); + +} + +/** + * Saves the state of the given scene and stores it into the given state object. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function saveSceneState( scene, state = {} ) { + + state.background = scene.background; + state.backgroundNode = scene.backgroundNode; + state.overrideMaterial = scene.overrideMaterial; + + return state; + +} + +/** + * Saves the state of the given scene and stores it into the given state object. + * Besides, the function also resets the state of the scene to its default values. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function resetSceneState( scene, state ) { + + state = saveSceneState( scene, state ); + + scene.background = null; + scene.backgroundNode = null; + scene.overrideMaterial = null; + + return state; + +} + +/** + * Restores the state of the given scene from the given state object. + * + * @function + * @param {Scene} scene - The scene. + * @param {Object} state - The state to restore. + */ +function restoreSceneState( scene, state ) { + + scene.background = state.background; + scene.backgroundNode = state.backgroundNode; + scene.overrideMaterial = state.overrideMaterial; + +} + +/** + * Saves the state of the given renderer and scene and stores it into the given state object. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function saveRendererAndSceneState( renderer, scene, state = {} ) { + + state = saveRendererState( renderer, state ); + state = saveSceneState( scene, state ); + + return state; + +} + +/** + * Saves the state of the given renderer and scene and stores it into the given state object. + * Besides, the function also resets the state of the renderer and scene to its default values. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +function resetRendererAndSceneState( renderer, scene, state ) { + + state = resetRendererState( renderer, state ); + state = resetSceneState( scene, state ); + + return state; + +} + +/** + * Restores the state of the given renderer and scene from the given state object. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Scene} scene - The scene. + * @param {Object} state - The state to restore. + */ +function restoreRendererAndSceneState( renderer, scene, state ) { + + restoreRendererState( renderer, state ); + restoreSceneState( scene, state ); + +} + +var RendererUtils = /*#__PURE__*/Object.freeze({ + __proto__: null, + resetRendererAndSceneState: resetRendererAndSceneState, + resetRendererState: resetRendererState, + resetSceneState: resetSceneState, + restoreRendererAndSceneState: restoreRendererAndSceneState, + restoreRendererState: restoreRendererState, + restoreSceneState: restoreSceneState, + saveRendererAndSceneState: saveRendererAndSceneState, + saveRendererState: saveRendererState, + saveSceneState: saveSceneState +}); + +/** @module ShadowNode **/ const shadowMaterialLib = /*@__PURE__*/ new WeakMap(); const linearDistance = /*@__PURE__*/ Fn( ( [ position, cameraNear, cameraFar ] ) => { @@ -25106,8 +34748,9 @@ const getShadowMaterial = ( light ) => { material = new NodeMaterial(); material.colorNode = vec4( 0, 0, 0, 1 ); material.depthNode = depthNode; - material.isShadowNodeMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode + material.isShadowPassMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode material.name = 'ShadowMaterial'; + material.fog = false; shadowMaterialLib.set( light, material ); @@ -25117,12 +34760,32 @@ const getShadowMaterial = ( light ) => { }; +/** + * A shadow filtering function performing basic filtering. This is in fact an unfiltered version of the shadow map + * with a binary `[0,1]` result. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - The shadow coordinates. + * @return {Node} The filtering result. + */ const BasicShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord } ) => { return texture( depthTexture, shadowCoord.xy ).compare( shadowCoord.z ); } ); +/** + * A shadow filtering function performing PCF filtering. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - The shadow coordinates. + * @param {LightShadow} inputs.shadow - The light shadow. + * @return {Node} The filtering result. + */ const PCFShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, shadow } ) => { const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); @@ -25162,6 +34825,16 @@ const PCFShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, shadow } ); +/** + * A shadow filtering function performing PCF soft filtering. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - The shadow coordinates. + * @param {LightShadow} inputs.shadow - The light shadow. + * @return {Node} The filtering result. + */ const PCFSoftShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, shadow } ) => { const depthCompare = ( uv, compare ) => texture( depthTexture, uv ).compare( compare ); @@ -25218,8 +34891,15 @@ const PCFSoftShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, sha } ); -// VSM - +/** + * A shadow filtering function performing VSM filtering. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - The shadow coordinates. + * @return {Node} The filtering result. + */ const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord } ) => { const occlusion = float( 1 ).toVar(); @@ -25242,6 +34922,17 @@ const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord } ) => { } ); +/** + * Represents the shader code for the first VSM render pass. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {Node} inputs.samples - The number of samples + * @param {Node} inputs.radius - The radius. + * @param {Node} inputs.size - The size. + * @param {TextureNode} inputs.shadowPass - A reference to the render target's depth data. + * @return {Node} The VSM output. + */ const VSMPassVertical = /*@__PURE__*/ Fn( ( { samples, radius, size, shadowPass } ) => { const mean = float( 0 ).toVar(); @@ -25268,6 +34959,17 @@ const VSMPassVertical = /*@__PURE__*/ Fn( ( { samples, radius, size, shadowPass } ); +/** + * Represents the shader code for the second VSM render pass. + * + * @method + * @param {Object} inputs - The input parameter object. + * @param {Node} inputs.samples - The number of samples + * @param {Node} inputs.radius - The radius. + * @param {Node} inputs.size - The size. + * @param {TextureNode} inputs.shadowPass - The result of the first VSM render pass. + * @return {Node} The VSM output. + */ const VSMPassHorizontal = /*@__PURE__*/ Fn( ( { samples, radius, size, shadowPass } ) => { const mean = float( 0 ).toVar(); @@ -25298,8 +35000,14 @@ const _shadowFilterLib = [ BasicShadowFilter, PCFShadowFilter, PCFSoftShadowFilt // -const _quadMesh$1 = /*@__PURE__*/ new QuadMesh(); +let _rendererState; +const _quadMesh = /*@__PURE__*/ new QuadMesh(); +/** + * Represents the default shadow implementation for lighting nodes. + * + * @augments module:ShadowBaseNode~ShadowBaseNode + */ class ShadowNode extends ShadowBaseNode { static get type() { @@ -25308,26 +35016,101 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Constructs a new shadow node. + * + * @param {Light} light - The shadow casting light. + * @param {LightShadow?} [shadow=null] - An optional light shadow. + */ constructor( light, shadow = null ) { super( light ); + /** + * The light shadow which defines the properties light's + * shadow. + * + * @type {LightShadow?} + * @default null + */ this.shadow = shadow || light.shadow; + /** + * A reference to the shadow map which is a render target. + * + * @type {RenderTarget?} + * @default null + */ this.shadowMap = null; + /** + * Only relevant for VSM shadows. Render target for the + * first VSM render pass. + * + * @type {RenderTarget?} + * @default null + */ this.vsmShadowMapVertical = null; + + /** + * Only relevant for VSM shadows. Render target for the + * second VSM render pass. + * + * @type {RenderTarget?} + * @default null + */ this.vsmShadowMapHorizontal = null; + /** + * Only relevant for VSM shadows. Node material which + * is used to render the first VSM pass. + * + * @type {NodeMaterial?} + * @default null + */ this.vsmMaterialVertical = null; + + /** + * Only relevant for VSM shadows. Node material which + * is used to render the second VSM pass. + * + * @type {NodeMaterial?} + * @default null + */ this.vsmMaterialHorizontal = null; + /** + * A reference to the output node which defines the + * final result of this shadow node. + * + * @type {Node?} + * @private + * @default null + */ this._node = null; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isShadowNode = true; } + /** + * Setups the shadow filtering. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Object} inputs - A configuration object that defines the shadow filtering. + * @param {Function} inputs.filterFn - This function defines the filtering type of the shadow map e.g. PCF. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - Shadow coordinates which are used to sample from the shadow map. + * @param {LightShadow} inputs.shadow - The light shadow. + * @return {Node} The result node of the shadow filtering. + */ setupShadowFilter( builder, { filterFn, depthTexture, shadowCoord, shadow } ) { const frustumTest = shadowCoord.x.greaterThanEqual( 0 ) @@ -25342,6 +35125,13 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Setups the shadow coordinates. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Node} shadowPosition - A node representing the shadow position. + * @return {Node} The shadow coordinates. + */ setupShadowCoord( builder, shadowPosition ) { const { shadow } = this; @@ -25389,12 +35179,24 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Returns the shadow filtering function for the given shadow type. + * + * @param {Number} type - The shadow type. + * @return {Function} The filtering function. + */ getShadowFilterFn( type ) { return _shadowFilterLib[ type ]; } + /** + * Setups the shadow output node. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {Node} The shadow output node. + */ setupShadow( builder ) { const { renderer } = builder; @@ -25442,7 +35244,7 @@ class ShadowNode extends ShadowBaseNode { const shadowIntensity = reference( 'intensity', 'float', shadow ).setGroup( renderGroup ); const normalBias = reference( 'normalBias', 'float', shadow ).setGroup( renderGroup ); - const shadowPosition = lightShadowMatrix( light ).mul( shadowWorldPosition.add( transformedNormalWorld.mul( normalBias ) ) ); + const shadowPosition = lightShadowMatrix( light ).mul( shadowPositionWorld.add( transformedNormalWorld.mul( normalBias ) ) ); const shadowCoord = this.setupShadowCoord( builder, shadowPosition ); // @@ -25469,6 +35271,13 @@ class ShadowNode extends ShadowBaseNode { } + /** + * The implementation performs the setup of the output node. An output is only + * produces if shadow mapping is globally enabled in the renderer. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {ShaderCallNodeInternal} The output node. + */ setup( builder ) { if ( builder.renderer.shadowMap.enabled === false ) return; @@ -25503,6 +35312,14 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Renders the shadow. The logic of this function could be included + * into {@link ShadowNode#updateShadow} however more specialized shadow + * nodes might require a custom shadow map rendering. By having a + * dedicated method, it's easier to overwrite the default behavior. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ renderShadow( frame ) { const { shadow, shadowMap, light } = this; @@ -25516,6 +35333,11 @@ class ShadowNode extends ShadowBaseNode { } + /** + * Updates the shadow. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ updateShadow( frame ) { const { shadowMap, light, shadow } = this; @@ -25526,22 +35348,27 @@ class ShadowNode extends ShadowBaseNode { const depthVersion = shadowMap.depthTexture.version; this._depthVersionCached = depthVersion; - const currentOverrideMaterial = scene.overrideMaterial; - - scene.overrideMaterial = getShadowMaterial( light ); - shadow.camera.layers.mask = camera.layers.mask; - const currentRenderTarget = renderer.getRenderTarget(); const currentRenderObjectFunction = renderer.getRenderObjectFunction(); + const currentMRT = renderer.getMRT(); + const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; - renderer.setMRT( null ); + _rendererState = resetRendererAndSceneState( renderer, scene, _rendererState ); + + scene.overrideMaterial = getShadowMaterial( light ); renderer.setRenderObjectFunction( ( object, scene, _camera, geometry, material, group, ...params ) => { if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { + if ( useVelocity ) { + + getDataFromObject( object ).useVelocity = true; + + } + object.onBeforeShadow( renderer, object, camera, shadow.camera, geometry, scene.overrideMaterial, group ); renderer.renderObject( object, scene, _camera, geometry, material, group, ...params ); @@ -25566,14 +35393,15 @@ class ShadowNode extends ShadowBaseNode { } - renderer.setRenderTarget( currentRenderTarget ); - - renderer.setMRT( currentMRT ); - - scene.overrideMaterial = currentOverrideMaterial; + restoreRendererAndSceneState( renderer, scene, _rendererState ); } + /** + * For VSM additional render passes are required. + * + * @param {Renderer} renderer - A reference to the current renderer. + */ vsmPass( renderer ) { const { shadow } = this; @@ -25582,15 +35410,18 @@ class ShadowNode extends ShadowBaseNode { this.vsmShadowMapHorizontal.setSize( shadow.mapSize.width, shadow.mapSize.height ); renderer.setRenderTarget( this.vsmShadowMapVertical ); - _quadMesh$1.material = this.vsmMaterialVertical; - _quadMesh$1.render( renderer ); + _quadMesh.material = this.vsmMaterialVertical; + _quadMesh.render( renderer ); renderer.setRenderTarget( this.vsmShadowMapHorizontal ); - _quadMesh$1.material = this.vsmMaterialHorizontal; - _quadMesh$1.render( renderer ); + _quadMesh.material = this.vsmMaterialHorizontal; + _quadMesh.render( renderer ); } + /** + * Frees the internal resources of this shadow node. + */ dispose() { this.shadowMap.dispose(); @@ -25620,6 +35451,11 @@ class ShadowNode extends ShadowBaseNode { } + /** + * The implementation performs the update of the shadow map if necessary. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ updateBefore( frame ) { const { shadow } = this; @@ -25642,6 +35478,14 @@ class ShadowNode extends ShadowBaseNode { } +/** + * TSL function for creating an instance of `ShadowNode`. + * + * @function + * @param {Light} light - The shadow casting light. + * @param {LightShadow} shadow - The light shadow. + * @return {ShadowNode} The created shadow node. + */ const shadow = ( light, shadow ) => nodeObject( new ShadowNode( light, shadow ) ); /** @@ -25669,7 +35513,7 @@ class AnalyticLightNode extends LightingNode { /** * The light source. * - * @type {Light} + * @type {Light?} * @default null */ this.light = light; @@ -25691,23 +35535,26 @@ class AnalyticLightNode extends LightingNode { /** * This property is used to retain a reference to the original value of {@link AnalyticLightNode#colorNode}. - * The final color node is represented by a differnt node when using shadows. + * The final color node is represented by a different node when using shadows. * - * @type {Node} + * @type {Node?} + * @default null */ this.baseColorNode = null; /** * Represents the light's shadow. * - * @type {ShadowNode} + * @type {ShadowNode?} + * @default null */ this.shadowNode = null; /** * Represents the light's shadow color. * - * @type {Node} + * @type {Node?} + * @default null */ this.shadowColorNode = null; @@ -25763,7 +35610,8 @@ class AnalyticLightNode extends LightingNode { /** * Setups the shadow for this light. This method is only executed if the light - * cast shadows and the current build object receives shadows. + * cast shadows and the current build object receives shadows. It incorporates + * shadows into the lighting computation. * * @param {NodeBuilder} builder - The current node builder. */ @@ -25808,7 +35656,7 @@ class AnalyticLightNode extends LightingNode { /** * Unlike most other nodes, lighting nodes do not return a output node in {@link Node#setup}. * The main purpose of lighting nodes is to configure the current {@link LightingModel} and/or - * invocate the respecitve interface methods. + * invocate the respective interface methods. * * @param {NodeBuilder} builder - The current node builder. */ @@ -25879,6 +35727,8 @@ const getDistanceAttenuation = /*@__PURE__*/ Fn( ( inputs ) => { } ); // validated +/** @module PointShadowNode **/ + const _clearColor$2 = /*@__PURE__*/ new Color(); // cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D @@ -26025,8 +35875,12 @@ const _viewport = /*@__PURE__*/ new Vector4(); const _viewportSize = /*@__PURE__*/ new Vector2(); const _shadowMapSize = /*@__PURE__*/ new Vector2(); -// +/** + * Represents the shadow implementation for point light nodes. + * + * @augments module:ShadowNode~ShadowNode + */ class PointShadowNode extends ShadowNode { static get type() { @@ -26035,30 +35889,69 @@ class PointShadowNode extends ShadowNode { } + /** + * Constructs a new point shadow node. + * + * @param {PointLight} light - The shadow casting point light. + * @param {PointLightShadow?} [shadow=null] - An optional point light shadow. + */ constructor( light, shadow = null ) { super( light, shadow ); } + /** + * Overwrites the default implementation to return point light shadow specific + * filtering functions. + * + * @param {Number} type - The shadow type. + * @return {Function} The filtering function. + */ getShadowFilterFn( type ) { return type === BasicShadowMap ? BasicPointShadowFilter : PointShadowFilter; } + /** + * Overwrites the default implementation so the unaltered shadow position is used. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Node} shadowPosition - A node representing the shadow position. + * @return {Node} The shadow coordinates. + */ setupShadowCoord( builder, shadowPosition ) { return shadowPosition; } + /** + * Overwrites the default implementation to only use point light specific + * shadow filter functions. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @param {Object} inputs - A configuration object that defines the shadow filtering. + * @param {Function} inputs.filterFn - This function defines the filtering type of the shadow map e.g. PCF. + * @param {Texture} inputs.shadowTexture - A reference to the shadow map's texture. + * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. + * @param {Node} inputs.shadowCoord - Shadow coordinates which are used to sample from the shadow map. + * @param {LightShadow} inputs.shadow - The light shadow. + * @return {Node} The result node of the shadow filtering. + */ setupShadowFilter( builder, { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } ) { return pointShadowFilter( { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } ); } + /** + * Overwrites the default implementation with point light specific + * rendering code. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ renderShadow( frame ) { const { shadow, shadowMap, light } = this; @@ -26117,6 +36010,14 @@ class PointShadowNode extends ShadowNode { } +/** + * TSL function for creating an instance of `PointShadowNode`. + * + * @function + * @param {PointLight} light - The shadow casting point light. + * @param {PointLightShadow?} [shadow=null] - An optional point light shadow. + * @return {PointShadowNode} The created point shadow node. + */ const pointShadow = ( light, shadow ) => nodeObject( new PointShadowNode( light, shadow ) ); const directPointLight = Fn( ( { color, lightViewPosition, cutoffDistance, decayExponent }, builder ) => { @@ -26232,7 +36133,7 @@ class PointLightNode extends AnalyticLightNode { * Creates a 2x2 checkerboard pattern that can be used as procedural texture data. * * @method - * @param {Node} uv - The uv coordinates. + * @param {Node} coord - The uv coordinates. * @return {Node} The result data. */ const checker = /*@__PURE__*/ Fn( ( [ coord = uv() ] ) => { @@ -26247,6 +36148,36 @@ const checker = /*@__PURE__*/ Fn( ( [ coord = uv() ] ) => { } ); +/** @module Shapes **/ + +/** + * Generates a circle based on the uv coordinates. + * + * @method + * @param {Node} coord - The uv to generate the circle. + * @return {Node} The circle shape. + */ +const shapeCircle = Fn( ( [ coord = uv() ], { renderer, material } ) => { + + const alpha = float( 1 ).toVar(); + const len2 = lengthSq( coord.mul( 2 ).sub( 1 ) ); + + if ( material.alphaToCoverage && 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(); + + } + + return alpha; + +} ); + // Three.js Transpiler // https://raw.githubusercontent.com/AcademySoftwareFoundation/MaterialX/main/libraries/stdlib/genglsl/lib/mx_noise.glsl @@ -27770,8 +37701,23 @@ const mx_fractal_noise_vec2 = ( position = uv(), octaves = 3, lacunarity = 2, di 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 ); -// https://devlog-martinsh.blogspot.com/2011/09/box-projected-cube-environment-mapping.html +/** @module getParallaxCorrectNormal **/ +/** + * This computes a parallax corrected normal which is used for box-projected cube mapping (BPCEM). + * + * Reference: {@link https://devlog-martinsh.blogspot.com/2011/09/box-projected-cube-environment-mapping.html} + * + * ```js + * const uvNode = getParallaxCorrectNormal( reflectVector, vec3( 200, 100, 100 ), vec3( 0, - 50, 0 ) ); + * material.envNode = pmremTexture( renderTarget.texture, uvNode ); + * ``` + * @function + * @param {Node} normal - The normal to correct. + * @param {Node} cubeSize - The cube size should reflect the size of the environment (BPCEM is usually applied in closed environments like rooms). + * @param {Node} cubePos - The cube position. + * @return {Node} The parallax corrected normal. + */ const getParallaxCorrectNormal = /*@__PURE__*/ Fn( ( [ normal, cubeSize, cubePos ] ) => { const nDir = normalize( normal ).toVar( 'nDir' ); @@ -27821,6 +37767,7 @@ var TSL = /*#__PURE__*/Object.freeze({ BRDF_Lambert: BRDF_Lambert, BasicShadowFilter: BasicShadowFilter, Break: Break, + Const: Const, Continue: Continue, DFGApprox: DFGApprox, D_GGX: D_GGX, @@ -27846,6 +37793,7 @@ var TSL = /*#__PURE__*/Object.freeze({ TBNViewMatrix: TBNViewMatrix, VSMShadowFilter: VSMShadowFilter, V_GGX_SmithCorrelated: V_GGX_SmithCorrelated, + Var: Var, abs: abs, acesFilmicToneMapping: acesFilmicToneMapping, acos: acos, @@ -27948,6 +37896,7 @@ var TSL = /*#__PURE__*/Object.freeze({ degrees: degrees, deltaTime: deltaTime, densityFog: densityFog, + densityFogFactor: densityFogFactor, depth: depth, depthPass: depthPass, difference: difference, @@ -27971,6 +37920,7 @@ var TSL = /*#__PURE__*/Object.freeze({ expression: expression, faceDirection: faceDirection, faceForward: faceForward, + faceforward: faceforward, float: float, floor: floor, fog: fog, @@ -27993,14 +37943,15 @@ var TSL = /*#__PURE__*/Object.freeze({ getShIrradianceAt: getShIrradianceAt, getTextureIndex: getTextureIndex, getViewPosition: getViewPosition, + globalId: globalId, glsl: glsl, glslFn: glslFn, grayscale: grayscale, greaterThan: greaterThan, greaterThanEqual: greaterThanEqual, hash: hash, - highPrecisionModelNormalViewMatrix: highPrecisionModelNormalViewMatrix, - highPrecisionModelViewMatrix: highPrecisionModelViewMatrix, + highpModelNormalViewMatrix: highpModelNormalViewMatrix, + highpModelViewMatrix: highpModelViewMatrix, hue: hue, instance: instance, instanceIndex: instanceIndex, @@ -28010,6 +37961,7 @@ var TSL = /*#__PURE__*/Object.freeze({ instancedMesh: instancedMesh, int: int, inverseSqrt: inverseSqrt, + inversesqrt: inversesqrt, invocationLocalIndex: invocationLocalIndex, invocationSubgroupIndex: invocationSubgroupIndex, ior: ior, @@ -28045,7 +37997,7 @@ var TSL = /*#__PURE__*/Object.freeze({ mat3: mat3, mat4: mat4, matcapUV: matcapUV, - materialAOMap: materialAOMap, + materialAO: materialAO, materialAlphaTest: materialAlphaTest, materialAnisotropy: materialAnisotropy, materialAnisotropyVector: materialAnisotropyVector, @@ -28070,7 +38022,7 @@ var TSL = /*#__PURE__*/Object.freeze({ materialMetalness: materialMetalness, materialNormal: materialNormal, materialOpacity: materialOpacity, - materialPointWidth: materialPointWidth, + materialPointSize: materialPointSize, materialReference: materialReference, materialReflectivity: materialReflectivity, materialRefractionRatio: materialRefractionRatio, @@ -28087,6 +38039,7 @@ var TSL = /*#__PURE__*/Object.freeze({ materialTransmission: materialTransmission, max: max$1, maxMipLevel: maxMipLevel, + mediumpModelViewMatrix: mediumpModelViewMatrix, metalness: metalness, min: min$1, mix: mix, @@ -28189,6 +38142,7 @@ var TSL = /*#__PURE__*/Object.freeze({ rand: rand, range: range, rangeFog: rangeFog, + rangeFogFactor: rangeFogFactor, reciprocal: reciprocal, reference: reference, referenceBuffer: referenceBuffer, @@ -28226,6 +38180,8 @@ var TSL = /*#__PURE__*/Object.freeze({ setCurrentStack: setCurrentStack, shaderStages: shaderStages, shadow: shadow, + shadowPositionWorld: shadowPositionWorld, + shapeCircle: shapeCircle, sharedUniformGroup: sharedUniformGroup, sheen: sheen, sheenRoughness: sheenRoughness, @@ -28316,6 +38272,7 @@ var TSL = /*#__PURE__*/Object.freeze({ velocity: velocity, vertexColor: vertexColor, vertexIndex: vertexIndex, + vertexStage: vertexStage, vibrance: vibrance, viewZToLogarithmicDepth: viewZToLogarithmicDepth, viewZToOrthographicDepth: viewZToOrthographicDepth, @@ -28344,17 +38301,50 @@ var TSL = /*#__PURE__*/Object.freeze({ const _clearColor$1 = /*@__PURE__*/ new Color4(); +/** + * This renderer module manages the background. + * + * @private + * @augments DataMap + */ class Background extends DataMap { + /** + * Constructs a new background management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + */ constructor( renderer, nodes ) { super(); + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; } + /** + * Updates the background for the given scene. Depending on how `Scene.background` + * or `Scene.backgroundNode` are configured, this method might configure a simple clear + * or add a mesh to the render list for rendering the background as a textured plane + * or skybox. + * + * @param {Scene} scene - The scene. + * @param {RenderList} renderList - The current render list. + * @param {RenderContext} renderContext - The current render context. + */ update( scene, renderList, renderContext ) { const renderer = this.renderer; @@ -28395,7 +38385,7 @@ class Background extends DataMap { getTextureLevel: () => backgroundBlurriness } ); - let viewProj = modelViewProjection(); + let viewProj = modelViewProjection; viewProj = viewProj.setZ( viewProj.w ); const nodeMaterial = new NodeMaterial(); @@ -28486,50 +38476,187 @@ class Background extends DataMap { let _id$6 = 0; +/** + * A bind group represents a collection of bindings and thus a collection + * or resources. Bind groups are assigned to pipelines to provide them + * with the required resources (like uniform buffers or textures). + * + * @private + */ class BindGroup { + /** + * Constructs a new bind group. + * + * @param {String} name - The bind group's name. + * @param {Array} bindings - An array of bindings. + * @param {Number} index - The group index. + * @param {Array} bindingsReference - An array of reference bindings. + */ constructor( name = '', bindings = [], index = 0, bindingsReference = [] ) { + /** + * The bind group's name. + * + * @type {String} + */ this.name = name; + + /** + * An array of bindings. + * + * @type {Array} + */ this.bindings = bindings; + + /** + * The group index. + * + * @type {Number} + */ this.index = index; + + /** + * An array of reference bindings. + * + * @type {Array} + */ this.bindingsReference = bindingsReference; + /** + * The group's ID. + * + * @type {Number} + */ this.id = _id$6 ++; } } +/** + * This module represents the state of a node builder after it was + * used to build the nodes for a render object. The state holds the + * results of the build for further processing in the renderer. + * + * Render objects with identical cache keys share the same node builder state. + * + * @private + */ class NodeBuilderState { + /** + * Constructs a new node builder state. + * + * @param {String?} vertexShader - The native vertex shader code. + * @param {String?} fragmentShader - The native fragment shader code. + * @param {String?} computeShader - The native compute shader code. + * @param {Array} nodeAttributes - An array of node attributes. + * @param {Array} bindings - An array of bind groups. + * @param {Array} updateNodes - An array of nodes that implement their `update()` method. + * @param {Array} updateBeforeNodes - An array of nodes that implement their `updateBefore()` method. + * @param {Array} updateAfterNodes - An array of nodes that implement their `updateAfter()` method. + * @param {NodeMaterialObserver} monitor - A node material observer. + * @param {Array} transforms - An array with transform attribute objects. Only relevant when using compute shaders with WebGL 2. + */ constructor( vertexShader, fragmentShader, computeShader, nodeAttributes, bindings, updateNodes, updateBeforeNodes, updateAfterNodes, monitor, transforms = [] ) { + /** + * The native vertex shader code. + * + * @type {String} + */ this.vertexShader = vertexShader; + + /** + * The native fragment shader code. + * + * @type {String} + */ this.fragmentShader = fragmentShader; + + /** + * The native compute shader code. + * + * @type {String} + */ this.computeShader = computeShader; + + /** + * An array with transform attribute objects. + * Only relevant when using compute shaders with WebGL 2. + * + * @type {Array} + */ this.transforms = transforms; + /** + * An array of node attributes representing + * the attributes of the shaders. + * + * @type {Array} + */ this.nodeAttributes = nodeAttributes; + + /** + * An array of bind groups representing the uniform or storage + * buffers, texture or samplers of the shader. + * + * @type {Array} + */ this.bindings = bindings; + /** + * An array of nodes that implement their `update()` method. + * + * @type {Array} + */ this.updateNodes = updateNodes; + + /** + * An array of nodes that implement their `updateBefore()` method. + * + * @type {Array} + */ this.updateBeforeNodes = updateBeforeNodes; + + /** + * An array of nodes that implement their `updateAfter()` method. + * + * @type {Array} + */ this.updateAfterNodes = updateAfterNodes; + /** + * A node material observer. + * + * @type {NodeMaterialObserver} + */ this.monitor = monitor; + /** + * How often this state is used by render objects. + * + * @type {Number} + */ this.usedTimes = 0; } + /** + * This method is used to create a array of bind groups based + * on the existing bind groups of this state. Shared groups are + * not cloned. + * + * @return {Array} A array of bind groups. + */ createBindings() { const bindings = []; for ( const instanceGroup of this.bindings ) { - const shared = instanceGroup.bindings[ 0 ].groupNode.shared; + const shared = instanceGroup.bindings[ 0 ].groupNode.shared; // TODO: Is it safe to always check the first binding in the group? if ( shared !== true ) { @@ -28711,8 +38838,9 @@ class NodeVar { * * @param {String} name - The name of the variable. * @param {String} type - The type of the variable. + * @param {Boolean} [readOnly=false] - The read-only flag. */ - constructor( name, type ) { + constructor( name, type, readOnly = false ) { /** * This flag can be used for type testing. @@ -28737,6 +38865,13 @@ class NodeVar { */ this.type = type; + /** + * The read-only flag. + * + * @type {boolean} + */ + this.readOnly = readOnly; + } } @@ -28965,26 +39100,79 @@ class StructTypeNode extends Node { } +/** + * Abstract base class for uniforms. + * + * @abstract + * @private + */ class Uniform { + /** + * Constructs a new uniform. + * + * @param {String} name - The uniform's name. + * @param {Any} value - The uniform's value. + */ constructor( name, value ) { + /** + * The uniform's name. + * + * @type {String} + */ this.name = name; + + /** + * The uniform's value. + * + * @type {Any} + */ this.value = value; - this.boundary = 0; // used to build the uniform buffer according to the STD140 layout + /** + * Used to build the uniform buffer according to the STD140 layout. + * Derived uniforms will set this property to a data type specific + * value. + * + * @type {Number} + */ + this.boundary = 0; + + /** + * The item size. Derived uniforms will set this property to a data + * type specific value. + * + * @type {Number} + */ this.itemSize = 0; - this.offset = 0; // this property is set by WebGPUUniformsGroup and marks the start position in the uniform buffer + /** + * This property is set by {@link UniformsGroup} and marks + * the start position in the uniform buffer. + * + * @type {Number} + */ + this.offset = 0; } + /** + * Sets the uniform's value. + * + * @param {Any} value - The value to set. + */ setValue( value ) { this.value = value; } + /** + * Returns the uniform's value. + * + * @return {Any} The value. + */ getValue() { return this.value; @@ -28993,12 +39181,31 @@ class Uniform { } +/** + * Represents a Number uniform. + * + * @private + * @augments Uniform + */ class NumberUniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Number} value - The uniform's value. + */ constructor( name, value = 0 ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isNumberUniform = true; this.boundary = 4; @@ -29008,12 +39215,31 @@ class NumberUniform extends Uniform { } +/** + * Represents a Vector2 uniform. + * + * @private + * @augments Uniform + */ class Vector2Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Vector2} value - The uniform's value. + */ constructor( name, value = new Vector2() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVector2Uniform = true; this.boundary = 8; @@ -29023,12 +39249,31 @@ class Vector2Uniform extends Uniform { } +/** + * Represents a Vector3 uniform. + * + * @private + * @augments Uniform + */ class Vector3Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Vector3} value - The uniform's value. + */ constructor( name, value = new Vector3() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVector3Uniform = true; this.boundary = 16; @@ -29038,12 +39283,31 @@ class Vector3Uniform extends Uniform { } +/** + * Represents a Vector4 uniform. + * + * @private + * @augments Uniform + */ class Vector4Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Vector4} value - The uniform's value. + */ constructor( name, value = new Vector4() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVector4Uniform = true; this.boundary = 16; @@ -29053,12 +39317,31 @@ class Vector4Uniform extends Uniform { } +/** + * Represents a Color uniform. + * + * @private + * @augments Uniform + */ class ColorUniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Color} value - The uniform's value. + */ constructor( name, value = new Color() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isColorUniform = true; this.boundary = 16; @@ -29068,12 +39351,31 @@ class ColorUniform extends Uniform { } +/** + * Represents a Matrix3 uniform. + * + * @private + * @augments Uniform + */ class Matrix3Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Matrix3} value - The uniform's value. + */ constructor( name, value = new Matrix3() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMatrix3Uniform = true; this.boundary = 48; @@ -29083,12 +39385,31 @@ class Matrix3Uniform extends Uniform { } +/** + * Represents a Matrix4 uniform. + * + * @private + * @augments Uniform + */ class Matrix4Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Matrix4} value - The uniform's value. + */ constructor( name, value = new Matrix4() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMatrix4Uniform = true; this.boundary = 64; @@ -29098,22 +39419,49 @@ class Matrix4Uniform extends Uniform { } +/** + * A special form of Number uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments NumberUniform + */ class NumberNodeUniform extends NumberUniform { + /** + * Constructs a new node-based Number uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Number} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29122,22 +39470,49 @@ class NumberNodeUniform extends NumberUniform { } +/** + * A special form of Vector2 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Vector2Uniform + */ class Vector2NodeUniform extends Vector2Uniform { + /** + * Constructs a new node-based Vector2 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Vector2} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29146,22 +39521,49 @@ class Vector2NodeUniform extends Vector2Uniform { } +/** + * A special form of Vector3 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Vector3Uniform + */ class Vector3NodeUniform extends Vector3Uniform { + /** + * Constructs a new node-based Vector3 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Vector3} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29170,22 +39572,49 @@ class Vector3NodeUniform extends Vector3Uniform { } +/** + * A special form of Vector4 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Vector4Uniform + */ class Vector4NodeUniform extends Vector4Uniform { + /** + * Constructs a new node-based Vector4 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Vector4} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29194,22 +39623,49 @@ class Vector4NodeUniform extends Vector4Uniform { } +/** + * A special form of Color uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments ColorUniform + */ class ColorNodeUniform extends ColorUniform { + /** + * Constructs a new node-based Color uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Color} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29218,22 +39674,49 @@ class ColorNodeUniform extends ColorUniform { } +/** + * A special form of Matrix3 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Matrix3Uniform + */ class Matrix3NodeUniform extends Matrix3Uniform { + /** + * Constructs a new node-based Matrix3 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Matrix3} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29242,22 +39725,49 @@ class Matrix3NodeUniform extends Matrix3Uniform { } +/** + * A special form of Matrix4 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Matrix4Uniform + */ class Matrix4NodeUniform extends Matrix4Uniform { + /** + * Constructs a new node-based Matrix4 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Matrix4} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -29370,6 +39880,7 @@ class PMREMGenerator { * @param {Number} [far=100] - The far plane distance. * @param {RenderTarget?} [renderTarget=null] - The render target to use. * @return {RenderTarget} The resulting PMREM. + * @see fromSceneAsync */ fromScene( scene, sigma = 0, near = 0.1, far = 100, renderTarget = null ) { @@ -29410,6 +39921,21 @@ class PMREMGenerator { } + /** + * 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). + * + * @param {Scene} scene - The scene to be captured. + * @param {Number} [sigma=0] - The blur radius in radians. + * @param {Number} [near=0.1] - The near plane distance. + * @param {Number} [far=100] - The far plane distance. + * @param {RenderTarget?} [renderTarget=null] - The render target to use. + * @return {Promise} The resulting PMREM. + * @see fromScene + */ async fromSceneAsync( scene, sigma = 0, near = 0.1, far = 100, renderTarget = null ) { if ( this._hasInitialized === false ) await this._renderer.init(); @@ -29426,6 +39952,7 @@ class PMREMGenerator { * @param {Texture} equirectangular - The equirectangular texture to be converted. * @param {RenderTarget?} [renderTarget=null] - The render target to use. * @return {RenderTarget} The resulting PMREM. + * @see fromEquirectangularAsync */ fromEquirectangular( equirectangular, renderTarget = null ) { @@ -29447,6 +39974,16 @@ class PMREMGenerator { } + /** + * 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. + * + * @param {Texture} equirectangular - The equirectangular texture to be converted. + * @param {RenderTarget?} [renderTarget=null] - The render target to use. + * @return {Promise} The resulting PMREM. + * @see fromEquirectangular + */ async fromEquirectangularAsync( equirectangular, renderTarget = null ) { if ( this._hasInitialized === false ) await this._renderer.init(); @@ -29463,6 +40000,7 @@ class PMREMGenerator { * @param {Texture} cubemap - The cubemap texture to be converted. * @param {RenderTarget?} [renderTarget=null] - The render target to use. * @return {RenderTarget} The resulting PMREM. + * @see fromCubemapAsync */ fromCubemap( cubemap, renderTarget = null ) { @@ -29484,6 +40022,16 @@ class PMREMGenerator { } + /** + * Generates a PMREM from an cubemap texture, which can be either LDR + * or HDR. The ideal input cube size is 256 x 256, + * with the 256 x 256 cubemap output. + * + * @param {Texture} cubemap - The cubemap texture to be converted. + * @param {RenderTarget?} [renderTarget=null] - The render target to use. + * @return {Promise} The resulting PMREM. + * @see fromCubemap + */ async fromCubemapAsync( cubemap, renderTarget = null ) { if ( this._hasInitialized === false ) await this._renderer.init(); @@ -29495,6 +40043,8 @@ class PMREMGenerator { /** * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during * your texture's network fetch for increased concurrency. + * + * @returns {Promise} */ async compileCubemapShader() { @@ -29510,6 +40060,8 @@ class PMREMGenerator { /** * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during * your texture's network fetch for increased concurrency. + * + * @returns {Promise} */ async compileEquirectangularShader() { @@ -30563,6 +41115,15 @@ class NodeBuilder { } + /** + * Returns the output struct name which is required by + * {@link module:OutputStructNode}. + * + * @abstract + * @return {String} The name of the output struct. + */ + getOutputStructName() {} + /** * Returns a bind group for the given group name and binding. * @@ -30744,6 +41305,7 @@ class NodeBuilder { /** * It is used to add Nodes that will be used as FRAME and RENDER events, * and need to follow a certain sequence in the calls to work correctly. + * This function should be called after 'setup()' in the 'build()' process to ensure that the child nodes are processed first. * * @param {Node} node - The node to add. */ @@ -31097,10 +41659,11 @@ class NodeBuilder { * @param {Texture} texture - The texture. * @param {String} textureProperty - The texture property name. * @param {String} uvSnippet - Snippet defining the texture coordinates. + * @param {String?} depthSnippet - Snippet defining the 0-based texture array index to sample. * @param {String} levelSnippet - Snippet defining the mip level. * @return {String} The generated shader string. */ - generateTextureLod( /* texture, textureProperty, uvSnippet, levelSnippet */ ) { + generateTextureLod( /* texture, textureProperty, uvSnippet, depthSnippet, levelSnippet */ ) { console.warn( 'Abstract function.' ); @@ -31274,11 +41837,11 @@ class NodeBuilder { } /** - * Whether the given texture needs a conversion to working color space. + * Checks if the given texture requires a manual conversion to the working color space. * * @abstract * @param {Texture} texture - The texture to check. - * @return {Boolean} Whether a color space conversion is required or not. + * @return {Boolean} Whether the given texture requires a conversion to working color space or not. */ needsToWorkingColorSpace( /*texture*/ ) { @@ -31657,9 +42220,11 @@ class NodeBuilder { * @param {String?} name - The variable's name. * @param {String} [type=node.getNodeType( this )] - The variable's type. * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage. + * @param {Boolean} [readOnly=false] - Whether the variable is read-only or not. + * * @return {NodeVar} The node variable. */ - getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage ) { + getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage, readOnly = false ) { const nodeData = this.getDataFromNode( node, shaderStage ); @@ -31667,13 +42232,26 @@ class NodeBuilder { if ( nodeVar === undefined ) { + const idNS = readOnly ? '_const' : '_var'; + const vars = this.vars[ shaderStage ] || ( this.vars[ shaderStage ] = [] ); + const id = this.vars[ idNS ] || ( this.vars[ idNS ] = 0 ); - if ( name === null ) name = 'nodeVar' + vars.length; + if ( name === null ) { - nodeVar = new NodeVar( name, type ); + name = ( readOnly ? 'nodeConst' : 'nodeVar' ) + id; - vars.push( nodeVar ); + this.vars[ idNS ] ++; + + } + + nodeVar = new NodeVar( name, type, readOnly ); + + if ( ! readOnly ) { + + vars.push( nodeVar ); + + } nodeData.variable = nodeVar; @@ -31683,6 +42261,35 @@ class NodeBuilder { } + /** + * Returns whether a Node or its flow is deterministic, useful for use in `const`. + * + * @param {Node} node - The varying node. + * @return {Boolean} Returns true if deterministic. + */ + isDeterministic( node ) { + + if ( node.isMathNode ) { + + return this.isDeterministic( node.aNode ) && + ( node.bNode ? this.isDeterministic( node.bNode ) : true ) && + ( node.cNode ? this.isDeterministic( node.cNode ) : true ); + + } else if ( node.isOperatorNode ) { + + return this.isDeterministic( node.aNode ) && + ( node.bNode ? this.isDeterministic( node.bNode ) : true ); + + } else if ( node.isConstNode ) { + + return true; + + } + + return false; + + } + /** * Returns an instance of {@link NodeVarying} for the given varying node. * @@ -32478,6 +43085,13 @@ class NodeBuilder { // deprecated + /** + * @function + * @deprecated since r168. Use `new NodeMaterial()` instead, with targeted node material name. + * + * @param {String} [type='NodeMaterial'] - The node material type. + * @throws {Error} + */ createNodeMaterial( type = 'NodeMaterial' ) { // @deprecated, r168 throw new Error( `THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${ type }() instead.` ); @@ -33043,14 +43657,14 @@ class SpotLightNode extends AnalyticLightNode { super( light ); /** - * Uniform node representing the cone cosinus. + * Uniform node representing the cone cosine. * * @type {UniformNode} */ this.coneCosNode = uniform( 0 ).setGroup( renderGroup ); /** - * Uniform node representing the penumbra cosinus. + * Uniform node representing the penumbra cosine. * * @type {UniformNode} */ @@ -33643,29 +44257,93 @@ class GLSLNodeParser extends NodeParser { } -const outputNodeMap = new WeakMap(); +const _outputNodeMap = new WeakMap(); +const _chainKeys$2 = []; +const _cacheKeyValues = []; +/** + * This renderer module manages node-related objects and is the + * primary interface between the renderer and the node system. + * + * @private + * @augments DataMap + */ class Nodes extends DataMap { + /** + * Constructs a new nodes management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Backend} backend - The renderer's backend. + */ constructor( renderer, backend ) { super(); + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * The node frame. + * + * @type {Renderer} + */ this.nodeFrame = new NodeFrame(); + + /** + * A cache for managing node builder states. + * + * @type {Map} + */ this.nodeBuilderCache = new Map(); + + /** + * A cache for managing data cache key data. + * + * @type {ChainMap} + */ this.callHashCache = new ChainMap(); + + /** + * A cache for managing node uniforms group data. + * + * @type {ChainMap} + */ this.groupsData = new ChainMap(); + /** + * A cache for managing node objects of + * scene properties like fog or environments. + * + * @type {Object} + */ + this.cacheLib = {}; + } + /** + * Returns `true` if the given node uniforms group must be updated or not. + * + * @param {NodeUniformsGroup} nodeUniformsGroup - The node uniforms group. + * @return {Boolean} Whether the node uniforms group requires an update or not. + */ updateGroup( nodeUniformsGroup ) { const groupNode = nodeUniformsGroup.groupNode; const name = groupNode.name; - // objectGroup is every updated + // objectGroup is always updated if ( name === objectGroup.name ) return true; @@ -33709,10 +44387,13 @@ class Nodes extends DataMap { // other groups are updated just when groupNode.needsUpdate is true - const groupChain = [ groupNode, nodeUniformsGroup ]; + _chainKeys$2[ 0 ] = groupNode; + _chainKeys$2[ 1 ] = nodeUniformsGroup; - let groupData = this.groupsData.get( groupChain ); - if ( groupData === undefined ) this.groupsData.set( groupChain, groupData = {} ); + let groupData = this.groupsData.get( _chainKeys$2 ); + if ( groupData === undefined ) this.groupsData.set( _chainKeys$2, groupData = {} ); + + _chainKeys$2.length = 0; if ( groupData.version !== groupNode.version ) { @@ -33726,12 +44407,24 @@ class Nodes extends DataMap { } + /** + * Returns the cache key for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Number} The cache key. + */ getForRenderCacheKey( renderObject ) { return renderObject.initialCacheKey; } + /** + * Returns a node builder state for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {NodeBuilderState} The node builder state. + */ getForRender( renderObject ) { const renderObjectData = this.get( renderObject ); @@ -33775,6 +44468,12 @@ class Nodes extends DataMap { } + /** + * Deletes the given object from the internal data map + * + * @param {Any} object - The object to delete. + * @return {Object?} The deleted dictionary. + */ delete( object ) { if ( object.isRenderObject ) { @@ -33794,6 +44493,12 @@ class Nodes extends DataMap { } + /** + * Returns a node builder state for the given compute node. + * + * @param {Node} computeNode - The compute node. + * @return {NodeBuilderState} The node builder state. + */ getForCompute( computeNode ) { const computeData = this.get( computeNode ); @@ -33815,6 +44520,13 @@ class Nodes extends DataMap { } + /** + * Creates a node builder state for the given node builder. + * + * @private + * @param {NodeBuilder} nodeBuilder - The node builder. + * @return {NodeBuilderState} The node builder state. + */ _createNodeBuilderState( nodeBuilder ) { return new NodeBuilderState( @@ -33832,71 +44544,149 @@ class Nodes extends DataMap { } + /** + * Returns an environment node for the current configured + * scene environment. + * + * @param {Scene} scene - The scene. + * @return {Node} A node representing the current scene environment. + */ getEnvironmentNode( scene ) { - return scene.environmentNode || this.get( scene ).environmentNode || null; + this.updateEnvironment( scene ); + + let environmentNode = null; + + if ( scene.environmentNode && scene.environmentNode.isNode ) { + + environmentNode = scene.environmentNode; + + } else { + + const sceneData = this.get( scene ); + + if ( sceneData.environmentNode ) { + + environmentNode = sceneData.environmentNode; + + } + + } + + return environmentNode; } + /** + * Returns a background node for the current configured + * scene background. + * + * @param {Scene} scene - The scene. + * @return {Node} A node representing the current scene background. + */ getBackgroundNode( scene ) { - return scene.backgroundNode || this.get( scene ).backgroundNode || null; + this.updateBackground( scene ); + + let backgroundNode = null; + + if ( scene.backgroundNode && scene.backgroundNode.isNode ) { + + backgroundNode = scene.backgroundNode; + + } else { + + const sceneData = this.get( scene ); + + if ( sceneData.backgroundNode ) { + + backgroundNode = sceneData.backgroundNode; + + } + + } + + return backgroundNode; } + /** + * Returns a fog node for the current configured scene fog. + * + * @param {Scene} scene - The scene. + * @return {Node} A node representing the current scene fog. + */ getFogNode( scene ) { + this.updateFog( scene ); + return scene.fogNode || this.get( scene ).fogNode || null; } + /** + * Returns a cache key for the given scene and lights node. + * This key is used by `RenderObject` as a part of the dynamic + * cache key (a key that must be checked every time the render + * objects is drawn). + * + * @param {Scene} scene - The scene. + * @param {LightsNode} lightsNode - The lights node. + * @return {Number} The cache key. + */ getCacheKey( scene, lightsNode ) { - const chain = [ scene, lightsNode ]; + _chainKeys$2[ 0 ] = scene; + _chainKeys$2[ 1 ] = lightsNode; + const callId = this.renderer.info.calls; - let cacheKeyData = this.callHashCache.get( chain ); + const cacheKeyData = this.callHashCache.get( _chainKeys$2 ) || {}; - if ( cacheKeyData === undefined || cacheKeyData.callId !== callId ) { + if ( cacheKeyData.callId !== callId ) { const environmentNode = this.getEnvironmentNode( scene ); const fogNode = this.getFogNode( scene ); - const values = []; + if ( lightsNode ) _cacheKeyValues.push( lightsNode.getCacheKey( true ) ); + if ( environmentNode ) _cacheKeyValues.push( environmentNode.getCacheKey() ); + if ( fogNode ) _cacheKeyValues.push( fogNode.getCacheKey() ); - if ( lightsNode ) values.push( lightsNode.getCacheKey( true ) ); - if ( environmentNode ) values.push( environmentNode.getCacheKey() ); - if ( fogNode ) values.push( fogNode.getCacheKey() ); + _cacheKeyValues.push( this.renderer.shadowMap.enabled ? 1 : 0 ); - values.push( this.renderer.shadowMap.enabled ? 1 : 0 ); + cacheKeyData.callId = callId; + cacheKeyData.cacheKey = hashArray( _cacheKeyValues ); - cacheKeyData = { - callId, - cacheKey: hashArray( values ) - }; + this.callHashCache.set( _chainKeys$2, cacheKeyData ); - this.callHashCache.set( chain, cacheKeyData ); + _cacheKeyValues.length = 0; } - return cacheKeyData.cacheKey; - - } - - updateScene( scene ) { + _chainKeys$2.length = 0; - this.updateEnvironment( scene ); - this.updateFog( scene ); - this.updateBackground( scene ); + return cacheKeyData.cacheKey; } + /** + * A boolean that indicates whether tone mapping should be enabled + * or not. + * + * @type {Boolean} + */ get isToneMappingState() { return this.renderer.getRenderTarget() ? false : true; } + /** + * If a scene background is configured, this method makes sure to + * represent the background with a corresponding node-based implementation. + * + * @param {Scene} scene - The scene. + */ updateBackground( scene ) { const sceneData = this.get( scene ); @@ -33908,41 +44698,43 @@ class Nodes extends DataMap { if ( sceneData.background !== background || forceUpdate ) { - let backgroundNode = null; + const backgroundNode = this.getCacheNode( 'background', background, () => { - if ( background.isCubeTexture === true || ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping || background.mapping === CubeUVReflectionMapping ) ) { + if ( background.isCubeTexture === true || ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping || background.mapping === CubeUVReflectionMapping ) ) { - if ( scene.backgroundBlurriness > 0 || background.mapping === CubeUVReflectionMapping ) { + if ( scene.backgroundBlurriness > 0 || background.mapping === CubeUVReflectionMapping ) { - backgroundNode = pmremTexture( background ); + return pmremTexture( background ); - } else { + } else { - let envMap; + let envMap; - if ( background.isCubeTexture === true ) { + if ( background.isCubeTexture === true ) { - envMap = cubeTexture( background ); + envMap = cubeTexture( background ); - } else { + } else { - envMap = texture( background ); + envMap = texture( background ); - } + } - backgroundNode = cubeMapNode( envMap ); + return cubeMapNode( envMap ); - } + } - } else if ( background.isTexture === true ) { + } else if ( background.isTexture === true ) { - backgroundNode = texture( background, screenUV.flipY() ).setUpdateMatrix( true ); + return texture( background, screenUV.flipY() ).setUpdateMatrix( true ); - } else if ( background.isColor !== true ) { + } else if ( background.isColor !== true ) { - console.error( 'WebGPUNodes: Unsupported background configuration.', background ); + console.error( 'WebGPUNodes: Unsupported background configuration.', background ); - } + } + + }, forceUpdate ); sceneData.backgroundNode = backgroundNode; sceneData.background = background; @@ -33959,40 +44751,75 @@ class Nodes extends DataMap { } + /** + * This method is part of the caching of nodes which are used to represents the + * scene's background, fog or environment. + * + * @param {String} type - The type of object to cache. + * @param {Object} object - The object. + * @param {Function} callback - A callback that produces a node representation for the given object. + * @param {Boolean} [forceUpdate=false] - Whether an update should be enforced or not. + * @return {Node} The node representation. + */ + getCacheNode( type, object, callback, forceUpdate = false ) { + + const nodeCache = this.cacheLib[ type ] || ( this.cacheLib[ type ] = new WeakMap() ); + + let node = nodeCache.get( object ); + + if ( node === undefined || forceUpdate ) { + + node = callback(); + nodeCache.set( object, node ); + + } + + return node; + + } + + /** + * If a scene fog is configured, this method makes sure to + * represent the fog with a corresponding node-based implementation. + * + * @param {Scene} scene - The scene. + */ updateFog( scene ) { const sceneData = this.get( scene ); - const fog = scene.fog; + const sceneFog = scene.fog; - if ( fog ) { + if ( sceneFog ) { - if ( sceneData.fog !== fog ) { + if ( sceneData.fog !== sceneFog ) { - let fogNode = null; + const fogNode = this.getCacheNode( 'fog', sceneFog, () => { - if ( fog.isFogExp2 ) { + if ( sceneFog.isFogExp2 ) { - const color = reference( 'color', 'color', fog ).setGroup( renderGroup ); - const density = reference( 'density', 'float', fog ).setGroup( renderGroup ); + const color = reference( 'color', 'color', sceneFog ).setGroup( renderGroup ); + const density = reference( 'density', 'float', sceneFog ).setGroup( renderGroup ); - fogNode = densityFog( color, density ); + return fog( color, densityFogFactor( density ) ); - } else if ( fog.isFog ) { + } else if ( sceneFog.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 ); + const color = reference( 'color', 'color', sceneFog ).setGroup( renderGroup ); + const near = reference( 'near', 'float', sceneFog ).setGroup( renderGroup ); + const far = reference( 'far', 'float', sceneFog ).setGroup( renderGroup ); - fogNode = rangeFog( color, near, far ); + return fog( color, rangeFogFactor( near, far ) ); - } else { + } else { - console.error( 'WebGPUNodes: Unsupported fog configuration.', fog ); + console.error( 'THREE.Renderer: Unsupported fog configuration.', sceneFog ); - } + } + + } ); sceneData.fogNode = fogNode; - sceneData.fog = fog; + sceneData.fog = sceneFog; } @@ -34005,6 +44832,12 @@ class Nodes extends DataMap { } + /** + * If a scene environment is configured, this method makes sure to + * represent the environment with a corresponding node-based implementation. + * + * @param {Scene} scene - The scene. + */ updateEnvironment( scene ) { const sceneData = this.get( scene ); @@ -34014,21 +44847,23 @@ class Nodes extends DataMap { if ( sceneData.environment !== environment ) { - let environmentNode = null; + const environmentNode = this.getCacheNode( 'environment', environment, () => { - if ( environment.isCubeTexture === true ) { + if ( environment.isCubeTexture === true ) { - environmentNode = cubeTexture( environment ); + return cubeTexture( environment ); - } else if ( environment.isTexture === true ) { + } else if ( environment.isTexture === true ) { - environmentNode = texture( environment ); + return texture( environment ); - } else { + } else { - console.error( 'Nodes: Unsupported environment configuration.', environment ); + console.error( 'Nodes: Unsupported environment configuration.', environment ); - } + } + + } ); sceneData.environmentNode = environmentNode; sceneData.environment = environment; @@ -34063,6 +44898,11 @@ class Nodes extends DataMap { } + /** + * Returns the current output cache key. + * + * @return {String} The output cache key. + */ getOutputCacheKey() { const renderer = this.renderer; @@ -34071,27 +44911,47 @@ class Nodes extends DataMap { } + /** + * Checks if the output configuration (tone mapping and color space) for + * the given target has changed. + * + * @param {Texture} outputTarget - The output target. + * @return {Boolean} Whether the output configuration has changed or not. + */ hasOutputChange( outputTarget ) { - const cacheKey = outputNodeMap.get( outputTarget ); + const cacheKey = _outputNodeMap.get( outputTarget ); return cacheKey !== this.getOutputCacheKey(); } - getOutputNode( outputTexture ) { + /** + * Returns a node that represents the output configuration (tone mapping and + * color space) for the current target. + * + * @param {Texture} outputTarget - The output target. + * @return {Node} The output node. + */ + getOutputNode( outputTarget ) { const renderer = this.renderer; const cacheKey = this.getOutputCacheKey(); - const output = texture( outputTexture, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); + const output = texture( outputTarget, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); - outputNodeMap.set( outputTexture, cacheKey ); + _outputNodeMap.set( outputTarget, cacheKey ); return output; } + /** + * Triggers the call of `updateBefore()` methods + * for all nodes of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateBefore( renderObject ) { const nodeBuilder = renderObject.getNodeBuilderState(); @@ -34106,6 +44966,12 @@ class Nodes extends DataMap { } + /** + * Triggers the call of `updateAfter()` methods + * for all nodes of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateAfter( renderObject ) { const nodeBuilder = renderObject.getNodeBuilderState(); @@ -34120,6 +44986,12 @@ class Nodes extends DataMap { } + /** + * Triggers the call of `update()` methods + * for all nodes of the given compute node. + * + * @param {Node} computeNode - The compute node. + */ updateForCompute( computeNode ) { const nodeFrame = this.getNodeFrame(); @@ -34133,6 +45005,12 @@ class Nodes extends DataMap { } + /** + * Triggers the call of `update()` methods + * for all nodes of the given compute node. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { const nodeFrame = this.getNodeFrameForRender( renderObject ); @@ -34146,6 +45024,12 @@ class Nodes extends DataMap { } + /** + * Returns `true` if the given render object requires a refresh. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object requires a refresh or not. + */ needsRefresh( renderObject ) { const nodeFrame = this.getNodeFrameForRender( renderObject ); @@ -34155,12 +45039,16 @@ class Nodes extends DataMap { } + /** + * Frees the internal resources. + */ dispose() { super.dispose(); this.nodeFrame = new NodeFrame(); this.nodeBuilderCache = new Map(); + this.cacheLib = {}; } @@ -34168,41 +45056,110 @@ class Nodes extends DataMap { const _plane = /*@__PURE__*/ new Plane(); +/** + * Represents the state that is used to perform clipping via clipping planes. + * There is a default clipping context for each render context. When the + * scene holds instances of `ClippingGroup`, there will be a context for each + * group. + * + * @private + */ class ClippingContext { + /** + * Constructs a new clipping context. + * + * @param {ClippingContext?} [parentContext=null] - A reference to the parent clipping context. + */ constructor( parentContext = null ) { + /** + * The clipping context's version. + * + * @type {Number} + * @readonly + */ this.version = 0; + /** + * Whether the intersection of the clipping planes is used to clip objects, rather than their union. + * + * @type {Boolean?} + * @default null + */ this.clipIntersection = null; + + /** + * The clipping context's cache key. + * + * @type {String} + */ this.cacheKey = ''; + /** + * Whether the shadow pass is active or not. + * + * @type {Boolean} + * @default false + */ + this.shadowPass = false; + + /** + * The view normal matrix. + * + * @type {Matrix3} + */ + this.viewNormalMatrix = new Matrix3(); - if ( parentContext === null ) { + /** + * Internal cache for maintaining clipping contexts. + * + * @type {WeakMap} + */ + this.clippingGroupContexts = new WeakMap(); - this.intersectionPlanes = []; - this.unionPlanes = []; + /** + * The intersection planes. + * + * @type {Array} + */ + this.intersectionPlanes = []; - this.viewNormalMatrix = new Matrix3(); - this.clippingGroupContexts = new WeakMap(); + /** + * The intersection planes. + * + * @type {Array} + */ + this.unionPlanes = []; - this.shadowPass = false; + /** + * The version of the clipping context's parent context. + * + * @type {Number?} + * @readonly + */ + this.parentVersion = null; - } else { + if ( parentContext !== null ) { this.viewNormalMatrix = parentContext.viewNormalMatrix; this.clippingGroupContexts = parentContext.clippingGroupContexts; this.shadowPass = parentContext.shadowPass; - this.viewMatrix = parentContext.viewMatrix; } - this.parentVersion = null; - } + /** + * Projects the given source clipping planes and writes the result into the + * destination array. + * + * @param {Array} source - The source clipping planes. + * @param {Array} destination - The destination. + * @param {Number} offset - The offset. + */ projectPlanes( source, destination, offset ) { const l = source.length; @@ -34223,15 +45180,27 @@ class ClippingContext { } + /** + * Updates the root clipping context of a scene. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera that is used to render the scene. + */ updateGlobal( scene, camera ) { - this.shadowPass = ( scene.overrideMaterial !== null && scene.overrideMaterial.isShadowNodeMaterial ); + this.shadowPass = ( scene.overrideMaterial !== null && scene.overrideMaterial.isShadowPassMaterial ); this.viewMatrix = camera.matrixWorldInverse; this.viewNormalMatrix.getNormalMatrix( this.viewMatrix ); } + /** + * Updates the clipping context. + * + * @param {ClippingContext} parentContext - The parent context. + * @param {ClippingGroup} clippingGroup - The clipping group this context belongs to. + */ update( parentContext, clippingGroup ) { let update = false; @@ -34303,6 +45272,12 @@ class ClippingContext { } + /** + * Returns a clipping context for the given clipping group. + * + * @param {ClippingGroup} clippingGroup - The clipping group. + * @return {ClippingContext} The clipping context. + */ getGroupContext( clippingGroup ) { if ( this.shadowPass && ! clippingGroup.clipShadows ) return this; @@ -34322,6 +45297,12 @@ class ClippingContext { } + /** + * The count of union clipping planes. + * + * @type {Number} + * @readonly + */ get unionClippingCount() { return this.unionPlanes.length; @@ -34330,67 +45311,141 @@ class ClippingContext { } +/** + * This module is used to represent render bundles inside the renderer + * for further processing. + * + * @private + */ class RenderBundle { - constructor( scene, camera ) { + /** + * Constructs a new bundle group. + * + * @param {BundleGroup} bundleGroup - The bundle group. + * @param {Camera} camera - The camera the bundle group is rendered with. + */ + constructor( bundleGroup, camera ) { - this.scene = scene; + this.bundleGroup = bundleGroup; this.camera = camera; } - clone() { - - return Object.assign( new this.constructor(), this ); - - } - } +const _chainKeys$1 = []; + +/** + * This renderer module manages render bundles. + * + * @private + */ class RenderBundles { + /** + * Constructs a new render bundle management component. + */ constructor() { - this.lists = new ChainMap(); + /** + * A chain map for maintaining the render bundles. + * + * @type {ChainMap} + */ + this.bundles = new ChainMap(); } - get( scene, camera ) { + /** + * Returns a render bundle for the given bundle group and camera. + * + * @param {BundleGroup} bundleGroup - The bundle group. + * @param {Camera} camera - The camera the bundle group is rendered with. + * @return {RenderBundle} The render bundle. + */ + get( bundleGroup, camera ) { - const lists = this.lists; - const keys = [ scene, camera ]; + const bundles = this.bundles; - let list = lists.get( keys ); + _chainKeys$1[ 0 ] = bundleGroup; + _chainKeys$1[ 1 ] = camera; - if ( list === undefined ) { + let bundle = bundles.get( _chainKeys$1 ); + + if ( bundle === undefined ) { - list = new RenderBundle( scene, camera ); - lists.set( keys, list ); + bundle = new RenderBundle( bundleGroup, camera ); + bundles.set( _chainKeys$1, bundle ); } - return list; + _chainKeys$1.length = 0; + + return bundle; } + /** + * Frees all internal resources. + */ dispose() { - this.lists = new ChainMap(); + this.bundles = new ChainMap(); } } +/** + * The purpose of a node library is to assign node implementations + * to existing library features. In `WebGPURenderer` lights, materials + * which are not based on `NodeMaterial` as well as tone mapping techniques + * are implemented with node-based modules. + * + * @private + */ class NodeLibrary { + /** + * Constructs a new node library. + */ constructor() { + /** + * A weak map that maps lights to light nodes. + * + * @type {WeakMap} + */ this.lightNodes = new WeakMap(); + + /** + * A map that maps materials to node materials. + * + * @type {WeakMap} + */ this.materialNodes = new Map(); + + /** + * A map that maps tone mapping techniques (constants) + * to tone mapping node functions. + * + * @type {WeakMap} + */ this.toneMappingNodes = new Map(); } + /** + * Returns a matching node material instance for the given material object. + * + * This method also assigns/copies the properties of the given material object + * to the node material. This is done to make sure the current material + * configuration carries over to the node version. + * + * @param {Material} material - A material. + * @return {NodeMaterial} The corresponding node material. + */ fromMaterial( material ) { if ( material.isNodeMaterial ) return material; @@ -34415,42 +45470,85 @@ class NodeLibrary { } + /** + * Adds a tone mapping node function for a tone mapping technique (constant). + * + * @param {Function} toneMappingNode - The tone mapping node function. + * @param {Number} toneMapping - The tone mapping. + */ addToneMapping( toneMappingNode, toneMapping ) { this.addType( toneMappingNode, toneMapping, this.toneMappingNodes ); } + /** + * Returns a tone mapping node function for a tone mapping technique (constant). + * + * @param {Number} toneMapping - The tone mapping. + * @return {Function?} The tone mapping node function. Returns `null` if no node function is found. + */ getToneMappingFunction( toneMapping ) { return this.toneMappingNodes.get( toneMapping ) || null; } + /** + * Returns a node material class definition for a material type. + * + * @param {String} materialType - The material type. + * @return {NodeMaterial.constructor?} The node material class definition. Returns `null` if no node material is found. + */ getMaterialNodeClass( materialType ) { return this.materialNodes.get( materialType ) || null; } + /** + * Adds a node material class definition for a given material type. + * + * @param {NodeMaterial.constructor} materialNodeClass - The node material class definition. + * @param {String} materialClassType - The material type. + */ addMaterial( materialNodeClass, materialClassType ) { this.addType( materialNodeClass, materialClassType, this.materialNodes ); } + /** + * Returns a light node class definition for a light class definition. + * + * @param {Light.constructor} light - The light class definition. + * @return {AnalyticLightNode.constructor?} The light node class definition. Returns `null` if no light node is found. + */ getLightNodeClass( light ) { return this.lightNodes.get( light ) || null; } + /** + * Adds a light node class definition for a given light class definition. + * + * @param {AnalyticLightNode.constructor} lightNodeClass - The light node class definition. + * @param {Light.constructor} lightClass - The light class definition. + */ addLight( lightNodeClass, lightClass ) { this.addClass( lightNodeClass, lightClass, this.lightNodes ); } + /** + * Adds a node class definition for the given type to the provided type library. + * + * @param {Any} nodeClass - The node class definition. + * @param {String} type - The object type. + * @param {Map} library - The type library. + */ addType( nodeClass, type, library ) { if ( library.has( type ) ) { @@ -34467,6 +45565,13 @@ class NodeLibrary { } + /** + * Adds a node class definition for the given class definition to the provided type library. + * + * @param {Any} nodeClass - The node class definition. + * @param {Any} baseClass - The class definition. + * @param {WeakMap} library - The type library. + */ addClass( nodeClass, baseClass, library ) { if ( library.has( baseClass ) ) { @@ -34486,46 +45591,76 @@ class NodeLibrary { } const _defaultLights = /*@__PURE__*/ new LightsNode(); +const _chainKeys = []; +/** + * This renderer module manages the lights nodes which are unique + * per scene and camera combination. + * + * The lights node itself is later configured in the render list + * with the actual lights from the scene. + * + * @private + * @augments ChainMap + */ class Lighting extends ChainMap { + /** + * Constructs a lighting management component. + */ constructor() { super(); } + /** + * Creates a new lights node for the given array of lights. + * + * @param {Array} lights - The render object. + * @return {Boolean} Whether if the given render object has an initialized geometry or not. + */ createNode( lights = [] ) { return new LightsNode().setLights( lights ); } + /** + * Returns a lights node for the given scene and camera. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera. + * @return {LightsNode} The lights node. + */ getNode( scene, camera ) { // ignore post-processing if ( scene.isQuadMesh ) return _defaultLights; - // tiled lighting - - const keys = [ scene, camera ]; + _chainKeys[ 0 ] = scene; + _chainKeys[ 1 ] = camera; - let node = this.get( keys ); + let node = this.get( _chainKeys ); if ( node === undefined ) { node = this.createNode(); - this.set( keys, node ); + this.set( _chainKeys, node ); } + _chainKeys.length = 0; + return node; } } +/** @module Renderer **/ + const _scene = /*@__PURE__*/ new Scene(); const _drawingBufferSize = /*@__PURE__*/ new Vector2(); const _screen = /*@__PURE__*/ new Vector4(); @@ -34533,10 +45668,34 @@ const _frustum = /*@__PURE__*/ new Frustum(); const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); const _vector4 = /*@__PURE__*/ new Vector4(); +/** + * Base class for renderers. + */ class Renderer { + /** + * Constructs a new renderer. + * + * @param {Backend} backend - The backend the renderer is targeting (e.g. WebGPU or WebGL 2). + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. This parameter can set to any other integer value than 0 + * to overwrite the default. + * @param {Function?} [parameters.getFallback=null] - This callback function can be used to provide a fallback backend, if the primary backend can't be targeted. + */ constructor( backend, parameters = {} ) { + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isRenderer = true; // @@ -34551,32 +45710,142 @@ class Renderer { getFallback = null } = parameters; - // public + /** + * A reference to the canvas element the renderer is drawing to. + * This value of this property will automatically be created by + * the renderer. + * + * @type {HTMLCanvasElement|OffscreenCanvas} + */ this.domElement = backend.getDomElement(); + /** + * A reference to the current backend. + * + * @type {Backend} + */ this.backend = backend; + /** + * The number of MSAA samples. + * + * @type {Number} + * @default 0 + */ this.samples = samples || ( antialias === true ) ? 4 : 0; + /** + * Whether the renderer should automatically clear the current rendering target + * before execute a `render()` call. The target can be the canvas (default framebuffer) + * or the current bound render target (custom framebuffer). + * + * @type {Boolean} + * @default true + */ this.autoClear = true; + + /** + * When `autoClear` is set to `true`, this property defines whether the renderer + * should clear the color buffer. + * + * @type {Boolean} + * @default true + */ this.autoClearColor = true; + + /** + * When `autoClear` is set to `true`, this property defines whether the renderer + * should clear the depth buffer. + * + * @type {Boolean} + * @default true + */ this.autoClearDepth = true; + + /** + * When `autoClear` is set to `true`, this property defines whether the renderer + * should clear the stencil buffer. + * + * @type {Boolean} + * @default true + */ this.autoClearStencil = true; + /** + * Whether the default framebuffer should be transparent or opaque. + * + * @type {Boolean} + * @default true + */ this.alpha = alpha; + /** + * Whether logarithmic depth buffer is enabled or not. + * + * @type {Boolean} + * @default false + */ this.logarithmicDepthBuffer = logarithmicDepthBuffer; + /** + * Defines the output color space of the renderer. + * + * @type {String} + * @default SRGBColorSpace + */ this.outputColorSpace = SRGBColorSpace; + /** + * Defines the tone mapping of the renderer. + * + * @type {Number} + * @default NoToneMapping + */ this.toneMapping = NoToneMapping; + + /** + * Defines the tone mapping exposure. + * + * @type {Number} + * @default 1 + */ this.toneMappingExposure = 1.0; + /** + * Whether the renderer should sort its render lists or not. + * + * Note: Sorting is used to attempt to properly render objects that have some degree of transparency. + * By definition, sorting objects may not work in all cases. Depending on the needs of application, + * it may be necessary to turn off sorting and use other methods to deal with transparency rendering + * e.g. manually determining each object's rendering order. + * + * @type {Boolean} + * @default true + */ this.sortObjects = true; + /** + * Whether the default framebuffer should have a depth buffer or not. + * + * @type {Boolean} + * @default true + */ this.depth = depth; + + /** + * Whether the default framebuffer should have a stencil buffer or not. + * + * @type {Boolean} + * @default false + */ this.stencil = stencil; + /** + * Holds a series of statistical information about the GPU memory + * and the rendering process. Useful for debugging and monitoring. + * + * @type {Info} + */ this.info = new Info(); this.nodes = { @@ -34584,82 +45853,449 @@ class Renderer { modelNormalViewMatrix: null }; + /** + * The node library defines how certain library objects like materials, lights + * or tone mapping functions are mapped to node types. This is required since + * although instances of classes like `MeshBasicMaterial` or `PointLight` can + * be part of the scene graph, they are internally represented as nodes for + * further processing. + * + * @type {NodeLibrary} + */ this.library = new NodeLibrary(); + + /** + * A map-like data structure for managing lights. + * + * @type {Lighting} + */ this.lighting = new Lighting(); // internals + /** + * This callback function can be used to provide a fallback backend, if the primary backend can't be targeted. + * + * @private + * @type {Function} + */ this._getFallback = getFallback; + /** + * The renderer's pixel ration. + * + * @private + * @type {Number} + * @default 1 + */ this._pixelRatio = 1; + + /** + * The width of the renderer's default framebuffer in logical pixel unit. + * + * @private + * @type {Number} + */ this._width = this.domElement.width; + + /** + * The height of the renderer's default framebuffer in logical pixel unit. + * + * @private + * @type {Number} + */ this._height = this.domElement.height; + /** + * The viewport of the renderer in logical pixel unit. + * + * @private + * @type {Vector4} + */ this._viewport = new Vector4( 0, 0, this._width, this._height ); + + /** + * The scissor rectangle of the renderer in logical pixel unit. + * + * @private + * @type {Vector4} + */ this._scissor = new Vector4( 0, 0, this._width, this._height ); + + /** + * Whether the scissor test should be enabled or not. + * + * @private + * @type {Boolean} + */ this._scissorTest = false; + /** + * A reference to a renderer module for managing shader attributes. + * + * @private + * @type {Attributes?} + * @default null + */ this._attributes = null; + + /** + * A reference to a renderer module for managing geometries. + * + * @private + * @type {Geometries?} + * @default null + */ this._geometries = null; + + /** + * A reference to a renderer module for managing node related logic. + * + * @private + * @type {Nodes?} + * @default null + */ this._nodes = null; + + /** + * A reference to a renderer module for managing the internal animation loop. + * + * @private + * @type {Animation?} + * @default null + */ this._animation = null; + + /** + * A reference to a renderer module for managing shader program bindings. + * + * @private + * @type {Bindings?} + * @default null + */ this._bindings = null; + + /** + * A reference to a renderer module for managing render objects. + * + * @private + * @type {RenderObjects?} + * @default null + */ this._objects = null; + + /** + * A reference to a renderer module for managing render and compute pipelines. + * + * @private + * @type {Pipelines?} + * @default null + */ this._pipelines = null; + + /** + * A reference to a renderer module for managing render bundles. + * + * @private + * @type {RenderBundles?} + * @default null + */ this._bundles = null; + + /** + * A reference to a renderer module for managing render lists. + * + * @private + * @type {RenderLists?} + * @default null + */ this._renderLists = null; + + /** + * A reference to a renderer module for managing render contexts. + * + * @private + * @type {RenderContexts?} + * @default null + */ this._renderContexts = null; + + /** + * A reference to a renderer module for managing textures. + * + * @private + * @type {Textures?} + * @default null + */ this._textures = null; + + /** + * A reference to a renderer module for backgrounds. + * + * @private + * @type {Background?} + * @default null + */ this._background = null; + /** + * This fullscreen quad is used for internal render passes + * like the tone mapping and color space output pass. + * + * @private + * @type {QuadMesh} + */ this._quad = new QuadMesh( new NodeMaterial() ); - this._quad.material.type = 'Renderer_output'; + this._quad.material.name = 'Renderer_output'; + /** + * A reference to the current render context. + * + * @private + * @type {RenderContext?} + * @default null + */ this._currentRenderContext = null; + /** + * A custom sort function for the opaque render list. + * + * @private + * @type {Function?} + * @default null + */ this._opaqueSort = null; + + /** + * A custom sort function for the transparent render list. + * + * @private + * @type {Function?} + * @default null + */ this._transparentSort = null; + /** + * The framebuffer target. + * + * @private + * @type {RenderTarget?} + * @default null + */ this._frameBufferTarget = null; const alphaClear = this.alpha === true ? 0 : 1; + /** + * The clear color value. + * + * @private + * @type {Color4} + */ this._clearColor = new Color4( 0, 0, 0, alphaClear ); + + /** + * The clear depth value. + * + * @private + * @type {Number} + * @default 1 + */ this._clearDepth = 1; + + /** + * The clear stencil value. + * + * @private + * @type {Number} + * @default 0 + */ this._clearStencil = 0; + /** + * The current render target. + * + * @private + * @type {RenderTarget?} + * @default null + */ this._renderTarget = null; + + /** + * The active cube face. + * + * @private + * @type {Number} + * @default 0 + */ this._activeCubeFace = 0; + + /** + * The active mipmap level. + * + * @private + * @type {Number} + * @default 0 + */ this._activeMipmapLevel = 0; + /** + * The MRT setting. + * + * @private + * @type {MRTNode?} + * @default null + */ this._mrt = null; + /** + * This function defines how a render object is going + * to be rendered. + * + * @private + * @type {Function?} + * @default null + */ this._renderObjectFunction = null; + + /** + * Used to keep track of the current render object function. + * + * @private + * @type {Function?} + * @default null + */ this._currentRenderObjectFunction = null; + + /** + * Used to keep track of the current render bundle. + * + * @private + * @type {RenderBundle?} + * @default null + */ this._currentRenderBundle = null; + /** + * Next to `_renderObjectFunction()`, this function provides another hook + * for influencing the render process of a render object. It is meant for internal + * use and only relevant for `compileAsync()` right now. Instead of using + * the default logic of `_renderObjectDirect()` which actually draws the render object, + * a different function might be used which performs no draw but just the node + * and pipeline updates. + * + * @private + * @type {Function?} + * @default null + */ this._handleObjectFunction = this._renderObjectDirect; + /** + * Indicates whether the device has been lost or not. In WebGL terms, the device + * lost is considered as a context lost. When this is set to `true`, rendering + * isn't possible anymore. + * + * @private + * @type {Boolean} + * @default false + */ this._isDeviceLost = false; + + /** + * A callback function that defines what should happen when a device/context lost occurs. + * + * @type {Function} + */ this.onDeviceLost = this._onDeviceLost; + /** + * Whether the renderer has been initialized or not. + * + * @private + * @type {Boolean} + * @default false + */ this._initialized = false; + + /** + * A reference to the promise which initializes the renderer. + * + * @private + * @type {Promise?} + * @default null + */ this._initPromise = null; + /** + * An array of compilation promises which are used in `compileAsync()`. + * + * @private + * @type {Array?} + * @default null + */ this._compilationPromises = null; + /** + * Whether the renderer should render transparent render objects or not. + * + * @type {Boolean} + * @default true + */ this.transparent = true; + + /** + * Whether the renderer should render opaque render objects or not. + * + * @type {Boolean} + * @default true + */ this.opaque = true; + /** + * Shadow map configuration + * @typedef {Object} ShadowMapConfig + * @property {Boolean} enabled - Whether to globally enable shadows or not. + * @property {Number} type - The shadow map type. + */ + + /** + * The renderer's shadow configuration. + * + * @type {module:Renderer~ShadowMapConfig} + */ this.shadowMap = { enabled: false, type: PCFShadowMap }; + /** + * XR configuration. + * @typedef {Object} XRConfig + * @property {Boolean} enabled - Whether to globally enable XR or not. + */ + + /** + * The renderer's XR configuration. + * + * @type {module:Renderer~XRConfig} + */ this.xr = { enabled: false }; + /** + * Debug configuration. + * @typedef {Object} DebugConfig + * @property {Boolean} checkShaderErrors - Whether shader errors should be checked or not. + * @property {Function} onShaderError - A callback function that is executed when a shader error happens. Only supported with WebGL 2 right now. + * @property {Function} getShaderAsync - Allows the get the raw shader code for the given scene, camera and 3D object. + */ + + /** + * The renderer's debug configuration. + * + * @type {module:Renderer~DebugConfig} + */ this.debug = { checkShaderErrors: true, onShaderError: null, @@ -34683,6 +46319,12 @@ class Renderer { } + /** + * Initializes the renderer so it is ready for usage. + * + * @async + * @return {Promise} A Promise that resolves when the renderer has been initialized. + */ async init() { if ( this._initialized ) { @@ -34758,12 +46400,35 @@ class Renderer { } + /** + * The coordinate system of the renderer. The value of this property + * depends on the selected backend. Either `THREE.WebGLCoordinateSystem` or + * `THREE.WebGPUCoordinateSystem`. + * + * @readonly + * @type {Number} + */ get coordinateSystem() { return this.backend.coordinateSystem; } + /** + * Compiles all materials in the given scene. This can be useful to avoid a + * phenomenon which is called "shader compilation stutter", which occurs when + * rendering an object with a new shader for the first time. + * + * If you want to add a 3D object to an existing scene, use the third optional + * parameter for applying the target scene. Note that the (target) scene's lighting + * and environment must be configured before calling this method. + * + * @async + * @param {Object3D} scene - The scene or 3D object to precompile. + * @param {Camera} camera - The camera that is used to render the scene. + * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. + * @return {Promise} A Promise that resolves when the compile has been finished. + */ async compileAsync( scene, camera, targetScene = null ) { if ( this._isDeviceLost === true ) return; @@ -34860,10 +46525,6 @@ class Renderer { // - this._nodes.updateScene( sceneRef ); - - // - this._background.update( sceneRef, renderList, renderContext ); // process render lists @@ -34892,6 +46553,14 @@ class Renderer { } + /** + * Renders the scene in an async fashion. + * + * @async + * @param {Object3D} scene - The scene or 3D object to render. + * @param {Camera} camera - The camera. + * @return {Promise} A Promise that resolves when the render has been finished. + */ async renderAsync( scene, camera ) { if ( this._initialized === false ) await this.init(); @@ -34902,12 +46571,25 @@ class Renderer { } + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ async waitForGPU() { await this.backend.waitForGPU(); } + /** + * Sets the given MRT configuration. + * + * @param {MRTNode} mrt - The MRT node to set. + * @return {Renderer} A reference to this renderer. + */ setMRT( mrt ) { this._mrt = mrt; @@ -34916,12 +46598,23 @@ class Renderer { } + /** + * Returns the MRT configuration. + * + * @return {MRTNode} The MRT configuration. + */ getMRT() { return this._mrt; } + /** + * Default implementation of the device lost callback. + * + * @private + * @param {Object} info - Information about the context lost. + */ _onDeviceLost( info ) { let errorMessage = `THREE.WebGPURenderer: ${info.api} Device Lost:\n\nMessage: ${info.message}`; @@ -34938,7 +46631,14 @@ class Renderer { } - + /** + * Renders the given render bundle. + * + * @private + * @param {Object} bundle - Render bundle data. + * @param {Scene} sceneRef - The scene the render bundle belongs to. + * @param {LightsNode} lightsNode - The current lights node. + */ _renderBundle( bundle, sceneRef, lightsNode ) { const { bundleGroup, camera, renderList } = bundle; @@ -35010,6 +46710,18 @@ class Renderer { } + /** + * Renders the scene or 3D object with the given camera. This method can only be called + * if the renderer has been initialized. + * + * The target of the method is the default framebuffer (meaning the canvas) + * or alternatively a render target when specified via `setRenderTarget()`. + * + * @param {Object3D} scene - The scene or 3D object to render. + * @param {Camera} camera - The camera to render the scene with. + * @return {Promise?} A Promise that resolve when the scene has been rendered. + * Only returned when the renderer has not been initialized. + */ render( scene, camera ) { if ( this._initialized === false ) { @@ -35024,6 +46736,14 @@ class Renderer { } + /** + * Returns an internal render target which is used when computing the output tone mapping + * and color space conversion. Unlike in `WebGLRenderer`, this is done in a separate render + * pass and not inline to achieve more correct results. + * + * @private + * @return {RenderTarget?} The render target. The method returns `null` if no output conversion should be applied. + */ _getFrameBufferTarget() { const { currentToneMapping, currentColorSpace } = this; @@ -35071,6 +46791,15 @@ class Renderer { } + /** + * Renders the scene or 3D object with the given camera. + * + * @private + * @param {Object3D} scene - The scene or 3D object to render. + * @param {Camera} camera - The camera to render the scene with. + * @param {Boolean} [useFrameBufferTarget=true] - Whether to use a framebuffer target or not. + * @return {RenderContext} The current render context. + */ _renderScene( scene, camera, useFrameBufferTarget = true ) { if ( this._isDeviceLost === true ) return; @@ -35236,10 +46965,6 @@ class Renderer { // - this._nodes.updateScene( sceneRef ); - - // - this._background.update( sceneRef, renderList, renderContext ); // @@ -35300,24 +47025,48 @@ class Renderer { } + /** + * Returns the maximum available anisotropy for texture filtering. + * + * @return {Number} The maximum available anisotropy. + */ getMaxAnisotropy() { return this.backend.getMaxAnisotropy(); } + /** + * Returns the active cube face. + * + * @return {Number} The active cube face. + */ getActiveCubeFace() { return this._activeCubeFace; } + /** + * Returns the active mipmap level. + * + * @return {Number} The active mipmap level. + */ getActiveMipmapLevel() { return this._activeMipmapLevel; } + /** + * Applications are advised to always define the animation loop + * with this method and not manually with `requestAnimationFrame()` + * for best compatibility. + * + * @async + * @param {Function} callback - The application's animation loop. + * @return {Promise} A Promise that resolves when the set has been executed. + */ async setAnimationLoop( callback ) { if ( this._initialized === false ) await this.init(); @@ -35326,36 +47075,71 @@ class Renderer { } + /** + * Can be used to transfer buffer data from a storage buffer attribute + * from the GPU to the CPU in context of compute shaders. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { return await this.backend.getArrayBufferAsync( attribute ); } + /** + * Returns the rendering context. + * + * @return {GPUCanvasContext|WebGL2RenderingContext} The rendering context. + */ getContext() { return this.backend.getContext(); } + /** + * Returns the pixel ratio. + * + * @return {Number} The pixel ratio. + */ getPixelRatio() { return this._pixelRatio; } + /** + * Returns the drawing buffer size in physical pixels. This method honors the pixel ratio. + * + * @param {Vector2} target - The method writes the result in this target object. + * @return {Vector2} The drawing buffer size. + */ getDrawingBufferSize( target ) { return target.set( this._width * this._pixelRatio, this._height * this._pixelRatio ).floor(); } + /** + * Returns the renderer's size in logical pixels. This method does not honor the pixel ratio. + * + * @param {Vector2} target - The method writes the result in this target object. + * @return {Vector2} The drawing buffer size. + */ getSize( target ) { return target.set( this._width, this._height ); } + /** + * Sets the given pixel ration and resizes the canvas if necessary. + * + * @param {Number} [value=1] - The pixel ratio. + */ setPixelRatio( value = 1 ) { if ( this._pixelRatio === value ) return; @@ -35366,6 +47150,19 @@ class Renderer { } + /** + * This method allows to define the drawing buffer size by specifying + * width, height and pixel ratio all at once. The size of the drawing + * buffer is computed with this formula: + * ```` + * size.x = width * pixelRatio; + * size.y = height * pixelRatio; + *``` + * + * @param {Number} width - The width in logical pixels. + * @param {Number} height - The height in logical pixels. + * @param {Number} pixelRatio - The pixel ratio. + */ setDrawingBufferSize( width, height, pixelRatio ) { this._width = width; @@ -35382,6 +47179,13 @@ class Renderer { } + /** + * Sets the size of the renderer. + * + * @param {Number} width - The width in logical pixels. + * @param {Number} height - The height in logical pixels. + * @param {Boolean} [updateStyle=true] - Whether to update the `style` attribute of the canvas or not. + */ setSize( width, height, updateStyle = true ) { this._width = width; @@ -35403,18 +47207,36 @@ class Renderer { } + /** + * Defines a manual sort function for the opaque render list. + * Pass `null` to use the default sort. + * + * @param {Function} method - The sort function. + */ setOpaqueSort( method ) { this._opaqueSort = method; } + /** + * Defines a manual sort function for the transparent render list. + * Pass `null` to use the default sort. + * + * @param {Function} method - The sort function. + */ setTransparentSort( method ) { this._transparentSort = method; } + /** + * Returns the scissor rectangle. + * + * @param {Vector4} target - The method writes the result in this target object. + * @return {Vector4} The scissor rectangle. + */ getScissor( target ) { const scissor = this._scissor; @@ -35428,6 +47250,15 @@ class Renderer { } + /** + * Defines the scissor rectangle. + * + * @param {Number | Vector4} x - The horizontal coordinate for the lower left corner of the box in logical pixel unit. + * Instead of passing four arguments, the method also works with a single four-dimensional vector. + * @param {Number} y - The vertical coordinate for the lower left corner of the box in logical pixel unit. + * @param {Number} width - The width of the scissor box in logical pixel unit. + * @param {Number} height - The height of the scissor box in logical pixel unit. + */ setScissor( x, y, width, height ) { const scissor = this._scissor; @@ -35444,12 +47275,22 @@ class Renderer { } + /** + * Returns the scissor test value. + * + * @return {Boolean} Whether the scissor test should be enabled or not. + */ getScissorTest() { return this._scissorTest; } + /** + * Defines the scissor test. + * + * @param {Boolean} boolean - Whether the scissor test should be enabled or not. + */ setScissorTest( boolean ) { this._scissorTest = boolean; @@ -35458,12 +47299,28 @@ class Renderer { } + /** + * Returns the viewport definition. + * + * @param {Vector4} target - The method writes the result in this target object. + * @return {Vector4} The viewport definition. + */ getViewport( target ) { return target.copy( this._viewport ); } + /** + * Defines the viewport. + * + * @param {Number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit. + * @param {Number} y - The vertical coordinate for the lower left corner of the viewport origin in logical pixel unit. + * @param {Number} width - The width of the viewport in logical pixel unit. + * @param {Number} height - The height of the viewport in logical pixel unit. + * @param {Number} minDepth - The minimum depth value of the viewport. WebGPU only. + * @param {Number} maxDepth - The maximum depth value of the viewport. WebGPU only. + */ setViewport( x, y, width, height, minDepth = 0, maxDepth = 1 ) { const viewport = this._viewport; @@ -35483,12 +47340,24 @@ class Renderer { } + /** + * Returns the clear color. + * + * @param {Color} target - The method writes the result in this target object. + * @return {Color} The clear color. + */ getClearColor( target ) { return target.copy( this._clearColor ); } + /** + * Defines the clear color and optionally the clear alpha. + * + * @param {Color} color - The clear color. + * @param {Number} [alpha=1] - The clear alpha. + */ setClearColor( color, alpha = 1 ) { this._clearColor.set( color ); @@ -35496,42 +47365,80 @@ class Renderer { } + /** + * Returns the clear alpha. + * + * @return {Number} The clear alpha. + */ getClearAlpha() { return this._clearColor.a; } + /** + * Defines the clear alpha. + * + * @param {Number} alpha - The clear alpha. + */ setClearAlpha( alpha ) { this._clearColor.a = alpha; } + /** + * Returns the clear depth. + * + * @return {Number} The clear depth. + */ getClearDepth() { return this._clearDepth; } + /** + * Defines the clear depth. + * + * @param {Number} depth - The clear depth. + */ setClearDepth( depth ) { this._clearDepth = depth; } + /** + * Returns the clear stencil. + * + * @return {Number} The clear stencil. + */ getClearStencil() { return this._clearStencil; } + /** + * Defines the clear stencil. + * + * @param {Number} stencil - The clear stencil. + */ setClearStencil( stencil ) { this._clearStencil = stencil; } + /** + * This method performs an occlusion query for the given 3D object. + * It returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. + * + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ isOccluded( object ) { const renderContext = this._currentRenderContext; @@ -35540,6 +47447,15 @@ class Renderer { } + /** + * Performs a manual clear operation. This method ignores `autoClear` properties. + * + * @param {Boolean} [color=true] - Whether the color buffer should be cleared or not. + * @param {Boolean} [depth=true] - Whether the depth buffer should be cleared or not. + * @param {Boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clear( color = true, depth = true, stencil = true ) { if ( this._initialized === false ) { @@ -35552,17 +47468,26 @@ class Renderer { const renderTarget = this._renderTarget || this._getFrameBufferTarget(); - let renderTargetData = null; + let renderContext = null; if ( renderTarget !== null ) { this._textures.updateRenderTarget( renderTarget ); - renderTargetData = this._textures.get( renderTarget ); + const renderTargetData = this._textures.get( renderTarget ); + + renderContext = this._renderContexts.getForClear( 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; } - this.backend.clear( color, depth, stencil, renderTargetData ); + this.backend.clear( color, depth, stencil, renderContext ); if ( renderTarget !== null && this._renderTarget === null ) { @@ -35584,24 +47509,51 @@ class Renderer { } + /** + * Performs a manual clear operation of the color buffer. This method ignores `autoClear` properties. + * + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clearColor() { return this.clear( true, false, false ); } + /** + * Performs a manual clear operation of the depth buffer. This method ignores `autoClear` properties. + * + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clearDepth() { return this.clear( false, true, false ); } + /** + * Performs a manual clear operation of the stencil buffer. This method ignores `autoClear` properties. + * + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clearStencil() { return this.clear( false, false, true ); } + /** + * Async version of {@link module:Renderer~Renderer#clear}. + * + * @async + * @param {Boolean} [color=true] - Whether the color buffer should be cleared or not. + * @param {Boolean} [depth=true] - Whether the depth buffer should be cleared or not. + * @param {Boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ async clearAsync( color = true, depth = true, stencil = true ) { if ( this._initialized === false ) await this.init(); @@ -35610,36 +47562,70 @@ class Renderer { } - clearColorAsync() { + /** + * Async version of {@link module:Renderer~Renderer#clearColor}. + * + * @async + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ + async clearColorAsync() { - return this.clearAsync( true, false, false ); + this.clearAsync( true, false, false ); } - clearDepthAsync() { + /** + * Async version of {@link module:Renderer~Renderer#clearDepth}. + * + * @async + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ + async clearDepthAsync() { - return this.clearAsync( false, true, false ); + this.clearAsync( false, true, false ); } - clearStencilAsync() { + /** + * Async version of {@link module:Renderer~Renderer#clearStencil}. + * + * @async + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ + async clearStencilAsync() { - return this.clearAsync( false, false, true ); + this.clearAsync( false, false, true ); } + /** + * The current output tone mapping of the renderer. When a render target is set, + * the output tone mapping is always `NoToneMapping`. + * + * @type {Number} + */ get currentToneMapping() { return this._renderTarget !== null ? NoToneMapping : this.toneMapping; } + /** + * The current output color space of the renderer. When a render target is set, + * the output color space is always `LinearSRGBColorSpace`. + * + * @type {String} + */ get currentColorSpace() { return this._renderTarget !== null ? LinearSRGBColorSpace : this.outputColorSpace; } + /** + * Frees all internal resources of the renderer. Call this method if the renderer + * is no longer in use by your app. + */ dispose() { this.info.dispose(); @@ -35659,6 +47645,15 @@ class Renderer { } + /** + * Sets the given render target. Calling this method means the renderer does not + * target the default framebuffer (meaning the canvas) anymore but a custom framebuffer. + * Use `null` as the first argument to reset the state. + * + * @param {RenderTarget?} renderTarget - The render target to set. + * @param {Number} [activeCubeFace=0] - The active cube face. + * @param {Number} [activeMipmapLevel=0] - The active mipmap level. + */ setRenderTarget( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { this._renderTarget = renderTarget; @@ -35667,27 +47662,70 @@ class Renderer { } + /** + * Returns the current render target. + * + * @return {RenderTarget?} The render target. Returns `null` if no render target is set. + */ getRenderTarget() { return this._renderTarget; } + /** + * Callback for {@link module:Renderer~Renderer#setRenderObjectFunction}. + * + * @callback renderObjectFunction + * @param {Object3D} object - The 3D object. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {BufferGeometry} geometry - The object's geometry. + * @param {Material} material - The object's material. + * @param {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {LightsNode} lightsNode - The current lights node. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ + + /** + * Sets the given render object function. Calling this method overwrites the default implementation + * which is {@link module:Renderer~Renderer#renderObject}. Defining a custom function can be useful + * if you want to modify the way objects are rendered. For example you can define things like "every + * object that has material of a certain type should perform a pre-pass with a special overwrite material". + * The custom function must always call `renderObject()` in its implementation. + * + * Use `null` as the first argument to reset the state. + * + * @param {module:Renderer~renderObjectFunction?} renderObjectFunction - The render object function. + */ setRenderObjectFunction( renderObjectFunction ) { this._renderObjectFunction = renderObjectFunction; } + /** + * Returns the current render object function. + * + * @return {Function?} The current render object function. Returns `null` if no function is set. + */ getRenderObjectFunction() { return this._renderObjectFunction; } + /** + * Execute a single or an array of compute nodes. This method can only be called + * if the renderer has been initialized. + * + * @param {Node|Array} computeNodes - The compute node(s). + * @return {Promise?} A Promise that resolve when the compute has finished. Only returned when the renderer has not been initialized. + */ compute( computeNodes ) { - if ( this.isDeviceLost === true ) return; + if ( this._isDeviceLost === true ) return; if ( this._initialized === false ) { @@ -35776,6 +47814,13 @@ class Renderer { } + /** + * Execute a single or an array of compute nodes. + * + * @async + * @param {Node|Array} computeNodes - The compute node(s). + * @return {Promise} A Promise that resolve when the compute has finished. + */ async computeAsync( computeNodes ) { if ( this._initialized === false ) await this.init(); @@ -35786,6 +47831,13 @@ class Renderer { } + /** + * Checks if the given feature is supported by the selected backend. + * + * @async + * @param {String} name - The feature's name. + * @return {Promise} A Promise that resolves with a bool that indicates whether the feature is supported or not. + */ async hasFeatureAsync( name ) { if ( this._initialized === false ) await this.init(); @@ -35794,6 +47846,13 @@ class Renderer { } + /** + * Checks if the given feature is supported by the selected backend. If the + * renderer has not been initialized, this method always returns `false`. + * + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ hasFeature( name ) { if ( this._initialized === false ) { @@ -35808,12 +47867,25 @@ class Renderer { } + /** + * Returns `true` when the renderer has been initialized. + * + * @return {Boolean} Whether the renderer has been initialized or not. + */ hasInitialized() { return this._initialized; } + /** + * Initializes the given textures. Useful for preloading a texture rather than waiting until first render + * (which can cause noticeable lags due to decode and GPU upload overhead). + * + * @async + * @param {Texture} texture - The texture. + * @return {Promise} A Promise that resolves when the texture has been initialized. + */ async initTextureAsync( texture ) { if ( this._initialized === false ) await this.init(); @@ -35822,20 +47894,32 @@ class Renderer { } + /** + * Initializes the given textures. Useful for preloading a texture rather than waiting until first render + * (which can cause noticeable lags due to decode and GPU upload overhead). + * + * This method can only be used if the renderer has been initialized. + * + * @param {Texture} texture - The texture. + */ initTexture( texture ) { if ( this._initialized === false ) { console.warn( 'THREE.Renderer: .initTexture() called before the backend is initialized. Try using .initTextureAsync() instead.' ); - return false; - } this._textures.updateTexture( texture ); } + /** + * Copies the current bound framebuffer into the given texture. + * + * @param {FramebufferTexture} framebufferTexture - The texture. + * @param {Vector2|Vector4} rectangle - A two or four dimensional vector that defines the rectangular portion of the framebuffer that should be copied. + */ copyFramebufferToTexture( framebufferTexture, rectangle = null ) { if ( rectangle !== null ) { @@ -35893,6 +47977,15 @@ class Renderer { } + /** + * Copies data of source texture into a destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Box2|Box3} [srcRegion=null] - A bounding box which describes the source region. Can be two or three-dimensional. + * @param {Vector2|Vector3} [dstPosition=null] - A vector that represents the origin of the destination region. Can be two or three-dimensional. + * @param {Number} level - The mipmap level to copy. + */ copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { this._textures.updateTexture( srcTexture ); @@ -35902,12 +47995,35 @@ class Renderer { } - readRenderTargetPixelsAsync( renderTarget, x, y, width, height, index = 0, faceIndex = 0 ) { + /** + * Reads pixel data from the given render target. + * + * @async + * @param {RenderTarget} renderTarget - The render target to read from. + * @param {Number} x - The `x` coordinate of the copy region's origin. + * @param {Number} y - The `y` coordinate of the copy region's origin. + * @param {Number} width - The width of the copy region. + * @param {Number} height - The height of the copy region. + * @param {Number} [textureIndex=0] - The texture index of a MRT render target. + * @param {Number} [faceIndex=0] - The active cube face index. + * @return {Promise} A Promise that resolves when the read has been finished. The resolve provides the read data as a typed array. + */ + async readRenderTargetPixelsAsync( renderTarget, x, y, width, height, textureIndex = 0, faceIndex = 0 ) { - return this.backend.copyTextureToBuffer( renderTarget.textures[ index ], x, y, width, height, faceIndex ); + return this.backend.copyTextureToBuffer( renderTarget.textures[ textureIndex ], x, y, width, height, faceIndex ); } + /** + * Analyzes the given 3D object's hierarchy and builds render lists from the + * processed hierarchy. + * + * @param {Object3D} object - The 3D object to process (usually a scene). + * @param {Camera} camera - The camera the object is rendered with. + * @param {Number} groupOrder - The group order is derived from the `renderOrder` of groups and is used to group 3D objects within groups. + * @param {RenderList} renderList - The current render list. + * @param {ClippingContext} clippingContext - The current clipping context. + */ _projectObject( object, camera, groupOrder, renderList, clippingContext ) { if ( object.visible === false ) return; @@ -36029,6 +48145,14 @@ class Renderer { } + /** + * Renders the given render bundles. + * + * @private + * @param {Array} bundles - Array with render bundle data. + * @param {Scene} sceneRef - The scene the render bundles belong to. + * @param {LightsNode} lightsNode - The current lights node. + */ _renderBundles( bundles, sceneRef, lightsNode ) { for ( const bundle of bundles ) { @@ -36039,6 +48163,16 @@ class Renderer { } + /** + * Renders the transparent objects from the given render lists. + * + * @private + * @param {Array} renderList - The transparent render list. + * @param {Array} doublePassList - The list of transparent objects which require a double pass (e.g. because of transmission). + * @param {Camera} camera - The camera the render list should be rendered with. + * @param {Scene} scene - The scene the render list belongs to. + * @param {LightsNode} lightsNode - The current lights node. + */ _renderTransparents( renderList, doublePassList, camera, scene, lightsNode ) { if ( doublePassList.length > 0 ) { @@ -36079,6 +48213,16 @@ class Renderer { } + /** + * Renders the objects from the given render list. + * + * @private + * @param {Array} renderList - The render list. + * @param {Camera} camera - The camera the render list should be rendered with. + * @param {Scene} scene - The scene the render list belongs to. + * @param {LightsNode} lightsNode - The current lights node. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ _renderObjects( renderList, camera, scene, lightsNode, passId = null ) { // process renderable objects @@ -36087,9 +48231,6 @@ class Renderer { 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, clippingContext } = renderItem; if ( camera.isArrayCamera ) { @@ -36110,6 +48251,7 @@ class Renderer { viewportValue.copy( vp ).multiplyScalar( this._pixelRatio ).floor(); viewportValue.minDepth = minDepth; viewportValue.maxDepth = maxDepth; + this._currentRenderContext.viewport = true; this.backend.updateViewport( this._currentRenderContext ); @@ -36129,6 +48271,20 @@ class Renderer { } + /** + * This method represents the default render object function that manages the render lifecycle + * of the object. + * + * @param {Object3D} object - The 3D object. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {BufferGeometry} geometry - The object's geometry. + * @param {Material} material - The object's material. + * @param {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {LightsNode} lightsNode - The current lights node. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ renderObject( object, scene, camera, geometry, material, group, lightsNode, clippingContext = null, passId = null ) { let overridePositionNode; @@ -36156,7 +48312,7 @@ class Renderer { overrideMaterial.alphaMap = material.alphaMap; overrideMaterial.transparent = material.transparent || material.transmission > 0; - if ( overrideMaterial.isShadowNodeMaterial ) { + if ( overrideMaterial.isShadowPassMaterial ) { overrideMaterial.side = material.shadowSide === null ? material.side : material.shadowSide; @@ -36224,6 +48380,20 @@ class Renderer { } + /** + * This method represents the default `_handleObjectFunction` implementation which creates + * a render object from the given data and performs the draw command with the selected backend. + * + * @private + * @param {Object3D} object - The 3D object. + * @param {Material} material - The object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The current lights node. + * @param {{start: Number, count: Number}?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ _renderObjectDirect( object, material, scene, camera, lightsNode, group, clippingContext, passId ) { const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId ); @@ -36255,7 +48425,7 @@ class Renderer { renderBundleData.renderObjects.push( renderObject ); - renderObject.bundle = this._currentRenderBundle.scene; + renderObject.bundle = this._currentRenderBundle.bundleGroup; } @@ -36265,9 +48435,25 @@ class Renderer { } - _createObjectPipeline( object, material, scene, camera, lightsNode, clippingContext, passId ) { + /** + * A different implementation for `_handleObjectFunction` which only makes sure the object is ready for rendering. + * Used in `compileAsync()`. + * + * @private + * @param {Object3D} object - The 3D object. + * @param {Material} material - The object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The current lights node. + * @param {{start: Number, count: Number}?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ + _createObjectPipeline( object, material, scene, camera, lightsNode, group, clippingContext, passId ) { const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId ); + renderObject.drawRange = object.geometry.drawRange; + renderObject.group = group; // @@ -36284,6 +48470,15 @@ class Renderer { } + /** + * Alias for `compileAsync()`. + * + * @method + * @param {Object3D} scene - The scene or 3D object to precompile. + * @param {Camera} camera - The camera that is used to render the scene. + * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. + * @return {Promise} A Promise that resolves when the compile has been finished. + */ get compile() { return this.compileAsync; @@ -36292,22 +48487,57 @@ class Renderer { } +/** + * A binding represents the connection between a resource (like a texture, sampler + * or uniform buffer) and the resource definition in a shader stage. + * + * This module is an abstract base class for all concrete bindings types. + * + * @abstract + * @private + */ class Binding { + /** + * Constructs a new binding. + * + * @param {String} [name=''] - The binding's name. + */ constructor( name = '' ) { + /** + * The binding's name. + * + * @type {String} + */ this.name = name; + /** + * A bitmask that defines in what shader stages the + * binding's resource is accessible. + * + * @type {Number} + */ this.visibility = 0; } + /** + * Makes sure binding's resource is visible for the given shader stage. + * + * @param {Number} visibility - The shader stage. + */ setVisibility( visibility ) { this.visibility |= visibility; } + /** + * Clones the binding. + * + * @return {Binding} The cloned binding. + */ clone() { return Object.assign( new this.constructor(), this ); @@ -36316,6 +48546,16 @@ class Binding { } +/** @module BufferUtils **/ + +/** + * This function is usually called with the length in bytes of an array buffer. + * It returns an padded value which ensure chunk size alignment according to STD140 layout. + * + * @function + * @param {Number} floatLength - The buffer length. + * @return {Number} The padded length. + */ function getFloatLength( floatLength ) { // ensure chunk size alignment (STD140 layout) @@ -36324,32 +48564,81 @@ function getFloatLength( floatLength ) { } +/** + * Represents a buffer binding type. + * + * @private + * @abstract + * @augments Binding + */ class Buffer extends Binding { + /** + * Constructs a new buffer. + * + * @param {String} name - The buffer's name. + * @param {TypedArray} [buffer=null] - The buffer. + */ constructor( name, buffer = null ) { super( name ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBuffer = true; + /** + * The bytes per element. + * + * @type {Number} + */ this.bytesPerElement = Float32Array.BYTES_PER_ELEMENT; + /** + * A reference to the internal buffer. + * + * @private + * @type {TypedArray} + */ this._buffer = buffer; } + /** + * The buffer's byte length. + * + * @type {Number} + * @readonly + */ get byteLength() { return getFloatLength( this._buffer.byteLength ); } + /** + * A reference to the internal buffer. + * + * @type {Float32Array} + * @readonly + */ get buffer() { return this._buffer; } + /** + * Updates the binding. + * + * @return {Boolean} Whether the buffer has been updated and must be + * uploaded to the GPU. + */ update() { return true; @@ -36358,12 +48647,31 @@ class Buffer extends Binding { } +/** + * Represents a uniform buffer binding type. + * + * @private + * @augments Buffer + */ class UniformBuffer extends Buffer { + /** + * Constructs a new uniform buffer. + * + * @param {String} name - The buffer's name. + * @param {TypedArray} [buffer=null] - The buffer. + */ constructor( name, buffer = null ) { super( name, buffer ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isUniformBuffer = true; } @@ -36372,17 +48680,46 @@ class UniformBuffer extends Buffer { let _id$4 = 0; +/** + * A special form of uniform buffer binding type. + * It's buffer value is managed by a node object. + * + * @private + * @augments UniformBuffer + */ class NodeUniformBuffer extends UniformBuffer { + /** + * Constructs a new node-based uniform buffer. + * + * @param {BufferNode} nodeUniform - The uniform buffer node. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( nodeUniform, groupNode ) { super( 'UniformBuffer_' + _id$4 ++, nodeUniform ? nodeUniform.value : null ); + /** + * The uniform buffer node. + * + * @type {BufferNode} + */ this.nodeUniform = nodeUniform; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; } + /** + * The uniform buffer. + * + * @type {Float32Array} + */ get buffer() { return this.nodeUniform.value; @@ -36391,22 +48728,59 @@ class NodeUniformBuffer extends UniformBuffer { } +/** + * This class represents a uniform buffer binding but with + * an API that allows to maintain individual uniform objects. + * + * @private + * @augments UniformBuffer + */ class UniformsGroup extends UniformBuffer { + /** + * Constructs a new uniforms group. + * + * @param {String} name - The group's name. + */ constructor( name ) { super( name ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isUniformsGroup = true; + /** + * An array with the raw uniform values. + * + * @private + * @type {Array?} + * @default null + */ this._values = null; - // the order of uniforms in this array must match the order of uniforms in the shader - + /** + * An array of uniform objects. + * + * The order of uniforms in this array must match the order of uniforms in the shader. + * + * @type {Array} + */ this.uniforms = []; } + /** + * Adds a uniform to this group. + * + * @param {Uniform} uniform - The uniform to add. + * @return {UniformsGroup} A reference to this group. + */ addUniform( uniform ) { this.uniforms.push( uniform ); @@ -36415,6 +48789,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Removes a uniform from this group. + * + * @param {Uniform} uniform - The uniform to remove. + * @return {UniformsGroup} A reference to this group. + */ removeUniform( uniform ) { const index = this.uniforms.indexOf( uniform ); @@ -36429,6 +48809,11 @@ class UniformsGroup extends UniformBuffer { } + /** + * An array with the raw uniform values. + * + * @type {Array} + */ get values() { if ( this._values === null ) { @@ -36441,6 +48826,11 @@ class UniformsGroup extends UniformBuffer { } + /** + * A Float32 array buffer with the uniform values. + * + * @type {Float32Array} + */ get buffer() { let buffer = this._buffer; @@ -36459,6 +48849,11 @@ class UniformsGroup extends UniformBuffer { } + /** + * The byte length of the buffer with correct buffer alignment. + * + * @type {Number} + */ get byteLength() { let offset = 0; // global buffer offset in bytes @@ -36500,6 +48895,15 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates this group by updating each uniform object of + * the internal uniform list. The uniform objects check if their + * values has actually changed so this method only returns + * `true` if there is a real value change. + * + * @return {Boolean} Whether the uniforms have been updated and + * must be uploaded to the GPU. + */ update() { let updated = false; @@ -36518,6 +48922,13 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given uniform by calling an update method matching + * the uniforms type. + * + * @param {Uniform} uniform - The uniform to update. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateByType( uniform ) { if ( uniform.isNumberUniform ) return this.updateNumber( uniform ); @@ -36532,6 +48943,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Number uniform. + * + * @param {NumberUniform} uniform - The Number uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateNumber( uniform ) { let updated = false; @@ -36554,6 +48971,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Vector2 uniform. + * + * @param {Vector2Uniform} uniform - The Vector2 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateVector2( uniform ) { let updated = false; @@ -36578,6 +49001,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Vector3 uniform. + * + * @param {Vector3Uniform} uniform - The Vector3 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateVector3( uniform ) { let updated = false; @@ -36603,6 +49032,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Vector4 uniform. + * + * @param {Vector4Uniform} uniform - The Vector4 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateVector4( uniform ) { let updated = false; @@ -36629,6 +49064,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Color uniform. + * + * @param {ColorUniform} uniform - The Color uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateColor( uniform ) { let updated = false; @@ -36653,6 +49094,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Matrix3 uniform. + * + * @param {Matrix3Uniform} uniform - The Matrix3 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateMatrix3( uniform ) { let updated = false; @@ -36685,6 +49132,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Matrix4 uniform. + * + * @param {Matrix4Uniform} uniform - The Matrix4 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateMatrix4( uniform ) { let updated = false; @@ -36706,6 +49159,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Returns a typed array that matches the given data type. + * + * @param {String} type - The data type. + * @return {TypedArray} The typed array. + */ _getBufferForType( type ) { if ( type === 'int' || type === 'ivec2' || type === 'ivec3' || type === 'ivec4' ) return new Int32Array( this.buffer.buffer ); @@ -36716,6 +49175,14 @@ class UniformsGroup extends UniformBuffer { } +/** + * Sets the values of the second array to the first array. + * + * @private + * @param {TypedArray} a - The first array. + * @param {TypedArray} b - The second array. + * @param {Number} offset - An index offset for the first array. + */ function setArray( a, b, offset ) { for ( let i = 0, l = b.length; i < l; i ++ ) { @@ -36726,6 +49193,15 @@ function setArray( a, b, offset ) { } +/** + * Returns `true` if the given arrays are equal. + * + * @private + * @param {TypedArray} a - The first array. + * @param {TypedArray} b - The second array. + * @param {Number} offset - An index offset for the first array. + * @return {Boolean} Whether the given arrays are equal or not. + */ function arraysEqual( a, b, offset ) { for ( let i = 0, l = b.length; i < l; i ++ ) { @@ -36740,58 +49216,128 @@ function arraysEqual( a, b, offset ) { let _id$3 = 0; +/** + * A special form of uniforms group that represents + * the individual uniforms as node-based uniforms. + * + * @private + * @augments UniformsGroup + */ class NodeUniformsGroup extends UniformsGroup { + /** + * Constructs a new node-based uniforms group. + * + * @param {String} name - The group's name. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( name, groupNode ) { super( name ); + /** + * The group's ID. + * + * @type {Number} + */ this.id = _id$3 ++; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ 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; +/** + * Represents a sampled texture binding type. + * + * @private + * @augments Binding + */ class SampledTexture extends Binding { + /** + * Constructs a new sampled texture. + * + * @param {String} name - The sampled texture's name. + * @param {Texture?} texture - The texture this binding is referring to. + */ constructor( name, texture ) { super( name ); + /** + * This identifier. + * + * @type {Number} + */ this.id = _id$2 ++; + /** + * The texture this binding is referring to. + * + * @type {Texture?} + */ this.texture = texture; + + /** + * The binding's version. + * + * @type {Number} + */ this.version = texture ? texture.version : 0; + + /** + * Whether the texture is a storage texture or not. + * + * @type {Boolean} + * @default false + */ this.store = false; + + /** + * The binding's generation which is an additional version + * qualifier. + * + * @type {Number?} + * @default null + */ this.generation = null; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledTexture = true; } + /** + * Returns `true` whether this binding requires an update for the + * given generation. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether an update is required or not. + */ needsBindingsUpdate( generation ) { const { texture } = this; @@ -36808,6 +49354,13 @@ class SampledTexture extends Binding { } + /** + * Updates the binding. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether the texture has been updated and must be + * uploaded to the GPU. + */ update() { const { texture, version } = this; @@ -36826,25 +49379,70 @@ class SampledTexture extends Binding { } +/** + * A special form of sampled texture binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments SampledTexture + */ class NodeSampledTexture extends SampledTexture { + /** + * Constructs a new node-based sampled texture. + * + * @param {String} name - The textures's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + * @param {String?} [access=null] - The access type. + */ constructor( name, textureNode, groupNode, access = null ) { super( name, textureNode ? textureNode.value : null ); + /** + * The texture node. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; + /** + * The access type. + * + * @type {String?} + * @default null + */ this.access = access; } + /** + * Overwrites the default to additionally check if the node value has changed. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether an update is required or not. + */ needsBindingsUpdate( generation ) { return this.textureNode.value !== this.texture || super.needsBindingsUpdate( generation ); } + /** + * Updates the binding. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether the texture has been updated and must be + * uploaded to the GPU. + */ update() { const { textureNode } = this; @@ -36863,24 +49461,68 @@ class NodeSampledTexture extends SampledTexture { } +/** + * A special form of sampled cube texture binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments NodeSampledTexture + */ class NodeSampledCubeTexture extends NodeSampledTexture { - constructor( name, textureNode, groupNode, access ) { + /** + * Constructs a new node-based sampled cube texture. + * + * @param {String} name - The textures's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + * @param {String?} [access=null] - The access type. + */ + constructor( name, textureNode, groupNode, access = null ) { super( name, textureNode, groupNode, access ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledCubeTexture = true; } } +/** + * A special form of sampled 3D texture binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments NodeSampledTexture + */ class NodeSampledTexture3D extends NodeSampledTexture { - constructor( name, textureNode, groupNode, access ) { + /** + * Constructs a new node-based sampled 3D texture. + * + * @param {String} name - The textures's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + * @param {String?} [access=null] - The access type. + */ + constructor( name, textureNode, groupNode, access = null ) { super( name, textureNode, groupNode, access ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledTexture3D = true; } @@ -36888,7 +49530,6 @@ class NodeSampledTexture3D extends NodeSampledTexture { } const glslMethods = { - atan2: 'atan', textureDimensions: 'textureSize', equals: 'equal' }; @@ -36925,39 +49566,109 @@ precision highp isampler2DArray; precision lowp sampler2DShadow; `; +/** + * A node builder targeting GLSL. + * + * This module generates GLSL shader code from node materials and also + * generates the respective bindings and vertex buffer definitions. These + * data are later used by the renderer to create render and compute pipelines + * for render objects. + * + * @augments NodeBuilder + */ class GLSLNodeBuilder extends NodeBuilder { + /** + * Constructs a new GLSL node builder renderer. + * + * @param {Object3D} object - The 3D object. + * @param {Renderer} renderer - The renderer. + */ constructor( object, renderer ) { super( object, renderer, new GLSLNodeParser() ); + /** + * A dictionary holds for each shader stage ('vertex', 'fragment', 'compute') + * another dictionary which manages UBOs per group ('render','frame','object'). + * + * @type {Object>} + */ this.uniformGroups = {}; + + /** + * An array that holds objects defining the varying and attribute data in + * context of Transform Feedback. + * + * @type {Object>} + */ this.transforms = []; + + /** + * A dictionary that holds for each shader stage a Map of used extensions. + * + * @type {Object>} + */ this.extensions = {}; + + /** + * A dictionary that holds for each shader stage an Array of used builtins. + * + * @type {Object>} + */ this.builtins = { vertex: [], fragment: [], compute: [] }; + /** + * Whether comparison in shader code are generated with methods or not. + * + * @type {Boolean} + * @default true + */ this.useComparisonMethod = true; } + /** + * Checks if the given texture requires a manual conversion to the working color space. + * + * @param {Texture} texture - The texture to check. + * @return {Boolean} Whether the given texture requires a conversion to working color space or not. + */ needsToWorkingColorSpace( texture ) { return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace; } + /** + * Returns the native shader method name for a given generic name. + * + * @param {String} method - The method name to resolve. + * @return {String} The resolved GLSL method name. + */ getMethod( method ) { return glslMethods[ method ] || method; } + /** + * Returns the output struct name. Not relevant for GLSL. + * + * @return {String} + */ getOutputStructName() { return ''; } + /** + * Builds the given shader node. + * + * @param {ShaderNodeInternal} shaderNode - The shader node. + * @return {String} The GLSL function code. + */ buildFunctionCode( shaderNode ) { const layout = shaderNode.layout; @@ -36988,6 +49699,12 @@ ${ flowData.code } } + /** + * Setups the Pixel Buffer Object (PBO) for the given storage + * buffer node. + * + * @param {StorageBufferNode} storageBufferNode - The storage buffer node. + */ setupPBO( storageBufferNode ) { const attribute = storageBufferNode.value; @@ -37056,6 +49773,13 @@ ${ flowData.code } } + /** + * Returns a GLSL snippet that represents the property name of the given node. + * + * @param {Node} node - The node. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The property name. + */ getPropertyName( node, shaderStage = this.shaderStage ) { if ( node.isNodeUniform && node.node.isTextureNode !== true && node.node.isBufferNode !== true ) { @@ -37068,6 +49792,13 @@ ${ flowData.code } } + /** + * Setups the Pixel Buffer Object (PBO) for the given storage + * buffer node. + * + * @param {StorageArrayElementNode} storageArrayElementNode - The storage array element node. + * @return {String} The property name. + */ generatePBO( storageArrayElementNode ) { const { node, indexNode } = storageArrayElementNode; @@ -37150,6 +49881,16 @@ ${ flowData.code } } + /** + * Generates the GLSL snippet that reads a single texel from a texture without sampling or filtering. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvIndexSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. + * @param {String} [levelSnippet='0u'] - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The GLSL snippet. + */ generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0' ) { if ( depthSnippet ) { @@ -37164,6 +49905,15 @@ ${ flowData.code } } + /** + * Generates the GLSL snippet for sampling/loading the given texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. + * @return {String} The GLSL snippet. + */ generateTexture( texture, textureProperty, uvSnippet, depthSnippet ) { if ( texture.isDepthTexture ) { @@ -37180,24 +49930,63 @@ ${ flowData.code } } + /** + * Generates the GLSL snippet when sampling textures with explicit mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The GLSL snippet. + */ generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet ) { return `textureLod( ${ textureProperty }, ${ uvSnippet }, ${ levelSnippet } )`; } + /** + * Generates the GLSL snippet when sampling textures with a bias to the mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String} biasSnippet - A GLSL snippet that represents the bias to apply to the mip level before sampling. + * @return {String} The GLSL snippet. + */ generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet ) { return `texture( ${ textureProperty }, ${ uvSnippet }, ${ biasSnippet } )`; } + /** + * Generates the GLSL snippet for sampling/loading the given texture using explicit gradients. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {Array} gradSnippet - An array holding both gradient GLSL snippets. + * @return {String} The GLSL snippet. + */ generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet ) { return `textureGrad( ${ textureProperty }, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] } )`; } + /** + * Generates the GLSL snippet for sampling a depth texture and comparing the sampled depth values + * against a reference value. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String} compareSnippet - A GLSL snippet that represents the reference value. + * @param {String?} depthSnippet - A GLSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The GLSL snippet. + */ generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -37212,6 +50001,12 @@ ${ flowData.code } } + /** + * Returns the variables of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the variables. + */ getVars( shaderStage ) { const snippets = []; @@ -37232,6 +50027,12 @@ ${ flowData.code } } + /** + * Returns the uniforms of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the uniforms. + */ getUniforms( shaderStage ) { const uniforms = this.uniforms[ shaderStage ]; @@ -37349,6 +50150,12 @@ ${ flowData.code } } + /** + * Returns the type for a given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + * @return {String} The type. + */ getTypeFromAttribute( attribute ) { let nodeType = super.getTypeFromAttribute( attribute ); @@ -37373,6 +50180,12 @@ ${ flowData.code } } + /** + * Returns the shader attributes of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the shader attributes. + */ getAttributes( shaderStage ) { let snippet = ''; @@ -37395,6 +50208,12 @@ ${ flowData.code } } + /** + * Returns the members of the given struct type node as a GLSL string. + * + * @param {StructTypeNode} struct - The struct type node. + * @return {String} The GLSL snippet that defines the struct members. + */ getStructMembers( struct ) { const snippets = []; @@ -37411,6 +50230,12 @@ ${ flowData.code } } + /** + * Returns the structs of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the structs. + */ getStructs( shaderStage ) { const snippets = []; @@ -37438,6 +50263,12 @@ ${ flowData.code } } + /** + * Returns the varyings of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the varyings. + */ getVaryings( shaderStage ) { let snippet = ''; @@ -37483,18 +50314,33 @@ ${ flowData.code } } + /** + * Returns the vertex index builtin. + * + * @return {String} The vertex index. + */ getVertexIndex() { return 'uint( gl_VertexID )'; } + /** + * Returns the instance index builtin. + * + * @return {String} The instance index. + */ getInstanceIndex() { return 'uint( gl_InstanceID )'; } + /** + * Returns the invocation local index builtin. + * + * @return {String} The invocation local index. + */ getInvocationLocalIndex() { const workgroupSize = this.object.workgroupSize; @@ -37505,6 +50351,11 @@ ${ flowData.code } } + /** + * Returns the draw index builtin. + * + * @return {String?} The drawIndex shader string. Returns `null` if `WEBGL_multi_draw` isn't supported by the device. + */ getDrawIndex() { const extensions = this.renderer.backend.extensions; @@ -37519,24 +50370,46 @@ ${ flowData.code } } + /** + * Returns the front facing builtin. + * + * @return {String} The front facing builtin. + */ getFrontFacing() { return 'gl_FrontFacing'; } + /** + * Returns the frag coord builtin. + * + * @return {String} The frag coord builtin. + */ getFragCoord() { return 'gl_FragCoord.xy'; } + /** + * Returns the frag depth builtin. + * + * @return {String} The frag depth builtin. + */ getFragDepth() { return 'gl_FragDepth'; } + /** + * Enables the given extension. + * + * @param {String} name - The extension name. + * @param {String} behavior - The extension behavior. + * @param {String} [shaderStage=this.shaderStage] - The shader stage. + */ enableExtension( name, behavior, shaderStage = this.shaderStage ) { const map = this.extensions[ shaderStage ] || ( this.extensions[ shaderStage ] = new Map() ); @@ -37552,6 +50425,12 @@ ${ flowData.code } } + /** + * Returns the enabled extensions of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the enabled extensions. + */ getExtensions( shaderStage ) { const snippets = []; @@ -37585,12 +50464,23 @@ ${ flowData.code } } + /** + * Returns the clip distances builtin. + * + * @return {String} The clip distances builtin. + */ getClipDistance() { return 'gl_ClipDistance'; } + /** + * Whether the requested feature is available or not. + * + * @param {String} name - The requested feature. + * @return {Boolean} Whether the requested feature is supported or not. + */ isAvailable( name ) { let result = supports$1[ name ]; @@ -37634,12 +50524,22 @@ ${ flowData.code } } + /** + * Whether to flip texture data along its vertical axis or not. + * + * @return {Boolean} Returns always `true` in context of GLSL. + */ isFlipY() { return true; } + /** + * Enables hardware clipping. + * + * @param {String} planeCount - The clipping plane count. + */ enableHardwareClipping( planeCount ) { this.enableExtension( 'GL_ANGLE_clip_cull_distance', 'require' ); @@ -37648,12 +50548,24 @@ ${ flowData.code } } + /** + * Registers a transform in context of Transform Feedback. + * + * @param {String} varyingName - The varying name. + * @param {AttributeNode} attributeNode - The attribute node. + */ registerTransform( varyingName, attributeNode ) { this.transforms.push( { varyingName, attributeNode } ); } + /** + * Returns the transforms of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the transforms. + */ getTransforms( /* shaderStage */ ) { const transforms = this.transforms; @@ -37674,6 +50586,14 @@ ${ flowData.code } } + /** + * Returns a GLSL struct based on the given name and variables. + * + * @private + * @param {String} name - The struct name. + * @param {String} vars - The struct variables. + * @return {String} The GLSL snippet representing a struct. + */ _getGLSLUniformStruct( name, vars ) { return ` @@ -37683,6 +50603,13 @@ ${vars} } + /** + * Returns a GLSL vertex shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getGLSLVertexCode( shaderData ) { return `#version 300 es @@ -37725,6 +50652,13 @@ void main() { } + /** + * Returns a GLSL fragment shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getGLSLFragmentCode( shaderData ) { return `#version 300 es @@ -37758,6 +50692,9 @@ void main() { } + /** + * Controls the code build of the shader stages. + */ buildCode() { const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; @@ -37838,6 +50775,19 @@ void main() { } + /** + * This method is one of the more important ones since it's responsible + * for generating a matching binding instance for the given uniform node. + * + * These bindings are later used in the renderer to create bind groups + * and layouts. + * + * @param {UniformNode} node - The uniform node. + * @param {String} type - The node data type. + * @param {String} shaderStage - The shader stage. + * @param {String?} [name=null] - An optional uniform name. + * @return {NodeUniform} The node uniform object. + */ getUniformFromNode( node, type, shaderStage, name = null ) { const uniformNode = super.getUniformFromNode( node, type, shaderStage, name ); @@ -37912,141 +50862,540 @@ void main() { } -let vector2 = null; -let vector4 = null; -let color4 = null; +let _vector2 = null; +let _color4 = null; +/** + * Most of the rendering related logic is implemented in the + * {@link module:Renderer} module and related management components. + * Sometimes it is required though to execute commands which are + * specific to the current 3D backend (which is WebGPU or WebGL 2). + * This abstract base class defines an interface that encapsulates + * all backend-related logic. Derived classes for each backend must + * implement the interface. + * + * @abstract + * @private + */ class Backend { + /** + * Constructs a new backend. + * + * @param {Object} parameters - An object holding parameters for the backend. + */ constructor( parameters = {} ) { + /** + * The parameters of the backend. + * + * @type {Object} + */ this.parameters = Object.assign( {}, parameters ); + + /** + * This weak map holds backend-specific data of objects + * like textures, attributes or render targets. + * + * @type {WeakMap} + */ this.data = new WeakMap(); + + /** + * A reference to the renderer. + * + * @type {Renderer?} + * @default null + */ this.renderer = null; + + /** + * A reference to the canvas element the renderer is drawing to. + * + * @type {(HTMLCanvasElement|OffscreenCanvas)?} + * @default null + */ this.domElement = null; } + /** + * Initializes the backend so it is ready for usage. Concrete backends + * are supposed to implement their rendering context creation and related + * operations in this method. + * + * @async + * @param {Renderer} renderer - The renderer. + * @return {Promise} A Promise that resolves when the backend has been initialized. + */ async init( renderer ) { this.renderer = renderer; } + /** + * The coordinate system of the backend. + * + * @abstract + * @type {Number} + * @readonly + */ + get coordinateSystem() {} + // render context - begin( /*renderContext*/ ) { } + /** + * This method is executed at the beginning of a render call and + * can be used by the backend to prepare the state for upcoming + * draw calls. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + */ + beginRender( /*renderContext*/ ) {} + + /** + * This method is executed at the end of a render call and + * can be used by the backend to finalize work after draw + * calls. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + */ + finishRender( /*renderContext*/ ) {} + + /** + * This method is executed at the beginning of a compute call and + * can be used by the backend to prepare the state for upcoming + * compute tasks. + * + * @abstract + * @param {Node|Array} computeGroup - The compute node(s). + */ + beginCompute( /*computeGroup*/ ) {} - finish( /*renderContext*/ ) { } + /** + * This method is executed at the end of a compute call and + * can be used by the backend to finalize work after compute + * tasks. + * + * @abstract + * @param {Node|Array} computeGroup - The compute node(s). + */ + finishCompute( /*computeGroup*/ ) {} // render object + /** + * Executes a draw command for the given render object. + * + * @abstract + * @param {RenderObject} renderObject - The render object to draw. + * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. + */ draw( /*renderObject, info*/ ) { } + // compute node + + /** + * Executes a compute command for the given compute node. + * + * @abstract + * @param {Node|Array} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @param {ComputePipeline} computePipeline - The compute pipeline. + */ + compute( /*computeGroup, computeNode, computeBindings, computePipeline*/ ) { } + // program + /** + * Creates a shader program from the given programmable stage. + * + * @abstract + * @param {ProgrammableStage} program - The programmable stage. + */ createProgram( /*program*/ ) { } + /** + * Destroys the shader program of the given programmable stage. + * + * @abstract + * @param {ProgrammableStage} program - The programmable stage. + */ destroyProgram( /*program*/ ) { } // bindings - createBindings( /*bingGroup, bindings*/ ) { } + /** + * Creates bindings from the given bind group definition. + * + * @abstract + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + createBindings( /*bindGroup, bindings, cacheIndex, version*/ ) { } + + /** + * Updates the given bind group definition. + * + * @abstract + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + updateBindings( /*bindGroup, bindings, cacheIndex, version*/ ) { } - updateBindings( /*bingGroup, bindings*/ ) { } + /** + * Updates a buffer binding. + * + * @abstract + * @param {Buffer} binding - The buffer binding to update. + */ + updateBinding( /*binding*/ ) { } // pipeline - createRenderPipeline( /*renderObject*/ ) { } - - createComputePipeline( /*computeNode, pipeline*/ ) { } + /** + * Creates a render pipeline for the given render object. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ + createRenderPipeline( /*renderObject, promises*/ ) { } - destroyPipeline( /*pipeline*/ ) { } + /** + * Creates a compute pipeline for the given compute node. + * + * @abstract + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ + createComputePipeline( /*computePipeline, bindings*/ ) { } // cache key - needsRenderUpdate( /*renderObject*/ ) { } // return Boolean ( fast test ) + /** + * Returns `true` if the render pipeline requires an update. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render pipeline requires an update or not. + */ + needsRenderUpdate( /*renderObject*/ ) { } - getRenderCacheKey( /*renderObject*/ ) { } // return String + /** + * Returns a cache key that is used to identify render pipelines. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @return {String} The cache key. + */ + getRenderCacheKey( /*renderObject*/ ) { } // node builder - createNodeBuilder( /*renderObject*/ ) { } // return NodeBuilder (ADD IT) + /** + * Returns a node builder for the given render object. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @param {Renderer} renderer - The renderer. + * @return {NodeBuilder} The node builder. + */ + createNodeBuilder( /*renderObject, renderer*/ ) { } // textures + /** + * Creates a GPU sampler for the given texture. + * + * @abstract + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( /*texture*/ ) { } + /** + * Destroys the GPU sampler for the given texture. + * + * @abstract + * @param {Texture} texture - The texture to destroy the sampler for. + */ + destroySampler( /*texture*/ ) {} + + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @abstract + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( /*texture*/ ) { } - createTexture( /*texture*/ ) { } + /** + * Defines a texture on the GPU for the given texture object. + * + * @abstract + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ + createTexture( /*texture, options={}*/ ) { } + + /** + * Uploads the updated texture data to the GPU. + * + * @abstract + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ + updateTexture( /*texture, options = {}*/ ) { } + + /** + * Generates mipmaps for the given texture. + * + * @abstract + * @param {Texture} texture - The texture. + */ + generateMipmaps( /*texture*/ ) { } + + /** + * Destroys the GPU data for the given texture object. + * + * @abstract + * @param {Texture} texture - The texture. + */ + destroyTexture( /*texture*/ ) { } + + /** + * Returns texture data as a typed array. + * + * @abstract + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ + async copyTextureToBuffer( /*texture, x, y, width, height, faceIndex*/ ) {} + + /** + * Copies data of the given source texture to the given destination texture. + * + * @abstract + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ + copyTextureToTexture( /*srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0*/ ) {} - copyTextureToBuffer( /*texture, x, y, width, height*/ ) {} + /** + * Copies the current bound framebuffer to the given texture. + * + * @abstract + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ + copyFramebufferToTexture( /*texture, renderContext, rectangle*/ ) {} // attributes + /** + * Creates the GPU buffer of a shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute. + */ createAttribute( /*attribute*/ ) { } + /** + * Creates the GPU buffer of an indexed shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The indexed buffer attribute. + */ createIndexAttribute( /*attribute*/ ) { } + /** + * Creates the GPU buffer of a storage attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute. + */ + createStorageAttribute( /*attribute*/ ) { } + + /** + * Updates the GPU buffer of a shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute to update. + */ updateAttribute( /*attribute*/ ) { } + /** + * Destroys the GPU buffer of a shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute to destroy. + */ destroyAttribute( /*attribute*/ ) { } // canvas + /** + * Returns the backend's rendering context. + * + * @abstract + * @return {Object} The rendering context. + */ getContext() { } + /** + * Backends can use this method if they have to run + * logic when the renderer gets resized. + * + * @abstract + */ updateSize() { } + /** + * Updates the viewport with the values from the given render context. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + */ + updateViewport( /*renderContext*/ ) {} + // utils - resolveTimestampAsync( /*renderContext, type*/ ) { } + /** + * Returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. Backends must implement this method by using + * a Occlusion Query API. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ + isOccluded( /*renderContext, object*/ ) {} - hasFeatureAsync( /*name*/ ) { } // return Boolean + /** + * Resolves the time stamp for the given render context and type. + * + * @async + * @abstract + * @param {RenderContext} renderContext - The render context. + * @param {String} type - The render context. + * @return {Promise} A Promise that resolves when the time stamp has been computed. + */ + async resolveTimestampAsync( /*renderContext, type*/ ) { } - hasFeature( /*name*/ ) { } // return Boolean + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @abstract + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ + async waitForGPU() {} - getInstanceCount( renderObject ) { + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ + async getArrayBufferAsync( /* attribute */ ) {} - const { object, geometry } = renderObject; + /** + * Checks if the given feature is supported by the backend. + * + * @async + * @abstract + * @param {String} name - The feature's name. + * @return {Promise} A Promise that resolves with a bool that indicates whether the feature is supported or not. + */ + async hasFeatureAsync( /*name*/ ) { } - return geometry.isInstancedBufferGeometry ? geometry.instanceCount : ( object.count > 1 ? object.count : 1 ); + /** + * Checks if the given feature is supported by the backend. + * + * @abstract + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ + hasFeature( /*name*/ ) {} - } + /** + * Returns the maximum anisotropy texture filtering value. + * + * @abstract + * @return {Number} The maximum anisotropy texture filtering value. + */ + getMaxAnisotropy() {} + /** + * Returns the drawing buffer size. + * + * @return {Vector2} The drawing buffer size. + */ getDrawingBufferSize() { - vector2 = vector2 || new Vector2(); - - return this.renderer.getDrawingBufferSize( vector2 ); - - } - - getScissor() { + _vector2 = _vector2 || new Vector2(); - vector4 = vector4 || new Vector4(); - - return this.renderer.getScissor( vector4 ); + return this.renderer.getDrawingBufferSize( _vector2 ); } + /** + * Defines the scissor test. + * + * @abstract + * @param {Boolean} boolean - Whether the scissor test should be enabled or not. + */ setScissorTest( /*boolean*/ ) { } + /** + * Returns the clear color and alpha into a single + * color object. + * + * @return {Color4} The clear color. + */ getClearColor() { const renderer = this.renderer; - color4 = color4 || new Color4(); + _color4 = _color4 || new Color4(); - renderer.getClearColor( color4 ); + renderer.getClearColor( _color4 ); - color4.getRGB( color4, this.renderer.currentColorSpace ); + _color4.getRGB( _color4, this.renderer.currentColorSpace ); - return color4; + return _color4; } + /** + * Returns the DOM element. If no DOM element exists, the backend + * creates a new one. + * + * @return {HTMLCanvasElement} The DOM element. + */ getDomElement() { let domElement = this.domElement; @@ -38066,14 +51415,25 @@ class Backend { } - // resource properties - + /** + * Sets a dictionary for the given object into the + * internal data structure. + * + * @param {Object} object - The object. + * @param {Object} value - The dictionary to set. + */ set( object, value ) { this.data.set( object, value ); } + /** + * Returns the dictionary for the given object. + * + * @param {Object} object - The object. + * @return {Object} The object's dictionary. + */ get( object ) { let map = this.data.get( object ); @@ -38089,24 +51449,49 @@ class Backend { } + /** + * Checks if the given object has a dictionary + * with data defined. + * + * @param {Object} object - The object. + * @return {Boolean} Whether a dictionary for the given object as been defined or not. + */ has( object ) { return this.data.has( object ); } + /** + * Deletes an object from the internal data structure. + * + * @param {Object} object - The object to delete. + */ delete( object ) { this.data.delete( object ); } + /** + * Frees internal resources. + * + * @abstract + */ dispose() { } } let _id$1 = 0; +/** + * This module is internally used in context of compute shaders. + * This type of shader is not natively supported in WebGL 2 and + * thus implemented via Transform Feedback. `DualAttributeData` + * manages the related data. + * + * @private + */ class DualAttributeData { constructor( attributeData, dualBuffer ) { @@ -38151,14 +51536,35 @@ class DualAttributeData { } +/** + * A WebGL 2 backend utility module for managing shader attributes. + * + * @private + */ class WebGLAttributeUtils { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; } + /** + * Creates the GPU buffer for the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + * @param {GLenum } bufferType - A flag that indicates the buffer type and thus binding point target. + */ createAttribute( attribute, bufferType ) { const backend = this.backend; @@ -38246,7 +51652,7 @@ class WebGLAttributeUtils { if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) { - // create buffer for tranform feedback use + // create buffer for transform feedback use const bufferGPUDual = this._createBuffer( gl, bufferType, array, usage ); attributeData = new DualAttributeData( attributeData, bufferGPUDual ); @@ -38256,6 +51662,11 @@ class WebGLAttributeUtils { } + /** + * Updates the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ updateAttribute( attribute ) { const backend = this.backend; @@ -38295,6 +51706,11 @@ class WebGLAttributeUtils { } + /** + * Destroys the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ destroyAttribute( attribute ) { const backend = this.backend; @@ -38314,6 +51730,14 @@ class WebGLAttributeUtils { } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { const backend = this.backend; @@ -38352,6 +51776,16 @@ class WebGLAttributeUtils { } + /** + * Creates a WebGL buffer with the given data. + * + * @private + * @param {WebGL2RenderingContext} gl - The rendering context. + * @param {GLenum } bufferType - A flag that indicates the buffer type and thus binding point target. + * @param {TypedArray} array - The array of the buffer attribute. + * @param {GLenum} usage - The usage. + * @return {WebGLBuffer} The WebGL buffer. + */ _createBuffer( gl, bufferType, array, usage ) { const bufferGPU = gl.createBuffer(); @@ -38368,14 +51802,43 @@ class WebGLAttributeUtils { let initialized$1 = false, equationToGL, factorToGL; +/** + * A WebGL 2 backend utility module for managing the WebGL state. + * + * The major goal of this module is to reduce the number of state changes + * by caching the WEbGL state with a series of variables. In this way, the + * renderer only executes state change commands when necessary which + * improves the overall performance. + * + * @private + */ class WebGLState { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = this.backend.gl; + // Below properties are intended to cache + // the WebGL state and are not explicitly + // documented for convenience reasons. + this.enabled = {}; this.currentFlipSided = null; this.currentCullFace = null; @@ -38412,7 +51875,7 @@ class WebGLState { if ( initialized$1 === false ) { - this._init( this.gl ); + this._init(); initialized$1 = true; @@ -38420,7 +51883,14 @@ class WebGLState { } - _init( gl ) { + /** + * Inits the state of the utility. + * + * @private + */ + _init() { + + const gl = this.gl; // Store only WebGL constants here. @@ -38446,6 +51916,14 @@ class WebGLState { } + /** + * Enables the given WebGL capability. + * + * This method caches the capability state so + * `gl.enable()` is only called when necessary. + * + * @param {GLenum} id - The capability to enable. + */ enable( id ) { const { enabled } = this; @@ -38459,6 +51937,14 @@ class WebGLState { } + /** + * Disables the given WebGL capability. + * + * This method caches the capability state so + * `gl.disable()` is only called when necessary. + * + * @param {GLenum} id - The capability to enable. + */ disable( id ) { const { enabled } = this; @@ -38472,6 +51958,15 @@ class WebGLState { } + /** + * Specifies whether polygons are front- or back-facing + * by setting the winding orientation. + * + * This method caches the state so `gl.frontFace()` is only + * called when necessary. + * + * @param {Boolean} flipSided - Whether triangles flipped their sides or not. + */ setFlipSided( flipSided ) { if ( this.currentFlipSided !== flipSided ) { @@ -38494,6 +51989,15 @@ class WebGLState { } + /** + * Specifies whether or not front- and/or back-facing + * polygons can be culled. + * + * This method caches the state so `gl.cullFace()` is only + * called when necessary. + * + * @param {Number} cullFace - Defines which polygons are candidates for culling. + */ setCullFace( cullFace ) { const { gl } = this; @@ -38530,6 +52034,14 @@ class WebGLState { } + /** + * Specifies the width of line primitives. + * + * This method caches the state so `gl.lineWidth()` is only + * called when necessary. + * + * @param {Number} width - The line width. + */ setLineWidth( width ) { const { currentLineWidth, gl } = this; @@ -38544,7 +52056,21 @@ class WebGLState { } - + /** + * Defines the blending. + * + * This method caches the state so `gl.blendEquation()`, `gl.blendEquationSeparate()`, + * `gl.blendFunc()` and `gl.blendFuncSeparate()` are only called when necessary. + * + * @param {Number} blending - The blending type. + * @param {Number} blendEquation - The blending equation. + * @param {Number} blendSrc - Only relevant for custom blending. The RGB source blending factor. + * @param {Number} blendDst - Only relevant for custom blending. The RGB destination blending factor. + * @param {Number} blendEquationAlpha - Only relevant for custom blending. The blending equation for alpha. + * @param {Number} blendSrcAlpha - Only relevant for custom blending. The alpha source blending factor. + * @param {Number} blendDstAlpha - Only relevant for custom blending. The alpha destination blending factor. + * @param {Boolean} premultipliedAlpha - Whether premultiplied alpha is enabled or not. + */ setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { const { gl } = this; @@ -38681,6 +52207,15 @@ class WebGLState { } + /** + * Specifies whether colors can be written when rendering + * into a framebuffer or not. + * + * This method caches the state so `gl.colorMask()` is only + * called when necessary. + * + * @param {Boolean} colorMask - The color mask. + */ setColorMask( colorMask ) { if ( this.currentColorMask !== colorMask ) { @@ -38692,6 +52227,11 @@ class WebGLState { } + /** + * Specifies whether the depth test is enabled or not. + * + * @param {Boolean} depthTest - Whether the depth test is enabled or not. + */ setDepthTest( depthTest ) { const { gl } = this; @@ -38708,6 +52248,15 @@ class WebGLState { } + /** + * Specifies whether depth values can be written when rendering + * into a framebuffer or not. + * + * This method caches the state so `gl.depthMask()` is only + * called when necessary. + * + * @param {Boolean} depthMask - The depth mask. + */ setDepthMask( depthMask ) { if ( this.currentDepthMask !== depthMask ) { @@ -38719,6 +52268,14 @@ class WebGLState { } + /** + * Specifies the depth compare function. + * + * This method caches the state so `gl.depthFunc()` is only + * called when necessary. + * + * @param {Number} depthFunc - The depth compare function. + */ setDepthFunc( depthFunc ) { if ( this.currentDepthFunc !== depthFunc ) { @@ -38779,6 +52336,11 @@ class WebGLState { } + /** + * Specifies whether the stencil test is enabled or not. + * + * @param {Boolean} stencilTest - Whether the stencil test is enabled or not. + */ setStencilTest( stencilTest ) { const { gl } = this; @@ -38795,6 +52357,15 @@ class WebGLState { } + /** + * Specifies whether stencil values can be written when rendering + * into a framebuffer or not. + * + * This method caches the state so `gl.stencilMask()` is only + * called when necessary. + * + * @param {Boolean} stencilMask - The stencil mask. + */ setStencilMask( stencilMask ) { if ( this.currentStencilMask !== stencilMask ) { @@ -38806,6 +52377,16 @@ class WebGLState { } + /** + * Specifies whether the stencil test functions. + * + * This method caches the state so `gl.stencilFunc()` is only + * called when necessary. + * + * @param {Number} stencilFunc - The stencil compare function. + * @param {Number} stencilRef - The reference value for the stencil test. + * @param {Number} stencilMask - A bit-wise mask that is used to AND the reference value and the stored stencil value when the test is done. + */ setStencilFunc( stencilFunc, stencilRef, stencilMask ) { if ( this.currentStencilFunc !== stencilFunc || @@ -38822,6 +52403,17 @@ class WebGLState { } + /** + * Specifies whether the stencil test operation. + * + * This method caches the state so `gl.stencilOp()` is only + * called when necessary. + * + * @param {Number} stencilFail - The function to use when the stencil test fails. + * @param {Number} stencilZFail - The function to use when the stencil test passes, but the depth test fail. + * @param {Number} stencilZPass - The function to use when both the stencil test and the depth test pass, + * or when the stencil test passes and there is no depth buffer or depth testing is disabled. + */ setStencilOp( stencilFail, stencilZFail, stencilZPass ) { if ( this.currentStencilFail !== stencilFail || @@ -38838,6 +52430,13 @@ class WebGLState { } + /** + * Configures the WebGL state for the given material. + * + * @param {Material} material - The material to configure the state for. + * @param {Number} frontFaceCW - Whether the front faces are counter-clockwise or not. + * @param {Number} hardwareClippingPlanes - The number of hardware clipping planes. + */ setMaterial( material, frontFaceCW, hardwareClippingPlanes ) { const { gl } = this; @@ -38902,6 +52501,16 @@ class WebGLState { } + /** + * Specifies the polygon offset. + * + * This method caches the state so `gl.polygonOffset()` is only + * called when necessary. + * + * @param {Boolean} polygonOffset - Whether polygon offset is enabled or not. + * @param {Number} factor - The scale factor for the variable depth offset for each polygon. + * @param {Number} units - The multiplier by which an implementation-specific value is multiplied with to create a constant depth offset. + */ setPolygonOffset( polygonOffset, factor, units ) { const { gl } = this; @@ -38927,6 +52536,15 @@ class WebGLState { } + /** + * Defines the usage of the given WebGL program. + * + * This method caches the state so `gl.useProgram()` is only + * called when necessary. + * + * @param {WebGLProgram} program - The WebGL program to use. + * @return {Boolean} Whether a program change has been executed or not. + */ useProgram( program ) { if ( this.currentProgram !== program ) { @@ -38946,6 +52564,16 @@ class WebGLState { // framebuffer + /** + * Binds the given framebuffer. + * + * This method caches the state so `gl.bindFramebuffer()` is only + * called when necessary. + * + * @param {Number} target - The binding point (target). + * @param {WebGLFramebuffer} framebuffer - The WebGL framebuffer to bind. + * @return {Boolean} Whether a bind has been executed or not. + */ bindFramebuffer( target, framebuffer ) { const { gl, currentBoundFramebuffers } = this; @@ -38978,6 +52606,16 @@ class WebGLState { } + /** + * Defines draw buffers to which fragment colors are written into. + * Configures the MRT setup of custom framebuffers. + * + * This method caches the state so `gl.drawBuffers()` is only + * called when necessary. + * + * @param {RenderContext} renderContext - The render context. + * @param {WebGLFramebuffer} framebuffer - The WebGL framebuffer. + */ drawBuffers( renderContext, framebuffer ) { const { gl } = this; @@ -39038,6 +52676,14 @@ class WebGLState { // texture + /** + * Makes the given texture unit active. + * + * This method caches the state so `gl.activeTexture()` is only + * called when necessary. + * + * @param {Number} webglSlot - The texture unit to make active. + */ activeTexture( webglSlot ) { const { gl, currentTextureSlot, maxTextures } = this; @@ -39053,6 +52699,16 @@ class WebGLState { } + /** + * Binds the given WebGL texture to a target. + * + * This method caches the state so `gl.bindTexture()` is only + * called when necessary. + * + * @param {Number} webglType - The binding point (target). + * @param {WebGLTexture} webglTexture - The WebGL texture to bind. + * @param {Number} webglSlot - The texture. + */ bindTexture( webglType, webglTexture, webglSlot ) { const { gl, currentTextureSlot, currentBoundTextures, maxTextures } = this; @@ -39098,6 +52754,17 @@ class WebGLState { } + /** + * Binds a given WebGL buffer to a given binding point (target) at a given index. + * + * This method caches the state so `gl.bindBufferBase()` is only + * called when necessary. + * + * @param {Number} target - The target for the bind operation. + * @param {Number} index - The index of the target. + * @param {WebGLBuffer} buffer - The WebGL buffer. + * @return {Boolean} Whether a bind has been executed or not. + */ bindBufferBase( target, index, buffer ) { const { gl } = this; @@ -39118,6 +52785,12 @@ class WebGLState { } + /** + * Unbinds the current bound texture. + * + * This method caches the state so `gl.bindTexture()` is only + * called when necessary. + */ unbindTexture() { const { gl, currentTextureSlot, currentBoundTextures } = this; @@ -39137,17 +52810,53 @@ class WebGLState { } +/** + * A WebGL 2 backend utility module with common helpers. + * + * @private + */ class WebGLUtils { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = this.backend.gl; + + /** + * A reference to a backend module holding extension-related + * utility functions. + * + * @type {WebGLExtensions} + */ this.extensions = backend.extensions; } + /** + * Converts the given three.js constant into a WebGL constant. + * The method currently supports the conversion of texture formats + * and types. + * + * @param {Number} p - The three.js constant. + * @param {String} [colorSpace=NoColorSpace] - The color space. + * @return {Number} The corresponding WebGL constant. + */ convert( p, colorSpace = NoColorSpace ) { const { gl, extensions } = this; @@ -39358,6 +53067,13 @@ class WebGLUtils { } + /** + * This method can be used to synchronize the CPU with the GPU by waiting until + * ongoing GPU commands have been completed. + * + * @private + * @return {Promise} A promise that resolves when all ongoing GPU commands have been completed. + */ _clientWaitAsync() { const { gl } = this; @@ -39404,19 +53120,53 @@ class WebGLUtils { let initialized = false, wrappingToGL, filterToGL, compareToGL; +/** + * A WebGL 2 backend utility module for managing textures. + * + * @private + */ class WebGLTextureUtils { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = backend.gl; + + /** + * A reference to a backend module holding extension-related + * utility functions. + * + * @type {WebGLExtensions} + */ this.extensions = backend.extensions; + + /** + * A dictionary for managing default textures. The key + * is the binding point (target), the value the WEbGL texture object. + * + * @type {Object} + */ this.defaultTextures = {}; if ( initialized === false ) { - this._init( this.gl ); + this._init(); initialized = true; @@ -39424,7 +53174,14 @@ class WebGLTextureUtils { } - _init( gl ) { + /** + * Inits the state of the utility. + * + * @private + */ + _init() { + + const gl = this.gl; // Store only WebGL constants here. @@ -39457,20 +53214,12 @@ class WebGLTextureUtils { } - filterFallback( f ) { - - const { gl } = this; - - if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - - return gl.NEAREST; - - } - - return gl.LINEAR; - - } - + /** + * Returns the native texture type for the given texture. + * + * @param {Texture} texture - The texture. + * @return {GLenum} The native texture type. + */ getGLTextureType( texture ) { const { gl } = this; @@ -39500,6 +53249,16 @@ class WebGLTextureUtils { } + /** + * Returns the native texture type for the given texture. + * + * @param {String?} internalFormatName - The internal format name. When `null`, the internal format is derived from the subsequent parameters. + * @param {GLenum} glFormat - The WebGL format. + * @param {GLenum} glType - The WebGL type. + * @param {String} colorSpace - The texture's color space. + * @param {Boolean} [forceLinearTransfer=false] - Whether to force a linear transfer or not. + * @return {GLenum} The internal format. + */ getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { const { gl, extensions } = this; @@ -39643,6 +53402,12 @@ class WebGLTextureUtils { } + /** + * Sets the texture parameters for the given texture. + * + * @param {GLenum} textureType - The texture type. + * @param {Texture} texture - The texture. + */ setTextureParameters( textureType, texture ) { const { gl, extensions, backend } = this; @@ -39696,6 +53461,12 @@ class WebGLTextureUtils { } + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { const { gl, backend, defaultTextures } = this; @@ -39727,6 +53498,13 @@ class WebGLTextureUtils { } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + * @return {undefined} + */ createTexture( texture, options ) { const { gl, backend } = this; @@ -39767,6 +53545,12 @@ class WebGLTextureUtils { } + /** + * Uploads texture buffer data to the GPU memory. + * + * @param {WebGLBuffer} buffer - The buffer data. + * @param {Texture} texture - The texture, + */ copyBufferToTexture( buffer, texture ) { const { gl, backend } = this; @@ -39802,6 +53586,12 @@ class WebGLTextureUtils { } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { const { gl } = this; @@ -39922,6 +53712,11 @@ class WebGLTextureUtils { } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { const { gl, backend } = this; @@ -39932,6 +53727,11 @@ class WebGLTextureUtils { } + /** + * Deallocates the render buffers of the given render target. + * + * @param {RenderTarget} renderTarget - The render target. + */ deallocateRenderBuffers( renderTarget ) { const { gl, backend } = this; @@ -39992,6 +53792,11 @@ class WebGLTextureUtils { } + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { const { gl, backend } = this; @@ -40004,6 +53809,15 @@ class WebGLTextureUtils { } + /** + * Copies data of the given source texture to the given destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { const { gl, backend } = this; @@ -40122,6 +53936,13 @@ class WebGLTextureUtils { } + /** + * Copies the current bound framebuffer to the given texture. + * + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ copyFramebufferToTexture( texture, renderContext, rectangle ) { const { gl } = this; @@ -40133,7 +53954,7 @@ class WebGLTextureUtils { const requireDrawFrameBuffer = texture.isDepthTexture === true || ( renderContext.renderTarget && renderContext.renderTarget.samples > 0 ); - const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.gerDrawingBufferSize().y; + const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.getDrawingBufferSize().y; if ( requireDrawFrameBuffer ) { @@ -40209,7 +54030,12 @@ class WebGLTextureUtils { } - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer + /** + * SetupS storage for internal depth/stencil buffers and bind to correct framebuffer. + * + * @param {WebGLRenderbuffer} renderbuffer - The render buffer. + * @param {RenderContext} renderContext - The render context. + */ setupRenderBufferStorage( renderbuffer, renderContext ) { const { gl } = this; @@ -40264,6 +54090,18 @@ class WebGLTextureUtils { } + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { const { backend, gl } = this; @@ -40305,6 +54143,13 @@ class WebGLTextureUtils { } + /** + * Returns the corresponding typed array type for the given WebGL data type. + * + * @private + * @param {GLenum} glType - The WebGL data type. + * @return {TypedArray.constructor} The typed array type. + */ _getTypedArrayType( glType ) { const { gl } = this; @@ -40324,6 +54169,14 @@ class WebGLTextureUtils { } + /** + * Returns the bytes-per-texel value for the given WebGL data type and texture format. + * + * @private + * @param {GLenum} glType - The WebGL data type. + * @param {GLenum} glFormat - The WebGL texture format. + * @return {Number} The bytes-per-texel. + */ _getBytesPerTexel( glType, glFormat ) { const { gl } = this; @@ -40349,19 +54202,58 @@ class WebGLTextureUtils { } +/** + * A WebGL 2 backend utility module for managing extensions. + * + * @private + */ class WebGLExtensions { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = this.backend.gl; + + /** + * A list with all the supported WebGL extensions. + * + * @type {Array} + */ this.availableExtensions = this.gl.getSupportedExtensions(); + /** + * A dictionary with requested WebGL extensions. + * The key is the name of the extension, the value + * the requested extension object. + * + * @type {Object} + */ this.extensions = {}; } + /** + * Returns the extension object for the given extension name. + * + * @param {String} name - The extension name. + * @return {Object} The extension object. + */ get( name ) { let extension = this.extensions[ name ]; @@ -40378,6 +54270,12 @@ class WebGLExtensions { } + /** + * Returns `true` if the requested extension is available. + * + * @param {String} name - The extension name. + * @return {Boolean} Whether the given extension is available or not. + */ has( name ) { return this.availableExtensions.includes( name ); @@ -40386,16 +54284,44 @@ class WebGLExtensions { } +/** + * A WebGL 2 backend utility module for managing the device's capabilities. + * + * @private + */ class WebGLCapabilities { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * This value holds the cached max anisotropy value. + * + * @type {Number?} + * @default null + */ this.maxAnisotropy = null; } + /** + * Returns the maximum anisotropy texture filtering value. This value + * depends on the device and is reported by the `EXT_texture_filter_anisotropic` + * WebGL extension. + * + * @return {Number} The maximum anisotropy texture filtering value. + */ getMaxAnisotropy() { if ( this.maxAnisotropy !== null ) return this.maxAnisotropy; @@ -40573,18 +54499,184 @@ class WebGLBufferRenderer { } -// - +/** + * A backend implementation targeting WebGL 2. + * + * @private + * @augments Backend + */ class WebGLBackend extends Backend { + /** + * Constructs a new WebGPU backend. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. + * @param {WebGL2RenderingContext} [parameters.context=undefined] - A WebGL 2 rendering context. + */ constructor( parameters = {} ) { super( parameters ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGLBackend = true; + /** + * A reference to a backend module holding shader attribute-related + * utility functions. + * + * @type {WebGLAttributeUtils?} + * @default null + */ + this.attributeUtils = null; + + /** + * A reference to a backend module holding extension-related + * utility functions. + * + * @type {WebGLExtensions?} + * @default null + */ + this.extensions = null; + + /** + * A reference to a backend module holding capability-related + * utility functions. + * + * @type {WebGLCapabilities?} + * @default null + */ + this.capabilities = null; + + /** + * A reference to a backend module holding texture-related + * utility functions. + * + * @type {WebGLTextureUtils?} + * @default null + */ + this.textureUtils = null; + + /** + * A reference to a backend module holding renderer-related + * utility functions. + * + * @type {WebGLBufferRenderer?} + * @default null + */ + this.bufferRenderer = null; + + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext?} + * @default null + */ + this.gl = null; + + /** + * A reference to a backend module holding state-related + * utility functions. + * + * @type {WebGLState?} + * @default null + */ + this.state = null; + + /** + * A reference to a backend module holding common + * utility functions. + * + * @type {WebGLUtils?} + * @default null + */ + this.utils = null; + + /** + * Dictionary for caching VAOs. + * + * @type {Object} + */ + this.vaoCache = {}; + + /** + * Dictionary for caching transform feedback objects. + * + * @type {Object} + */ + this.transformFeedbackCache = {}; + + /** + * Controls if `gl.RASTERIZER_DISCARD` should be enabled or not. + * Only relevant when using compute shaders. + * + * @type {Boolean} + * @default false + */ + this.discard = false; + + /** + * A reference to the `EXT_disjoint_timer_query_webgl2` extension. `null` if the + * device does not support the extension. + * + * @type {EXTDisjointTimerQueryWebGL2?} + * @default null + */ + this.disjoint = null; + + /** + * A reference to the `KHR_parallel_shader_compile` extension. `null` if the + * device does not support the extension. + * + * @type {KHRParallelShaderCompile?} + * @default null + */ + this.parallel = null; + + /** + * Whether to track timestamps with a Timestamp Query API or not. + * + * @type {Boolean} + * @default false + */ + this.trackTimestamp = ( parameters.trackTimestamp === true ); + + /** + * A reference to the current render context. + * + * @private + * @type {RenderContext} + * @default null + */ + this._currentContext = null; + + /** + * A unique collection of bindings. + * + * @private + * @type {WeakSet} + */ + this._knownBindings = new WeakSet(); + } + /** + * Initializes the backend so it is ready for usage. + * + * @param {Renderer} renderer - The renderer. + */ init( renderer ) { super.init( renderer ); @@ -40625,11 +54717,6 @@ class WebGLBackend extends Backend { 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' ); @@ -40641,30 +54728,52 @@ class WebGLBackend extends Backend { this.disjoint = this.extensions.get( 'EXT_disjoint_timer_query_webgl2' ); this.parallel = this.extensions.get( 'KHR_parallel_shader_compile' ); - this._knownBindings = new WeakSet(); - - this._currentContext = null; - } + /** + * The coordinate system of the backend. + * + * @type {Number} + * @readonly + */ get coordinateSystem() { return WebGLCoordinateSystem; } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { return await this.attributeUtils.getArrayBufferAsync( attribute ); } + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ async waitForGPU() { await this.utils._clientWaitAsync(); } + /** + * Inits a time stamp query for the given render context. + * + * @param {RenderContext} renderContext - The render context. + */ initTimestampQuery( renderContext ) { if ( ! this.disjoint || ! this.trackTimestamp ) return; @@ -40699,6 +54808,11 @@ class WebGLBackend extends Backend { // timestamp utils + /** + * Prepares the timestamp buffer. + * + * @param {RenderContext} renderContext - The render context. + */ prepareTimestampBuffer( renderContext ) { if ( ! this.disjoint || ! this.trackTimestamp ) return; @@ -40725,6 +54839,14 @@ class WebGLBackend extends Backend { } + /** + * Resolves the time stamp for the given render context and type. + * + * @async + * @param {RenderContext} renderContext - The render context. + * @param {String} type - The render context. + * @return {Promise} A Promise that resolves when the time stamp has been computed. + */ async resolveTimestampAsync( renderContext, type = 'render' ) { if ( ! this.disjoint || ! this.trackTimestamp ) return; @@ -40754,12 +54876,23 @@ class WebGLBackend extends Backend { } + /** + * Returns the backend's rendering context. + * + * @return {WebGL2RenderingContext} The rendering context. + */ getContext() { return this.gl; } + /** + * This method is executed at the beginning of a render call and prepares + * the WebGL state for upcoming render calls + * + * @param {RenderContext} renderContext - The render context. + */ beginRender( renderContext ) { const { gl } = this; @@ -40815,6 +54948,12 @@ class WebGLBackend extends Backend { } + /** + * This method is executed at the end of a render call and finalizes work + * after draw calls. + * + * @param {RenderContext} renderContext - The render context. + */ finishRender( renderContext ) { const { gl, state } = this; @@ -40921,6 +55060,13 @@ class WebGLBackend extends Backend { } + /** + * This method processes the result of occlusion queries and writes it + * into render context data. + * + * @async + * @param {RenderContext} renderContext - The render context. + */ resolveOccludedAsync( renderContext ) { const renderContextData = this.get( renderContext ); @@ -40950,7 +55096,7 @@ class WebGLBackend extends Backend { if ( gl.getQueryParameter( query, gl.QUERY_RESULT_AVAILABLE ) ) { - if ( gl.getQueryParameter( query, gl.QUERY_RESULT ) > 0 ) occluded.add( currentOcclusionQueryObjects[ i ] ); + if ( gl.getQueryParameter( query, gl.QUERY_RESULT ) === 0 ) occluded.add( currentOcclusionQueryObjects[ i ] ); currentOcclusionQueries[ i ] = null; gl.deleteQuery( query ); @@ -40979,6 +55125,14 @@ class WebGLBackend extends Backend { } + /** + * Returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ isOccluded( renderContext, object ) { const renderContextData = this.get( renderContext ); @@ -40987,6 +55141,11 @@ class WebGLBackend extends Backend { } + /** + * Updates the viewport with the values from the given render context. + * + * @param {RenderContext} renderContext - The render context. + */ updateViewport( renderContext ) { const gl = this.gl; @@ -40996,6 +55155,11 @@ class WebGLBackend extends Backend { } + /** + * Defines the scissor test. + * + * @param {Boolean} boolean - Whether the scissor test should be enabled or not. + */ setScissorTest( boolean ) { const gl = this.gl; @@ -41012,6 +55176,15 @@ class WebGLBackend extends Backend { } + /** + * Performs a clear operation. + * + * @param {Boolean} color - Whether the color buffer should be cleared or not. + * @param {Boolean} depth - Whether the depth buffer should be cleared or not. + * @param {Boolean} stencil - Whether the stencil buffer should be cleared or not. + * @param {Object?} [descriptor=null] - The render context of the current set render target. + * @param {Boolean} [setFrameBuffer=true] - TODO. + */ clear( color, depth, stencil, descriptor = null, setFrameBuffer = true ) { const { gl } = this; @@ -41102,6 +55275,12 @@ class WebGLBackend extends Backend { } + /** + * This method is executed at the beginning of a compute call and + * prepares the state for upcoming compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ beginCompute( computeGroup ) { const { state, gl } = this; @@ -41111,11 +55290,19 @@ class WebGLBackend extends Backend { } + /** + * Executes a compute command for the given compute node. + * + * @param {Node|Array} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @param {ComputePipeline} pipeline - The compute pipeline. + */ compute( computeGroup, computeNode, bindings, pipeline ) { const { state, gl } = this; - if ( ! this.discard ) { + if ( this.discard === false ) { // required here to handle async behaviour of render.compute() gl.enable( gl.RASTERIZER_DISCARD ); @@ -41180,6 +55367,12 @@ class WebGLBackend extends Backend { } + /** + * This method is executed at the end of a compute call and + * finalizes work after compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ finishCompute( computeGroup ) { const gl = this.gl; @@ -41198,6 +55391,12 @@ class WebGLBackend extends Backend { } + /** + * Executes a draw command for the given render object. + * + * @param {RenderObject} renderObject - The render object to draw. + * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. + */ draw( renderObject/*, info*/ ) { const { object, pipeline, material, context, hardwareClippingPlanes } = renderObject; @@ -41360,12 +55559,24 @@ class WebGLBackend extends Backend { } + /** + * Explain why always null is returned. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render pipeline requires an update or not. + */ needsRenderUpdate( /*renderObject*/ ) { return false; } + /** + * Explain why no cache key is computed. + * + * @param {RenderObject} renderObject - The render object. + * @return {String} The cache key. + */ getRenderCacheKey( /*renderObject*/ ) { return ''; @@ -41374,53 +55585,109 @@ class WebGLBackend extends Backend { // textures + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { this.textureUtils.createDefaultTexture( texture ); } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ createTexture( texture, options ) { this.textureUtils.createTexture( texture, options ); } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { this.textureUtils.updateTexture( texture, options ); } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { this.textureUtils.generateMipmaps( texture ); } - + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { this.textureUtils.destroyTexture( texture ); } - copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); } + /** + * This method does nothing since WebGL 2 has no concept of samplers. + * + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( /*texture*/ ) { //console.warn( 'Abstract class.' ); } - destroySampler() {} + /** + * This method does nothing since WebGL 2 has no concept of samplers. + * + * @param {Texture} texture - The texture to destroy the sampler for. + */ + destroySampler( /*texture*/ ) {} // node builder + /** + * Returns a node builder for the given render object. + * + * @param {RenderObject} object - The render object. + * @param {Renderer} renderer - The renderer. + * @return {GLSLNodeBuilder} The node builder. + */ createNodeBuilder( object, renderer ) { return new GLSLNodeBuilder( object, renderer ); @@ -41429,6 +55696,11 @@ class WebGLBackend extends Backend { // program + /** + * Creates a shader program from the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ createProgram( program ) { const gl = this.gl; @@ -41445,12 +55717,23 @@ class WebGLBackend extends Backend { } - destroyProgram( /*program*/ ) { + /** + * Destroys the shader program of the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ + destroyProgram( program ) { - console.warn( 'Abstract class.' ); + this.delete( program ); } + /** + * Creates a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ createRenderPipeline( renderObject, promises ) { const gl = this.gl; @@ -41509,6 +55792,14 @@ class WebGLBackend extends Backend { } + /** + * Formats the source code of error messages. + * + * @private + * @param {String} string - The code. + * @param {Number} errorLine - The error line. + * @return {String} The formatted code. + */ _handleSource( string, errorLine ) { const lines = string.split( '\n' ); @@ -41528,6 +55819,15 @@ class WebGLBackend extends Backend { } + /** + * Gets the shader compilation errors from the info log. + * + * @private + * @param {WebGL2RenderingContext} gl - The rendering context. + * @param {WebGLShader} shader - The WebGL shader object. + * @param {String} type - The shader type. + * @return {String} The shader errors. + */ _getShaderErrors( gl, shader, type ) { const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); @@ -41549,6 +55849,14 @@ class WebGLBackend extends Backend { } + /** + * Logs shader compilation errors. + * + * @private + * @param {WebGLProgram} programGPU - The WebGL program. + * @param {WebGLShader} glFragmentShader - The fragment shader as a native WebGL shader object. + * @param {WebGLShader} glVertexShader - The vertex shader as a native WebGL shader object. + */ _logProgramError( programGPU, glFragmentShader, glVertexShader ) { if ( this.renderer.debug.checkShaderErrors ) { @@ -41591,6 +55899,13 @@ class WebGLBackend extends Backend { } + /** + * Completes the shader program setup for the given render object. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @param {RenderPipeline} pipeline - The render pipeline. + */ _completeCompile( renderObject, pipeline ) { const { state, gl } = this; @@ -41619,6 +55934,12 @@ class WebGLBackend extends Backend { } + /** + * Creates a compute pipeline for the given compute node. + * + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ createComputePipeline( computePipeline, bindings ) { const { state, gl } = this; @@ -41713,7 +56034,15 @@ class WebGLBackend extends Backend { } - createBindings( bindGroup, bindings ) { + /** + * Creates bindings from the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + createBindings( bindGroup, bindings /*, cacheIndex, version*/ ) { if ( this._knownBindings.has( bindings ) === false ) { @@ -41744,7 +56073,15 @@ class WebGLBackend extends Backend { } - updateBindings( bindGroup /*, bindings*/ ) { + /** + * Updates the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + updateBindings( bindGroup /*, bindings, cacheIndex, version*/ ) { const { gl } = this; @@ -41784,6 +56121,11 @@ class WebGLBackend extends Backend { } + /** + * Updates a buffer binding. + * + * @param {Buffer} binding - The buffer binding to update. + */ updateBinding( binding ) { const gl = this.gl; @@ -41803,6 +56145,11 @@ class WebGLBackend extends Backend { // attributes + /** + * Creates the GPU buffer of an indexed shader attribute. + * + * @param {BufferAttribute} attribute - The indexed buffer attribute. + */ createIndexAttribute( attribute ) { const gl = this.gl; @@ -41811,6 +56158,11 @@ class WebGLBackend extends Backend { } + /** + * Creates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createAttribute( attribute ) { if ( this.has( attribute ) ) return; @@ -41821,6 +56173,11 @@ class WebGLBackend extends Backend { } + /** + * Creates the GPU buffer of a storage attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createStorageAttribute( attribute ) { if ( this.has( attribute ) ) return; @@ -41831,24 +56188,34 @@ class WebGLBackend extends Backend { } + /** + * Updates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to update. + */ updateAttribute( attribute ) { this.attributeUtils.updateAttribute( attribute ); } + /** + * Destroys the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to destroy. + */ destroyAttribute( attribute ) { this.attributeUtils.destroyAttribute( attribute ); } - updateSize() { - - //console.warn( 'Abstract class.' ); - - } - + /** + * Checks if the given feature is supported by the backend. + * + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ hasFeature( name ) { const keysMatching = Object.keys( GLFeatureName ).filter( key => GLFeatureName[ key ] === name ); @@ -41865,24 +56232,51 @@ class WebGLBackend extends Backend { } + /** + * Returns the maximum anisotropy texture filtering value. + * + * @return {Number} The maximum anisotropy texture filtering value. + */ getMaxAnisotropy() { return this.capabilities.getMaxAnisotropy(); } - copyTextureToTexture( srcTexture, dstTexture, srcRegion, dstPosition, level ) { + /** + * Copies data of the given source texture to the given destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ + copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { this.textureUtils.copyTextureToTexture( srcTexture, dstTexture, srcRegion, dstPosition, level ); } + /** + * Copies the current bound framebuffer to the given texture. + * + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ copyFramebufferToTexture( texture, renderContext, rectangle ) { this.textureUtils.copyFramebufferToTexture( texture, renderContext, rectangle ); } + /** + * Configures the active framebuffer from the given render context. + * + * @private + * @param {RenderContext} descriptor - The render context. + */ _setFramebuffer( descriptor ) { const { gl, state } = this; @@ -41896,6 +56290,8 @@ class WebGLBackend extends Backend { const { samples, depthBuffer, stencilBuffer } = renderTarget; const isCube = renderTarget.isWebGLCubeRenderTarget === true; + const isRenderTarget3D = renderTarget.isRenderTarget3D === true; + const isRenderTargetArray = renderTarget.isRenderTargetArray === true; let msaaFb = renderTargetContextData.msaaFrameBuffer; let depthRenderbuffer = renderTargetContextData.depthRenderbuffer; @@ -41949,7 +56345,19 @@ class WebGLBackend extends Backend { const attachment = gl.COLOR_ATTACHMENT0 + i; - gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0 ); + if ( isRenderTarget3D || isRenderTargetArray ) { + + const layer = this.renderer._activeCubeFace; + + gl.framebufferTextureLayer( gl.FRAMEBUFFER, attachment, textureData.textureGPU, 0, layer ); + + } else { + + gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0 ); + + } + + } @@ -42041,10 +56449,17 @@ class WebGLBackend extends Backend { } - + /** + * Computes the VAO key for the given index and attributes. + * + * @private + * @param {BufferAttribute?} index - The index. `null` for non-indexed geometries. + * @param {Array} attributes - An array of buffer attributes. + * @return {String} The VAO key. + */ _getVaoKey( index, attributes ) { - let key = []; + let key = ''; if ( index !== null ) { @@ -42066,6 +56481,14 @@ class WebGLBackend extends Backend { } + /** + * Creates a VAO from the index and attributes. + * + * @private + * @param {BufferAttribute?} index - The index. `null` for non-indexed geometries. + * @param {Array} attributes - An array of buffer attributes. + * @return {Object} The VAO data. + */ _createVao( index, attributes ) { const { gl } = this; @@ -42143,6 +56566,13 @@ class WebGLBackend extends Backend { } + /** + * Creates a transform feedback from the given transform buffers. + * + * @private + * @param {Array} transformBuffers - The transform buffers. + * @return {WebGLTransformFeedback} The transform feedback. + */ _getTransformFeedback( transformBuffers ) { let key = ''; @@ -42183,7 +56613,13 @@ class WebGLBackend extends Backend { } - + /** + * Setups the given bindings. + * + * @private + * @param {Array} bindings - The bindings. + * @param {WebGLProgram} programGPU - The WebGL program. + */ _setupBindings( bindings, programGPU ) { const gl = this.gl; @@ -42213,6 +56649,12 @@ class WebGLBackend extends Backend { } + /** + * Binds the given uniforms. + * + * @private + * @param {Array} bindings - The bindings. + */ _bindUniforms( bindings ) { const { gl, state } = this; @@ -42241,6 +56683,9 @@ class WebGLBackend extends Backend { } + /** + * Frees internal resources. + */ dispose() { this.renderer.domElement.removeEventListener( 'webglcontextlost', this._onContextLost ); @@ -42544,32 +56989,90 @@ const GPUFeatureName = { Subgroups: 'subgroups' }; +/** + * Represents a sampler binding type. + * + * @private + * @augments Binding + */ class Sampler extends Binding { + /** + * Constructs a new sampler. + * + * @param {String} name - The samplers's name. + * @param {Texture?} texture - The texture this binding is referring to. + */ constructor( name, texture ) { super( name ); + /** + * The texture the sampler is referring to. + * + * @type {Texture?} + */ this.texture = texture; + + /** + * The binding's version. + * + * @type {Number} + */ this.version = texture ? texture.version : 0; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampler = true; } } +/** + * A special form of sampler binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments Sampler + */ class NodeSampler extends Sampler { + /** + * Constructs a new node-based sampler. + * + * @param {String} name - The samplers's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( name, textureNode, groupNode ) { super( name, textureNode ? textureNode.value : null ); + /** + * The texture node. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; } + /** + * Updates the texture value of this sampler. + */ update() { this.texture = this.textureNode.value; @@ -42578,14 +57081,38 @@ class NodeSampler extends Sampler { } +/** + * Represents a storage buffer binding type. + * + * @private + * @augments Buffer + */ class StorageBuffer extends Buffer { + /** + * Constructs a new uniform buffer. + * + * @param {String} name - The buffer's name. + * @param {BufferAttribute} attribute - The buffer attribute. + */ constructor( name, attribute ) { super( name, attribute ? attribute.array : null ); + /** + * This flag can be used for type testing. + * + * @type {BufferAttribute} + */ this.attribute = attribute; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageBuffer = true; } @@ -42594,18 +57121,53 @@ class StorageBuffer extends Buffer { let _id = 0; +/** + * A special form of storage buffer binding type. + * It's buffer value is managed by a node object. + * + * @private + * @augments StorageBuffer + */ class NodeStorageBuffer extends StorageBuffer { + /** + * Constructs a new node-based storage buffer. + * + * @param {StorageBufferNode} nodeUniform - The storage buffer node. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( nodeUniform, groupNode ) { super( 'StorageBuffer_' + _id ++, nodeUniform ? nodeUniform.value : null ); + /** + * The node uniform. + * + * @type {StorageBufferNode} + */ this.nodeUniform = nodeUniform; + + /** + * The access type. + * + * @type {String} + */ this.access = nodeUniform ? nodeUniform.access : NodeAccess.READ_WRITE; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; } + /** + * The storage buffer. + * + * @type {BufferAttribute} + */ get buffer() { return this.nodeUniform.value; @@ -42614,12 +57176,27 @@ class NodeStorageBuffer extends StorageBuffer { } +/** + * A WebGPU backend utility module used by {@link WebGPUTextureUtils}. + * + * @private + */ class WebGPUTexturePassUtils extends DataMap { + /** + * Constructs a new utility object. + * + * @param {GPUDevice} device - The WebGPU device. + */ constructor( device ) { super(); + /** + * The WebGPU device. + * + * @type {GPUDevice} + */ this.device = device; const mipmapVertexSource = ` @@ -42684,23 +57261,62 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } `; + + /** + * The mipmap GPU sampler. + * + * @type {GPUSampler} + */ this.mipmapSampler = device.createSampler( { minFilter: GPUFilterMode.Linear } ); + + /** + * The flipY GPU sampler. + * + * @type {GPUSampler} + */ this.flipYSampler = device.createSampler( { minFilter: GPUFilterMode.Nearest } ); //@TODO?: Consider using textureLoad() - // We'll need a new pipeline for every texture format used. + /** + * A cache for GPU render pipelines used for copy/transfer passes. + * Every texture format requires a unique pipeline. + * + * @type {Object} + */ this.transferPipelines = {}; + + /** + * A cache for GPU render pipelines used for flipY passes. + * Every texture format requires a unique pipeline. + * + * @type {Object} + */ this.flipYPipelines = {}; + /** + * The mipmap vertex shader module. + * + * @type {GPUShaderModule} + */ this.mipmapVertexShaderModule = device.createShaderModule( { label: 'mipmapVertex', code: mipmapVertexSource } ); + /** + * The mipmap fragment shader module. + * + * @type {GPUShaderModule} + */ this.mipmapFragmentShaderModule = device.createShaderModule( { label: 'mipmapFragment', code: mipmapFragmentSource } ); + /** + * The flipY fragment shader module. + * + * @type {GPUShaderModule} + */ this.flipYFragmentShaderModule = device.createShaderModule( { label: 'flipYFragment', code: flipYFragmentSource @@ -42708,6 +57324,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Returns a render pipeline for the internal copy render pass. The pass + * requires a unique render pipeline for each texture format. + * + * @param {String} format - The GPU texture format + * @return {GPURenderPipeline} The GPU render pipeline. + */ getTransferPipeline( format ) { let pipeline = this.transferPipelines[ format ]; @@ -42740,6 +57363,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Returns a render pipeline for the flipY render pass. The pass + * requires a unique render pipeline for each texture format. + * + * @param {String} format - The GPU texture format + * @return {GPURenderPipeline} The GPU render pipeline. + */ getFlipYPipeline( format ) { let pipeline = this.flipYPipelines[ format ]; @@ -42772,6 +57402,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Flip the contents of the given GPU texture along its vertical axis. + * + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureGPUDescriptor - The texture descriptor. + * @param {Number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. + */ flipY( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) { const format = textureGPUDescriptor.format; @@ -42842,6 +57479,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Generates mipmaps for the given GPU texture. + * + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureGPUDescriptor - The texture descriptor. + * @param {Number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. + */ generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) { const textureData = this.get( textureGPU ); @@ -42867,6 +57511,15 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Since multiple copy render passes are required to generate mipmaps, the passes + * are managed as render bundles to improve performance. + * + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureGPUDescriptor - The texture descriptor. + * @param {Number} baseArrayLayer - The index of the first array layer accessible to the texture view. + * @return {Array} An array of render bundles. + */ _mipmapCreateBundles( textureGPU, textureGPUDescriptor, baseArrayLayer ) { const pipeline = this.getTransferPipeline( textureGPUDescriptor.format ); @@ -42932,6 +57585,12 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Executes the render bundles. + * + * @param {GPUCommandEncoder} commandEncoder - The GPU command encoder. + * @param {Array} passes - An array of render bundles. + */ _mipmapRunBundles( commandEncoder, passes ) { const levels = passes.length; @@ -42965,25 +57624,82 @@ const _compareToWebGPU = { const _flipMap = [ 0, 1, 3, 2, 4, 5 ]; +/** + * A WebGPU backend utility module for managing textures. + * + * @private + */ class WebGPUTextureUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; + /** + * A reference to the pass utils. + * + * @type {WebGPUTexturePassUtils?} + * @default null + */ this._passUtils = null; + /** + * A dictionary for managing default textures. The key + * is the texture format, the value the texture object. + * + * @type {Object} + */ this.defaultTexture = {}; + + /** + * A dictionary for managing default cube textures. The key + * is the texture format, the value the texture object. + * + * @type {Object} + */ this.defaultCubeTexture = {}; + + /** + * A default video frame. + * + * @type {VideoFrame?} + * @default null + */ this.defaultVideoFrame = null; + /** + * Represents the color attachment of the default framebuffer. + * + * @type {GPUTexture?} + * @default null + */ this.colorBuffer = null; + /** + * Represents the depth attachment of the default framebuffer. + * + * @type {DepthTexture} + */ this.depthTexture = new DepthTexture(); this.depthTexture.name = 'depthBuffer'; } + /** + * Creates a GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( texture ) { const backend = this.backend; @@ -43019,6 +57735,12 @@ class WebGPUTextureUtils { } + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { let textureGPU; @@ -43043,6 +57765,13 @@ class WebGPUTextureUtils { } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + * @return {undefined} + */ createTexture( texture, options = {} ) { const backend = this.backend; @@ -43154,6 +57883,11 @@ class WebGPUTextureUtils { } + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { const backend = this.backend; @@ -43167,6 +57901,11 @@ class WebGPUTextureUtils { } + /** + * Destroys the GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to destroy the sampler for. + */ destroySampler( texture ) { const backend = this.backend; @@ -43176,6 +57915,11 @@ class WebGPUTextureUtils { } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { const textureData = this.backend.get( texture ); @@ -43202,6 +57946,12 @@ class WebGPUTextureUtils { } + /** + * Returns the color buffer representing the color + * attachment of the default framebuffer. + * + * @return {GPUTexture} The color buffer. + */ getColorBuffer() { if ( this.colorBuffer ) this.colorBuffer.destroy(); @@ -43225,6 +57975,14 @@ class WebGPUTextureUtils { } + /** + * Returns the depth buffer representing the depth + * attachment of the default framebuffer. + * + * @param {Boolean} [depth=true] - Whether depth is enabled or not. + * @param {Boolean} [stencil=false] - Whether stencil is enabled or not. + * @return {GPUTexture} The depth buffer. + */ getDepthBuffer( depth = true, stencil = false ) { const backend = this.backend; @@ -43271,6 +58029,12 @@ class WebGPUTextureUtils { } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { const textureData = this.backend.get( texture ); @@ -43322,6 +58086,18 @@ class WebGPUTextureUtils { } + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { const device = this.backend.device; @@ -43371,6 +58147,13 @@ class WebGPUTextureUtils { } + /** + * Returns `true` if the given texture is an environment map. + * + * @private + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the given texture is an environment map or not. + */ _isEnvironmentTexture( texture ) { const mapping = texture.mapping; @@ -43379,6 +58162,13 @@ class WebGPUTextureUtils { } + /** + * Returns the default GPU texture for the given format. + * + * @private + * @param {String} format - The GPU format. + * @return {GPUTexture} The GPU texture. + */ _getDefaultTextureGPU( format ) { let defaultTexture = this.defaultTexture[ format ]; @@ -43399,6 +58189,13 @@ class WebGPUTextureUtils { } + /** + * Returns the default GPU cube texture for the given format. + * + * @private + * @param {String} format - The GPU format. + * @return {GPUTexture} The GPU texture. + */ _getDefaultCubeTextureGPU( format ) { let defaultCubeTexture = this.defaultTexture[ format ]; @@ -43419,6 +58216,12 @@ class WebGPUTextureUtils { } + /** + * Returns the default video frame used as default data in context of video textures. + * + * @private + * @return {VideoFrame} The video frame. + */ _getDefaultVideoFrame() { let defaultVideoFrame = this.defaultVideoFrame; @@ -43440,6 +58243,15 @@ class WebGPUTextureUtils { } + /** + * Uploads cube texture image data to the GPU memory. + * + * @private + * @param {Array} images - The cube image data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + * @param {Boolean} flipY - Whether to flip texture data along their vertical axis or not. + */ _copyCubeMapToTexture( images, textureGPU, textureDescriptorGPU, flipY ) { for ( let i = 0; i < 6; i ++ ) { @@ -43462,13 +58274,24 @@ class WebGPUTextureUtils { } + /** + * Uploads texture image data to the GPU memory. + * + * @private + * @param {HTMLImageElement|ImageBitmap|HTMLCanvasElement} image - The image data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + * @param {Number} originDepth - The origin depth. + * @param {Boolean} flipY - Whether to flip texture data along their vertical axis or not. + */ _copyImageToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY ) { const device = this.backend.device; device.queue.copyExternalImageToTexture( { - source: image + source: image, + flipY: flipY }, { texture: textureGPU, mipLevel: 0, @@ -43480,14 +58303,14 @@ class WebGPUTextureUtils { } ); - if ( flipY === true ) { - - this._flipY( textureGPU, textureDescriptorGPU, originDepth ); - - } - } + /** + * Returns the pass utils singleton. + * + * @private + * @return {WebGPUTexturePassUtils} The utils instance. + */ _getPassUtils() { let passUtils = this._passUtils; @@ -43502,18 +58325,45 @@ class WebGPUTextureUtils { } + /** + * Generates mipmaps for the given GPU texture. + * + * @private + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureDescriptorGPU - The texture descriptor. + * @param {Number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. + */ _generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0 ) { this._getPassUtils().generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer ); } + /** + * Flip the contents of the given GPU texture along its vertical axis. + * + * @private + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureDescriptorGPU - The texture descriptor. + * @param {Number} [originDepth=0] - The origin depth. + */ _flipY( textureGPU, textureDescriptorGPU, originDepth = 0 ) { this._getPassUtils().flipY( textureGPU, textureDescriptorGPU, originDepth ); } + /** + * Uploads texture buffer data to the GPU memory. + * + * @private + * @param {Object} image - An object defining the image buffer data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + * @param {Number} originDepth - The origin depth. + * @param {Boolean} flipY - Whether to flip texture data along their vertical axis or not. + * @param {Number} [depth=0] - TODO. + */ _copyBufferToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY, depth = 0 ) { // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture() @@ -43551,6 +58401,14 @@ class WebGPUTextureUtils { } + /** + * Uploads compressed texture data to the GPU memory. + * + * @private + * @param {Array} mipmaps - An array with mipmap data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + */ _copyCompressedBufferToTexture( mipmaps, textureGPU, textureDescriptorGPU ) { // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture() @@ -43598,10 +58456,16 @@ class WebGPUTextureUtils { } + /** + * This method is only relevant for compressed texture formats. It returns a block + * data descriptor for the given GPU compressed texture format. + * + * @private + * @param {String} format - The GPU compressed texture format. + * @return {Object} The block data descriptor. + */ _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 @@ -43635,6 +58499,13 @@ class WebGPUTextureUtils { } + /** + * Converts the three.js uv wrapping constants to GPU address mode constants. + * + * @private + * @param {Number} value - The three.js constant defining a uv wrapping mode. + * @return {String} The GPU address mode. + */ _convertAddressMode( value ) { let addressMode = GPUAddressMode.ClampToEdge; @@ -43653,6 +58524,13 @@ class WebGPUTextureUtils { } + /** + * Converts the three.js filter constants to GPU filter constants. + * + * @private + * @param {Number} value - The three.js constant defining a filter mode. + * @return {String} The GPU filter mode. + */ _convertFilterMode( value ) { let filterMode = GPUFilterMode.Linear; @@ -43667,6 +58545,13 @@ class WebGPUTextureUtils { } + /** + * Returns the bytes-per-texel value for the given GPU texture format. + * + * @private + * @param {String} format - The GPU texture format. + * @return {Number} The bytes-per-texel. + */ _getBytesPerTexel( format ) { // 8-bit formats @@ -43723,6 +58608,13 @@ class WebGPUTextureUtils { } + /** + * Returns the corresponding typed array type for the given GPU texture format. + * + * @private + * @param {String} format - The GPU texture format. + * @return {TypedArray.constructor} The typed array type. + */ _getTypedArrayType( format ) { if ( format === GPUTextureFormat.R8Uint ) return Uint8Array; @@ -43773,6 +58665,13 @@ class WebGPUTextureUtils { } + /** + * Returns the GPU dimensions for the given texture. + * + * @private + * @param {Texture} texture - The texture. + * @return {String} The GPU dimension. + */ _getDimension( texture ) { let dimension; @@ -43793,6 +58692,14 @@ class WebGPUTextureUtils { } +/** + * Returns the GPU format for the given texture. + * + * @param {Texture} texture - The texture. + * @param {GPUDevice?} [device=null] - The GPU device which is used for feature detection. + * It is not necessary to apply the device for most formats. + * @return {String} The GPU format. + */ function getFormat( texture, device = null ) { const format = texture.format; @@ -44212,6 +59119,7 @@ const wgslTypeLib$1 = { 'texture_multisampled_2d': 'cubeTexture', 'texture_depth_2d': 'depthTexture', + 'texture_depth_multisampled_2d': 'depthTexture', 'texture_3d': 'texture3D', @@ -44494,30 +59402,83 @@ if ( ( typeof navigator !== 'undefined' && /Firefox|Deno/g.test( navigator.userA } -// - +/** + * A node builder targeting WGSL. + * + * This module generates WGSL shader code from node materials and also + * generates the respective bindings and vertex buffer definitions. These + * data are later used by the renderer to create render and compute pipelines + * for render objects. + * + * @augments NodeBuilder + */ class WGSLNodeBuilder extends NodeBuilder { + /** + * Constructs a new WGSL node builder renderer. + * + * @param {Object3D} object - The 3D object. + * @param {Renderer} renderer - The renderer. + */ constructor( object, renderer ) { super( object, renderer, new WGSLNodeParser() ); + /** + * A dictionary that holds for each shader stage ('vertex', 'fragment', 'compute') + * another dictionary which manages UBOs per group ('render','frame','object'). + * + * @type {Object>} + */ this.uniformGroups = {}; + /** + * A dictionary that holds for each shader stage a Map of builtins. + * + * @type {Object>} + */ this.builtins = {}; + /** + * A dictionary that holds for each shader stage a Set of directives. + * + * @type {Object>} + */ this.directives = {}; + /** + * A map for managing scope arrays. Only relevant for when using + * {@link module:WorkgroupInfoNode} in context of compute shaders. + * + * @type {Map} + */ this.scopedArrays = new Map(); } + /** + * Checks if the given texture requires a manual conversion to the working color space. + * + * @param {Texture} texture - The texture to check. + * @return {Boolean} Whether the given texture requires a conversion to working color space or not. + */ needsToWorkingColorSpace( texture ) { return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace; } + /** + * Generates the WGSL snippet for sampled textures. + * + * @private + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ _generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44544,6 +59505,15 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling video textures. + * + * @private + * @param {String} textureProperty - The name of the video texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ _generateVideoSample( textureProperty, uvSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44558,6 +59528,18 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling textures with explicit mip level. + * + * @private + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ _generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( ( shaderStage === 'fragment' || shaderStage === 'compute' ) && this.isUnfilterable( texture ) === false ) { @@ -44576,9 +59558,15 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates a wrap function used in context of textures. + * + * @param {Texture} texture - The texture to generate the function for. + * @return {String} The name of the generated function. + */ generateWrapFunction( texture ) { - const functionName = `tsl_coord_${ wrapNames[ texture.wrapS ] }S_${ wrapNames[ texture.wrapT ] }T`; + const functionName = `tsl_coord_${ wrapNames[ texture.wrapS ] }S_${ wrapNames[ texture.wrapT ] }_${texture.isData3DTexture ? '3d' : '2d'}T`; let nodeCode = wgslCodeCache[ functionName ]; @@ -44586,7 +59574,9 @@ class WGSLNodeBuilder extends NodeBuilder { const includes = []; - let code = `fn ${ functionName }( coord : vec2f ) -> vec2f {\n\n\treturn vec2f(\n`; + // For 3D textures, use vec3f; for texture arrays, keep vec2f since array index is separate + const coordType = texture.isData3DTexture ? 'vec3f' : 'vec2f'; + let code = `fn ${functionName}( coord : ${coordType} ) -> ${coordType} {\n\n\treturn ${coordType}(\n`; const addWrapSnippet = ( wrap, axis ) => { @@ -44624,6 +59614,13 @@ class WGSLNodeBuilder extends NodeBuilder { addWrapSnippet( texture.wrapT, 'y' ); + if ( texture.isData3DTexture ) { + + code += ',\n'; + addWrapSnippet( texture.wrapR, 'z' ); + + } + code += '\n\t);\n\n}\n'; wgslCodeCache[ functionName ] = nodeCode = new CodeNode( code, includes ); @@ -44636,6 +59633,16 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates a WGSL variable that holds the texture dimension of the given texture. + * It also returns information about the the number of layers (elements) of an arrayed + * texture as well as the cube face count of cube textures. + * + * @param {Texture} texture - The texture to generate the function for. + * @param {String} textureProperty - The name of the video texture uniform in the shader. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The name of the dimension variable. + */ generateTextureDimension( texture, textureProperty, levelSnippet ) { const textureData = this.getDataFromNode( texture, this.shaderStage, this.globalCache ); @@ -44647,29 +59654,72 @@ class WGSLNodeBuilder extends NodeBuilder { if ( textureData.dimensionsSnippet[ levelSnippet ] === undefined ) { let textureDimensionsParams; + let dimensionType; const { primarySamples } = this.renderer.backend.utils.getTextureSampleData( texture ); + const isMultisampled = primarySamples > 1; + + if ( texture.isData3DTexture ) { + + dimensionType = 'vec3'; + + } else { + + // Regular 2D textures, depth textures, etc. + dimensionType = 'vec2'; + + } - if ( primarySamples > 1 ) { + // Build parameters string based on texture type and multisampling + if ( isMultisampled || texture.isVideoTexture || texture.isStorageTexture ) { textureDimensionsParams = textureProperty; } else { - textureDimensionsParams = `${ textureProperty }, u32( ${ levelSnippet } )`; + textureDimensionsParams = `${textureProperty}${levelSnippet ? `, u32( ${ levelSnippet } )` : ''}`; } - textureDimensionNode = new VarNode( new ExpressionNode( `textureDimensions( ${ textureDimensionsParams } )`, 'uvec2' ) ); + textureDimensionNode = new VarNode( new ExpressionNode( `textureDimensions( ${ textureDimensionsParams } )`, dimensionType ) ); textureData.dimensionsSnippet[ levelSnippet ] = textureDimensionNode; + if ( texture.isDataArrayTexture || texture.isData3DTexture ) { + + textureData.arrayLayerCount = new VarNode( + new ExpressionNode( + `textureNumLayers(${textureProperty})`, + 'u32' + ) + ); + + } + + // For cube textures, we know it's always 6 faces + if ( texture.isTextureCube ) { + + textureData.cubeFaceCount = new VarNode( + new ExpressionNode( '6u', 'u32' ) + ); + + } + } return textureDimensionNode.build( this ); } + /** + * Generates the WGSL snippet for a manual filtered texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The WGSL snippet. + */ generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet = '0u' ) { this._include( 'biquadraticTexture' ); @@ -44681,17 +59731,39 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for a texture lookup with explicit level-of-detail. + * Since it's a lookup, no sampling or filtering is applied. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The WGSL snippet. + */ generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, levelSnippet = '0u' ) { const wrapFunction = this.generateWrapFunction( texture ); const textureDimension = this.generateTextureDimension( texture, textureProperty, levelSnippet ); - const coordSnippet = `vec2u( ${ wrapFunction }( ${ uvSnippet } ) * vec2f( ${ textureDimension } ) )`; + const vecType = texture.isData3DTexture ? 'vec3' : 'vec2'; + const coordSnippet = `${vecType}(${wrapFunction}(${uvSnippet}) * ${vecType}(${textureDimension}))`; return this.generateTextureLoad( texture, textureProperty, coordSnippet, depthSnippet, levelSnippet ); } + /** + * Generates the WGSL snippet that reads a single texel from a texture without sampling or filtering. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The WGSL snippet. + */ generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0u' ) { if ( texture.isVideoTexture === true || texture.isStorageTexture === true ) { @@ -44710,18 +59782,39 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet that writes a single texel to a texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} valueSnippet - A WGSL snippet that represent the new texel value. + * @return {String} The WGSL snippet. + */ generateTextureStore( texture, textureProperty, uvIndexSnippet, valueSnippet ) { return `textureStore( ${ textureProperty }, ${ uvIndexSnippet }, ${ valueSnippet } )`; } + /** + * Returns `true` if the sampled values of the given texture should be compared against a reference value. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the sampled values of the given texture should be compared against a reference value or not. + */ isSampleCompare( texture ) { return texture.isDepthTexture === true && texture.compareFunction !== null; } + /** + * Returns `true` if the given texture is unfilterable. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the given texture is unfilterable or not. + */ isUnfilterable( texture ) { return this.getComponentTypeFromTexture( texture ) !== 'float' || @@ -44731,6 +59824,16 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for sampling/loading the given texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTexture( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { let snippet = null; @@ -44753,6 +59856,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for sampling/loading the given texture using explicit gradients. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {Array} gradSnippet - An array holding both gradient WGSL snippets. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44768,6 +59882,18 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for sampling a depth texture and comparing the sampled depth values + * against a reference value. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} compareSnippet - A WGSL snippet that represents the reference value. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44782,6 +59908,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling textures with explicit mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) { let snippet = null; @@ -44800,6 +59937,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling textures with a bias to the mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} biasSnippet - A WGSL snippet that represents the bias to apply to the mip level before sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -44814,6 +59962,13 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns a WGSL snippet that represents the property name of the given node. + * + * @param {Node} node - The node. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The property name. + */ getPropertyName( node, shaderStage = this.shaderStage ) { if ( node.isNodeVarying === true && node.needsInterpolation === true ) { @@ -44849,18 +60004,36 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns the output struct name. + * + * @return {String} The name of the output struct. + */ getOutputStructName() { return 'output'; } + /** + * Returns uniforms group count for the given shader stage. + * + * @private + * @param {String} shaderStage - The shader stage. + * @return {Number} The uniforms group count for the given shader stage. + */ _getUniformGroupCount( shaderStage ) { return Object.keys( this.uniforms[ shaderStage ] ).length; } + /** + * Returns the native shader operator name for a given generic name. + * + * @param {String} op - The operator name to resolve. + * @return {String} The resolved operator name. + */ getFunctionOperator( op ) { const fnOp = wgslFnOpLib[ op ]; @@ -44877,6 +60050,13 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns the node access for the given node and shader stage. + * + * @param {StorageTextureNode|StorageBufferNode} node - The storage node. + * @param {String} shaderStage - The shader stage. + * @return {String} The node access. + */ getNodeAccess( node, shaderStage ) { if ( shaderStage !== 'compute' ) @@ -44886,12 +60066,32 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns A WGSL snippet representing the storage access. + * + * @param {StorageTextureNode|StorageBufferNode} node - The storage node. + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet representing the storage access. + */ getStorageAccess( node, shaderStage ) { return accessNames[ this.getNodeAccess( node, shaderStage ) ]; } + /** + * This method is one of the more important ones since it's responsible + * for generating a matching binding instance for the given uniform node. + * + * These bindings are later used in the renderer to create bind groups + * and layouts. + * + * @param {UniformNode} node - The uniform node. + * @param {String} type - The node data type. + * @param {String} shaderStage - The shader stage. + * @param {String?} [name=null] - An optional uniform name. + * @return {NodeUniform} The node uniform object. + */ getUniformFromNode( node, type, shaderStage, name = null ) { const uniformNode = super.getUniformFromNode( node, type, shaderStage, name ); @@ -44988,6 +60188,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * This method should be used whenever builtins are required in nodes. + * The internal builtins data structure will make sure builtins are + * defined in the WGSL source. + * + * @param {String} name - The builtin name. + * @param {String} property - The property name. + * @param {String} type - The node data type. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The property name. + */ getBuiltin( name, property, type, shaderStage = this.shaderStage ) { const map = this.builtins[ shaderStage ] || ( this.builtins[ shaderStage ] = new Map() ); @@ -45006,12 +60217,24 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns `true` if the given builtin is defined in the given shader stage. + * + * @param {String} name - The builtin name. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} Whether the given builtin is defined in the given shader stage or not. + */ hasBuiltin( name, shaderStage = this.shaderStage ) { return ( this.builtins[ shaderStage ] !== undefined && this.builtins[ shaderStage ].has( name ) ); } + /** + * Returns the vertex index builtin. + * + * @return {String} The vertex index. + */ getVertexIndex() { if ( this.shaderStage === 'vertex' ) { @@ -45024,6 +60247,12 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Builds the given shader node. + * + * @param {ShaderNodeInternal} shaderNode - The shader node. + * @return {String} The WGSL function code. + */ buildFunctionCode( shaderNode ) { const layout = shaderNode.layout; @@ -45058,6 +60287,11 @@ ${ flowData.code } } + /** + * Returns the instance index builtin. + * + * @return {String} The instance index. + */ getInstanceIndex() { if ( this.shaderStage === 'vertex' ) { @@ -45070,12 +60304,22 @@ ${ flowData.code } } + /** + * Returns the invocation local index builtin. + * + * @return {String} The invocation local index. + */ getInvocationLocalIndex() { return this.getBuiltin( 'local_invocation_index', 'invocationLocalIndex', 'u32', 'attribute' ); } + /** + * Returns the subgroup size builtin. + * + * @return {String} The subgroup size. + */ getSubgroupSize() { this.enableSubGroups(); @@ -45084,6 +60328,11 @@ ${ flowData.code } } + /** + * Returns the invocation subgroup index builtin. + * + * @return {String} The invocation subgroup index. + */ getInvocationSubgroupIndex() { this.enableSubGroups(); @@ -45092,6 +60341,11 @@ ${ flowData.code } } + /** + * Returns the subgroup index builtin. + * + * @return {String} The subgroup index. + */ getSubgroupIndex() { this.enableSubGroups(); @@ -45100,42 +60354,78 @@ ${ flowData.code } } + /** + * Overwritten as a NOP since this method is intended for the WebGL 2 backend. + * + * @return {null} Null. + */ getDrawIndex() { return null; } + /** + * Returns the front facing builtin. + * + * @return {String} The front facing builtin. + */ getFrontFacing() { return this.getBuiltin( 'front_facing', 'isFront', 'bool' ); } + /** + * Returns the frag coord builtin. + * + * @return {String} The frag coord builtin. + */ getFragCoord() { return this.getBuiltin( 'position', 'fragCoord', 'vec4' ) + '.xy'; } + /** + * Returns the frag depth builtin. + * + * @return {String} The frag depth builtin. + */ getFragDepth() { return 'output.' + this.getBuiltin( 'frag_depth', 'depth', 'f32', 'output' ); } + /** + * Returns the clip distances builtin. + * + * @return {String} The clip distances builtin. + */ getClipDistance() { return 'varyings.hw_clip_distances'; } + /** + * Whether to flip texture data along its vertical axis or not. + * + * @return {Boolean} Returns always `false` in context of WGSL. + */ isFlipY() { return false; } + /** + * Enables the given directive for the given shader stage. + * + * @param {String} name - The directive name. + * @param {String} [shaderStage=this.shaderStage] - The shader stage to enable the directive for. + */ enableDirective( name, shaderStage = this.shaderStage ) { const stage = this.directives[ shaderStage ] || ( this.directives[ shaderStage ] = new Set() ); @@ -45143,6 +60433,12 @@ ${ flowData.code } } + /** + * Returns the directives of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} A WGSL snippet that enables the directives of the given stage. + */ getDirectives( shaderStage ) { const snippets = []; @@ -45162,36 +60458,56 @@ ${ flowData.code } } + /** + * Enables the 'subgroups' directive. + */ enableSubGroups() { this.enableDirective( 'subgroups' ); } + /** + * Enables the 'subgroups-f16' directive. + */ enableSubgroupsF16() { this.enableDirective( 'subgroups-f16' ); } + /** + * Enables the 'clip_distances' directive. + */ enableClipDistances() { this.enableDirective( 'clip_distances' ); } + /** + * Enables the 'f16' directive. + */ enableShaderF16() { this.enableDirective( 'f16' ); } + /** + * Enables the 'dual_source_blending' directive. + */ enableDualSourceBlending() { this.enableDirective( 'dual_source_blending' ); } + /** + * Enables hardware clipping. + * + * @param {String} planeCount - The clipping plane count. + */ enableHardwareClipping( planeCount ) { this.enableClipDistances(); @@ -45199,6 +60515,12 @@ ${ flowData.code } } + /** + * Returns the builtins of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} A WGSL snippet that represents the builtins of the given stage. + */ getBuiltins( shaderStage ) { const snippets = []; @@ -45218,6 +60540,17 @@ ${ flowData.code } } + /** + * This method should be used when a new scoped buffer is used in context of + * compute shaders. It adds the array to the internal data structure which is + * later used to generate the respective WGSL. + * + * @param {String} name - The array name. + * @param {String} scope - The scope. + * @param {String} bufferType - The buffer type. + * @param {String} bufferCount - The buffer count. + * @return {String} The array name. + */ getScopedArray( name, scope, bufferType, bufferCount ) { if ( this.scopedArrays.has( name ) === false ) { @@ -45235,6 +60568,13 @@ ${ flowData.code } } + /** + * Returns the scoped arrays of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String|undefined} The WGSL snippet that defines the scoped arrays. + * Returns `undefined` when used in the vertex or fragment stage. + */ getScopedArrays( shaderStage ) { if ( shaderStage !== 'compute' ) { @@ -45257,13 +60597,19 @@ ${ flowData.code } } + /** + * Returns the shader attributes of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the shader attributes. + */ getAttributes( shaderStage ) { const snippets = []; if ( shaderStage === 'compute' ) { - this.getBuiltin( 'global_invocation_id', 'id', 'vec3', 'attribute' ); + this.getBuiltin( 'global_invocation_id', 'globalId', 'vec3', 'attribute' ); this.getBuiltin( 'workgroup_id', 'workgroupId', 'vec3', 'attribute' ); this.getBuiltin( 'local_invocation_id', 'localId', 'vec3', 'attribute' ); this.getBuiltin( 'num_workgroups', 'numWorkgroups', 'vec3', 'attribute' ); @@ -45301,6 +60647,12 @@ ${ flowData.code } } + /** + * Returns the members of the given struct type node as a WGSL string. + * + * @param {StructTypeNode} struct - The struct type node. + * @return {String} The WGSL snippet that defines the struct members. + */ getStructMembers( struct ) { const snippets = []; @@ -45321,6 +60673,12 @@ ${ flowData.code } } + /** + * Returns the structs of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the structs. + */ getStructs( shaderStage ) { const snippets = []; @@ -45346,12 +60704,25 @@ ${ flowData.code } } + /** + * Returns a WGSL string representing a variable. + * + * @param {String} type - The variable's type. + * @param {String} name - The variable's name. + * @return {String} The WGSL snippet that defines a variable. + */ getVar( type, name ) { return `var ${ name } : ${ this.getType( type ) }`; } + /** + * Returns the variables of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the variables. + */ getVars( shaderStage ) { const snippets = []; @@ -45371,6 +60742,12 @@ ${ flowData.code } } + /** + * Returns the varyings of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the varyings. + */ getVaryings( shaderStage ) { const snippets = []; @@ -45423,6 +60800,12 @@ ${ flowData.code } } + /** + * Returns the uniforms of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the uniforms. + */ getUniforms( shaderStage ) { const uniforms = this.uniforms[ shaderStage ]; @@ -45550,6 +60933,9 @@ ${ flowData.code } } + /** + * Controls the code build of the shader stages. + */ buildCode() { const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; @@ -45588,7 +60974,7 @@ ${ flowData.code } if ( flow.length > 0 ) flow += '\n'; - flow += `\t// flow -> ${ slotName }\n\t`; + flow += `\t// flow -> ${ slotName }\n`; } @@ -45650,6 +61036,13 @@ ${ flowData.code } } + /** + * Returns the native shader method name for a given generic name. + * + * @param {String} method - The method name to resolve. + * @param {String} [output=null] - An optional output. + * @return {String} The resolved WGSL method name. + */ getMethod( method, output = null ) { let wgslMethod; @@ -45670,12 +61063,24 @@ ${ flowData.code } } + /** + * Returns the WGSL type of the given node data type. + * + * @param {String} type - The node data type. + * @return {String} The WGSL type. + */ getType( type ) { return wgslTypeLib[ type ] || type; } + /** + * Whether the requested feature is available or not. + * + * @param {String} name - The requested feature. + * @return {Boolean} Whether the requested feature is supported or not. + */ isAvailable( name ) { let result = supports[ name ]; @@ -45700,6 +61105,13 @@ ${ flowData.code } } + /** + * Returns the native shader method name for a given generic name. + * + * @private + * @param {String} method - The method name to resolve. + * @return {String} The resolved WGSL method name. + */ _getWGSLMethod( method ) { if ( wgslPolyfill[ method ] !== undefined ) { @@ -45712,6 +61124,14 @@ ${ flowData.code } } + /** + * Includes the given method name into the current + * function node. + * + * @private + * @param {String} name - The method name to include. + * @return {CodeNode} The respective code node. + */ _include( name ) { const codeNode = wgslPolyfill[ name ]; @@ -45727,6 +61147,13 @@ ${ flowData.code } } + /** + * Returns a WGSL vertex shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getWGSLVertexCode( shaderData ) { return `${ this.getSignature() } @@ -45759,6 +61186,13 @@ fn main( ${shaderData.attributes} ) -> VaryingsStruct { } + /** + * Returns a WGSL fragment shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getWGSLFragmentCode( shaderData ) { return `${ this.getSignature() } @@ -45788,6 +61222,14 @@ fn main( ${shaderData.varyings} ) -> ${shaderData.returnType} { } + /** + * Returns a WGSL compute shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @param {String} workgroupSize - The workgroup size. + * @return {String} The vertex shader. + */ _getWGSLComputeCode( shaderData, workgroupSize ) { return `${ this.getSignature() } @@ -45810,7 +61252,7 @@ ${shaderData.codes} fn main( ${shaderData.attributes} ) { // system - instanceIndex = id.x + id.y * numWorkgroups.x * u32(${workgroupSize}) + id.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize}); + instanceIndex = globalId.x + globalId.y * numWorkgroups.x * u32(${workgroupSize}) + globalId.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize}); // vars ${shaderData.vars} @@ -45823,6 +61265,14 @@ fn main( ${shaderData.attributes} ) { } + /** + * Returns a WGSL struct based on the given name and variables. + * + * @private + * @param {String} name - The struct name. + * @param {String} vars - The struct variables. + * @return {String} The WGSL snippet representing a struct. + */ _getWGSLStruct( name, vars ) { return ` @@ -45832,6 +61282,17 @@ ${vars} } + /** + * Returns a WGSL struct binding. + * + * @private + * @param {String} name - The struct name. + * @param {String} vars - The struct variables. + * @param {String} access - The access. + * @param {Number} [binding=0] - The binding index. + * @param {Number} [group=0] - The group index. + * @return {String} The WGSL snippet representing a struct binding. + */ _getWGSLStructBinding( name, vars, access, binding = 0, group = 0 ) { const structName = name + 'Struct'; @@ -45845,14 +61306,35 @@ var<${access}> ${name} : ${structName};`; } +/** + * A WebGPU backend utility module with common helpers. + * + * @private + */ class WebGPUUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; } + /** + * Returns the depth/stencil GPU format for the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {String} The depth/stencil GPU texture format. + */ getCurrentDepthStencilFormat( renderContext ) { let format; @@ -45875,12 +61357,24 @@ class WebGPUUtils { } + /** + * Returns the GPU format for the given texture. + * + * @param {Texture} texture - The texture. + * @return {String} The GPU texture format. + */ getTextureFormatGPU( texture ) { return this.backend.get( texture ).format; } + /** + * Returns an object that defines the multi-sampling state of the given texture. + * + * @param {Texture} texture - The texture. + * @return {Object} The multi-sampling state. + */ getTextureSampleData( texture ) { let samples; @@ -45911,6 +61405,12 @@ class WebGPUUtils { } + /** + * Returns the default color attachment's GPU format of the current render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {String} The GPU texture format of the default color attachment. + */ getCurrentColorFormat( renderContext ) { let format; @@ -45929,6 +61429,12 @@ class WebGPUUtils { } + /** + * Returns the output color space of the current render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {String} The output color space. + */ getCurrentColorSpace( renderContext ) { if ( renderContext.textures !== null ) { @@ -45941,6 +61447,13 @@ class WebGPUUtils { } + /** + * Returns GPU primitive topology for the given object and material. + * + * @param {Object3D} object - The 3D object. + * @param {Material} material - The material. + * @return {String} The GPU primitive topology. + */ getPrimitiveTopology( object, material ) { if ( object.isPoints ) return GPUPrimitiveTopology.PointList; @@ -45950,6 +61463,14 @@ class WebGPUUtils { } + /** + * Returns a modified sample count from the given sample count value. + * + * That is required since WebGPU does not support arbitrary sample counts. + * + * @param {Number} sampleCount - The input sample count. + * @return {Number} The (potentially updated) output sample count. + */ getSampleCount( sampleCount ) { let count = 1; @@ -45971,6 +61492,12 @@ class WebGPUUtils { } + /** + * Returns the sample count of the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {Number} The sample count. + */ getSampleCountRenderContext( renderContext ) { if ( renderContext.textures !== null ) { @@ -45983,6 +61510,14 @@ class WebGPUUtils { } + /** + * Returns the preferred canvas format. + * + * There is a separate method for this so it's possible to + * honor edge cases for specific devices. + * + * @return {String} The GPU texture format of the canvas. + */ getPreferredCanvasFormat() { // TODO: Remove this check when Quest 34.5 is out @@ -46024,14 +61559,35 @@ const typeArraysToVertexFormatPrefixForItemSize1 = new Map( [ [ Float32Array, 'float32' ] ] ); +/** + * A WebGPU backend utility module for managing shader attributes. + * + * @private + */ class WebGPUAttributeUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; } + /** + * Creates the GPU buffer for the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + * @param {GPUBufferUsage} usage - A flag that indicates how the buffer may be used after its creation. + */ createAttribute( attribute, usage ) { const bufferAttribute = this._getBufferAttribute( attribute ); @@ -46048,16 +61604,27 @@ class WebGPUAttributeUtils { let array = bufferAttribute.array; // patch for INT16 and UINT16 - if ( attribute.normalized === false && ( array.constructor === Int16Array || array.constructor === Uint16Array ) ) { + if ( attribute.normalized === false ) { - const tempArray = new Uint32Array( array.length ); - for ( let i = 0; i < array.length; i ++ ) { + if ( array.constructor === Int16Array ) { - tempArray[ i ] = array[ i ]; + array = new Int32Array( array ); - } + } else if ( array.constructor === Uint16Array ) { + + array = new Uint32Array( array ); - array = tempArray; + if ( usage & GPUBufferUsage.INDEX ) { + + for ( let i = 0; i < array.length; i ++ ) { + + if ( array[ i ] === 0xffff ) array[ i ] = 0xffffffff; // use correct primitive restart index + + } + + } + + } } @@ -46098,6 +61665,11 @@ class WebGPUAttributeUtils { } + /** + * Updates the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ updateAttribute( attribute ) { const bufferAttribute = this._getBufferAttribute( attribute ); @@ -46149,6 +61721,13 @@ class WebGPUAttributeUtils { } + /** + * This method creates the vertex buffer layout data which are + * require when creating a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Array} An array holding objects which describe the vertex buffer layout. + */ createShaderVertexBuffers( renderObject ) { const attributes = renderObject.getAttributes(); @@ -46210,6 +61789,11 @@ class WebGPUAttributeUtils { } + /** + * Destroys the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ destroyAttribute( attribute ) { const backend = this.backend; @@ -46221,24 +61805,32 @@ class WebGPUAttributeUtils { } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ 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, + label: `${ attribute.name }_readback`, size, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ } ); - - const cmdEncoder = device.createCommandEncoder( {} ); + const cmdEncoder = device.createCommandEncoder( { + label: `readback_encoder_${ attribute.name }` + } ); cmdEncoder.copyBufferToBuffer( bufferGPU, @@ -46248,8 +61840,6 @@ class WebGPUAttributeUtils { size ); - readBufferGPU.unmap(); - const gpuCommands = cmdEncoder.finish(); device.queue.submit( [ gpuCommands ] ); @@ -46257,10 +61847,21 @@ class WebGPUAttributeUtils { const arrayBuffer = readBufferGPU.getMappedRange(); - return arrayBuffer; + const dstBuffer = new attribute.array.constructor( arrayBuffer.slice( 0 ) ); + + readBufferGPU.unmap(); + + return dstBuffer.buffer; } + /** + * Returns the vertex format of the given buffer attribute. + * + * @private + * @param {BufferAttribute} geometryAttribute - The buffer attribute. + * @return {String} The vertex format (e.g. 'float32x3'). + */ _getVertexFormat( geometryAttribute ) { const { itemSize, normalized } = geometryAttribute; @@ -46306,12 +61907,27 @@ class WebGPUAttributeUtils { } + /** + * Returns `true` if the given array is a typed array. + * + * @private + * @param {Any} array - The array. + * @return {Boolean} Whether the given array is a typed array or not. + */ _isTypedArray( array ) { return ArrayBuffer.isView( array ) && ! ( array instanceof DataView ); } + /** + * Utility method for handling interleaved buffer attributes correctly. + * To process them, their `InterleavedBuffer` is returned. + * + * @private + * @param {BufferAttribute} attribute - The attribute. + * @return {BufferAttribute|InterleavedBuffer} + */ _getBufferAttribute( attribute ) { if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; @@ -46322,15 +61938,47 @@ class WebGPUAttributeUtils { } +/** + * A WebGPU backend utility module for managing bindings. + * + * When reading the documentation it's helpful to keep in mind that + * all class definitions starting with 'GPU*' are modules from the + * WebGPU API. So for example `BindGroup` is a class from the engine + * whereas `GPUBindGroup` is a class from WebGPU. + * + * @private + */ class WebGPUBindingUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; + + /** + * A cache for managing bind group layouts. + * + * @type {WeakMap,GPUBindGroupLayout>} + */ this.bindGroupLayoutCache = new WeakMap(); } + /** + * Creates a GPU bind group layout for the given bind group. + * + * @param {BindGroup} bindGroup - The bind group. + * @return {GPUBindGroupLayout} The GPU bind group layout. + */ createBindingsLayout( bindGroup ) { const backend = this.backend; @@ -46500,6 +62148,14 @@ class WebGPUBindingUtils { } + /** + * Creates bindings from the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ createBindings( bindGroup, bindings, cacheIndex, version = 0 ) { const { backend, bindGroupLayoutCache } = this; @@ -46553,6 +62209,11 @@ class WebGPUBindingUtils { } + /** + * Updates a buffer binding. + * + * @param {Buffer} binding - The buffer binding to update. + */ updateBinding( binding ) { const backend = this.backend; @@ -46565,6 +62226,13 @@ class WebGPUBindingUtils { } + /** + * Creates a GPU bind group for the given bind group and GPU layout. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {GPUBindGroupLayout} layoutGPU - The GPU bind group layout. + * @return {GPUBindGroup} The GPU bind group. + */ createBindGroup( bindGroup, layoutGPU ) { const backend = this.backend; @@ -46685,20 +62353,48 @@ class WebGPUBindingUtils { } +/** + * A WebGPU backend utility module for managing pipelines. + * + * @private + */ class WebGPUPipelineUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; } - _getSampleCount( renderObjectContext ) { + /** + * Returns the sample count derived from the given render context. + * + * @private + * @param {RenderContext} renderContext - The render context. + * @return {Number} The sample count. + */ + _getSampleCount( renderContext ) { - return this.backend.utils.getSampleCountRenderContext( renderObjectContext ); + return this.backend.utils.getSampleCountRenderContext( renderContext ); } + /** + * Creates a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ createRenderPipeline( renderObject, promises ) { const { object, material, geometry, pipeline } = renderObject; @@ -46858,6 +62554,12 @@ class WebGPUPipelineUtils { } + /** + * Creates GPU render bundle encoder for the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {GPURenderBundleEncoder} The GPU render bundle encoder. + */ createBundleEncoder( renderContext ) { const backend = this.backend; @@ -46878,6 +62580,12 @@ class WebGPUPipelineUtils { } + /** + * Creates a compute pipeline for the given compute node. + * + * @param {ComputePipeline} pipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ createComputePipeline( pipeline, bindings ) { const backend = this.backend; @@ -46908,6 +62616,14 @@ class WebGPUPipelineUtils { } + /** + * Returns the blending state as a descriptor object required + * for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {Object} The blending state. + */ _getBlending( material ) { let color, alpha; @@ -47015,7 +62731,13 @@ class WebGPUPipelineUtils { } } - + /** + * Returns the GPU blend factor which is required for the pipeline creation. + * + * @private + * @param {Number} blend - The blend factor as a three.js constant. + * @return {String} The GPU blend factor. + */ _getBlendFactor( blend ) { let blendFactor; @@ -47083,6 +62805,13 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU stencil compare function which is required for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {String} The GPU stencil compare function. + */ _getStencilCompare( material ) { let stencilCompare; @@ -47132,6 +62861,13 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU stencil operation which is required for the pipeline creation. + * + * @private + * @param {Number} op - A three.js constant defining the stencil operation. + * @return {String} The GPU stencil operation. + */ _getStencilOperation( op ) { let stencilOperation; @@ -47179,6 +62915,13 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU blend operation which is required for the pipeline creation. + * + * @private + * @param {Number} blendEquation - A three.js constant defining the blend equation. + * @return {String} The GPU blend operation. + */ _getBlendOperation( blendEquation ) { let blendOperation; @@ -47214,6 +62957,16 @@ class WebGPUPipelineUtils { } + /** + * Returns the primitive state as a descriptor object required + * for the pipeline creation. + * + * @private + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The geometry. + * @param {Material} material - The material. + * @return {Object} The primitive state. + */ _getPrimitiveState( object, geometry, material ) { const descriptor = {}; @@ -47254,12 +63007,26 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU color write mask which is required for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {String} The GPU color write mask. + */ _getColorWriteMask( material ) { return ( material.colorWrite === true ) ? GPUColorWriteFlags.All : GPUColorWriteFlags.None; } + /** + * Returns the GPU depth compare function which is required for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {String} The GPU depth compare function. + */ _getDepthCompare( material ) { let depthCompare; @@ -47324,14 +63091,41 @@ import 'https://greggman.github.io/webgpu-avoid-redundant-state-setting/webgpu-c //*/ -// - +/** + * A backend implementation targeting WebGPU. + * + * @private + * @augments Backend + */ class WebGPUBackend extends Backend { + /** + * Constructs a new WebGPU backend. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. + * @param {Boolean} [parameters.trackTimestamp=false] - Whether to track timestamps with a Timestamp Query API or not. + * @param {String} [parameters.powerPreference=undefined] - The power preference. + * @param {Object} [parameters.requiredLimits=undefined] - Specifies the limits that are required by the device request. The request will fail if the adapter cannot provide these limits. + * @param {GPUDevice} [parameters.device=undefined] - If there is an existing GPU device on app level, it can be passed to the renderer as a parameter. + */ constructor( parameters = {} ) { super( parameters ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGPUBackend = true; // some parameters require default values other than "undefined" @@ -47339,22 +63133,101 @@ class WebGPUBackend extends Backend { this.parameters.requiredLimits = ( parameters.requiredLimits === undefined ) ? {} : parameters.requiredLimits; + /** + * Whether to track timestamps with a Timestamp Query API or not. + * + * @type {Boolean} + * @default false + */ this.trackTimestamp = ( parameters.trackTimestamp === true ); + /** + * A reference to the device. + * + * @type {GPUDevice?} + * @default null + */ this.device = null; + + /** + * A reference to the context. + * + * @type {GPUCanvasContext?} + * @default null + */ this.context = null; + + /** + * A reference to the color attachment of the default framebuffer. + * + * @type {GPUTexture?} + * @default null + */ this.colorBuffer = null; + + /** + * A reference to the default render pass descriptor. + * + * @type {Object?} + * @default null + */ this.defaultRenderPassdescriptor = null; + /** + * A reference to a backend module holding common utility functions. + * + * @type {WebGPUUtils} + */ this.utils = new WebGPUUtils( this ); + + /** + * A reference to a backend module holding shader attribute-related + * utility functions. + * + * @type {WebGPUAttributeUtils} + */ this.attributeUtils = new WebGPUAttributeUtils( this ); + + /** + * A reference to a backend module holding shader binding-related + * utility functions. + * + * @type {WebGPUBindingUtils} + */ this.bindingUtils = new WebGPUBindingUtils( this ); + + /** + * A reference to a backend module holding shader pipeline-related + * utility functions. + * + * @type {WebGPUPipelineUtils} + */ this.pipelineUtils = new WebGPUPipelineUtils( this ); + + /** + * A reference to a backend module holding shader texture-related + * utility functions. + * + * @type {WebGPUTextureUtils} + */ this.textureUtils = new WebGPUTextureUtils( this ); + + /** + * A map that manages the resolve buffers for occlusion queries. + * + * @type {Map} + */ this.occludedResolveCache = new Map(); } + /** + * Initializes the backend so it is ready for usage. + * + * @async + * @param {Renderer} renderer - The renderer. + * @return {Promise} A Promise that resolves when the backend has been initialized. + */ async init( renderer ) { await super.init( renderer ); @@ -47443,24 +63316,53 @@ class WebGPUBackend extends Backend { } + /** + * The coordinate system of the backend. + * + * @type {Number} + * @readonly + */ get coordinateSystem() { return WebGPUCoordinateSystem; } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { return await this.attributeUtils.getArrayBufferAsync( attribute ); } + /** + * Returns the backend's rendering context. + * + * @return {GPUCanvasContext} The rendering context. + */ getContext() { return this.context; } + /** + * Returns the default render pass descriptor. + * + * In WebGPU, the default framebuffer must be configured + * like custom framebuffers so the backend needs a render + * pass descriptor even when rendering directly to screen. + * + * @private + * @return {Object} The render pass descriptor. + */ _getDefaultRenderPassDescriptor() { let descriptor = this.defaultRenderPassdescriptor; @@ -47515,7 +63417,15 @@ class WebGPUBackend extends Backend { } - _getRenderPassDescriptor( renderContext ) { + /** + * Returns the render pass descriptor for the given render context. + * + * @private + * @param {RenderContext} renderContext - The render context. + * @param {Object} colorAttachmentsConfig - Configuration object for the color attachments. + * @return {Object} The render pass descriptor. + */ + _getRenderPassDescriptor( renderContext, colorAttachmentsConfig = {} ) { const renderTarget = renderContext.renderTarget; const renderTargetData = this.get( renderTarget ); @@ -47525,8 +63435,11 @@ class WebGPUBackend extends Backend { if ( descriptors === undefined || renderTargetData.width !== renderTarget.width || renderTargetData.height !== renderTarget.height || + renderTargetData.dimensions !== renderTarget.dimensions || renderTargetData.activeMipmapLevel !== renderTarget.activeMipmapLevel || - renderTargetData.samples !== renderTarget.samples + renderTargetData.activeCubeFace !== renderContext.activeCubeFace || + renderTargetData.samples !== renderTarget.samples || + renderTargetData.loadOp !== colorAttachmentsConfig.loadOp ) { descriptors = {}; @@ -47556,16 +63469,37 @@ class WebGPUBackend extends Backend { const textures = renderContext.textures; const colorAttachments = []; + let sliceIndex; + for ( let i = 0; i < textures.length; i ++ ) { const textureData = this.get( textures[ i ] ); - const textureView = textureData.texture.createView( { + const viewDescriptor = { + label: `colorAttachment_${ i }`, baseMipLevel: renderContext.activeMipmapLevel, mipLevelCount: 1, baseArrayLayer: renderContext.activeCubeFace, + arrayLayerCount: 1, dimension: GPUTextureViewDimension.TwoD - } ); + }; + + if ( renderTarget.isRenderTarget3D ) { + + sliceIndex = renderContext.activeCubeFace; + + viewDescriptor.baseArrayLayer = 0; + viewDescriptor.dimension = GPUTextureViewDimension.ThreeD; + viewDescriptor.depthOrArrayLayers = textures[ i ].image.depth; + + } else if ( renderTarget.isRenderTargetArray ) { + + viewDescriptor.dimension = GPUTextureViewDimension.TwoDArray; + viewDescriptor.depthOrArrayLayers = textures[ i ].image.depth; + + } + + const textureView = textureData.texture.createView( viewDescriptor ); let view, resolveTarget; @@ -47583,9 +63517,11 @@ class WebGPUBackend extends Backend { colorAttachments.push( { view, + depthSlice: sliceIndex, resolveTarget, loadOp: GPULoadOp.Load, - storeOp: GPUStoreOp.Store + storeOp: GPUStoreOp.Store, + ...colorAttachmentsConfig } ); } @@ -47611,7 +63547,11 @@ class WebGPUBackend extends Backend { renderTargetData.width = renderTarget.width; renderTargetData.height = renderTarget.height; renderTargetData.samples = renderTarget.samples; - renderTargetData.activeMipmapLevel = renderTarget.activeMipmapLevel; + renderTargetData.activeMipmapLevel = renderContext.activeMipmapLevel; + renderTargetData.activeCubeFace = renderContext.activeCubeFace; + renderTargetData.dimensions = renderTarget.dimensions; + renderTargetData.depthSlice = sliceIndex; + renderTargetData.loadOp = colorAttachments[ 0 ].loadOp; } @@ -47619,6 +63559,12 @@ class WebGPUBackend extends Backend { } + /** + * This method is executed at the beginning of a render call and prepares + * the WebGPU state for upcoming render calls + * + * @param {RenderContext} renderContext - The render context. + */ beginRender( renderContext ) { const renderContextData = this.get( renderContext ); @@ -47659,7 +63605,7 @@ class WebGPUBackend extends Backend { } else { - descriptor = this._getRenderPassDescriptor( renderContext ); + descriptor = this._getRenderPassDescriptor( renderContext, { loadOp: GPULoadOp.Load } ); } @@ -47778,6 +63724,12 @@ class WebGPUBackend extends Backend { } + /** + * This method is executed at the end of a render call and finalizes work + * after draw calls. + * + * @param {RenderContext} renderContext - The render context. + */ finishRender( renderContext ) { const renderContextData = this.get( renderContext ); @@ -47866,6 +63818,14 @@ class WebGPUBackend extends Backend { } + /** + * Returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ isOccluded( renderContext, object ) { const renderContextData = this.get( renderContext ); @@ -47874,6 +63834,14 @@ class WebGPUBackend extends Backend { } + /** + * This method processes the result of occlusion queries and writes it + * into render context data. + * + * @async + * @param {RenderContext} renderContext - The render context. + * @return {Promise} A Promise that resolves when the occlusion query results have been processed. + */ async resolveOccludedAsync( renderContext ) { const renderContextData = this.get( renderContext ); @@ -47896,7 +63864,7 @@ class WebGPUBackend extends Backend { for ( let i = 0; i < currentOcclusionQueryObjects.length; i ++ ) { - if ( results[ i ] !== BigInt( 0 ) ) { + if ( results[ i ] === BigInt( 0 ) ) { occluded.add( currentOcclusionQueryObjects[ i ] ); @@ -47912,6 +63880,11 @@ class WebGPUBackend extends Backend { } + /** + * Updates the viewport with the values from the given render context. + * + * @param {RenderContext} renderContext - The render context. + */ updateViewport( renderContext ) { const { currentPass } = this.get( renderContext ); @@ -47921,7 +63894,15 @@ class WebGPUBackend extends Backend { } - clear( color, depth, stencil, renderTargetData = null ) { + /** + * Performs a clear operation. + * + * @param {Boolean} color - Whether the color buffer should be cleared or not. + * @param {Boolean} depth - Whether the depth buffer should be cleared or not. + * @param {Boolean} stencil - Whether the stencil buffer should be cleared or not. + * @param {RenderContext?} [renderTargetContext=null] - The render context of the current set render target. + */ + clear( color, depth, stencil, renderTargetContext = null ) { const device = this.device; const renderer = this.renderer; @@ -47954,7 +63935,7 @@ class WebGPUBackend extends Backend { } - if ( renderTargetData === null ) { + if ( renderTargetContext === null ) { supportsDepth = renderer.depth; supportsStencil = renderer.stencil; @@ -47981,45 +63962,20 @@ class WebGPUBackend extends Backend { } else { - supportsDepth = renderTargetData.depth; - supportsStencil = renderTargetData.stencil; + supportsDepth = renderTargetContext.depth; + supportsStencil = renderTargetContext.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; + const descriptor = this._getRenderPassDescriptor( renderTargetContext, { loadOp: GPULoadOp.Clear, clearValue } ); - } else { - - view = textureView; - resolveTarget = undefined; - - } - - colorAttachments.push( { - view, - resolveTarget, - clearValue, - loadOp: GPULoadOp.Clear, - storeOp: GPUStoreOp.Store - } ); - - } + colorAttachments = descriptor.colorAttachments; } if ( supportsDepth || supportsStencil ) { - const depthTextureData = this.get( renderTargetData.depthTexture ); + const depthTextureData = this.get( renderTargetContext.depthTexture ); depthStencilAttachment = { view: depthTextureData.texture.createView() @@ -48069,7 +64025,7 @@ class WebGPUBackend extends Backend { // - const encoder = device.createCommandEncoder( {} ); + const encoder = device.createCommandEncoder( { label: 'clear' } ); const currentPass = encoder.beginRenderPass( { colorAttachments, depthStencilAttachment @@ -48083,21 +64039,37 @@ class WebGPUBackend extends Backend { // compute + /** + * This method is executed at the beginning of a compute call and + * prepares the state for upcoming compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ beginCompute( computeGroup ) { const groupGPU = this.get( computeGroup ); - const descriptor = {}; + const descriptor = { + label: 'computeGroup_' + computeGroup.id + }; this.initTimestampQuery( computeGroup, descriptor ); - groupGPU.cmdEncoderGPU = this.device.createCommandEncoder(); + groupGPU.cmdEncoderGPU = this.device.createCommandEncoder( { label: 'computeGroup_' + computeGroup.id } ); groupGPU.passEncoderGPU = groupGPU.cmdEncoderGPU.beginComputePass( descriptor ); } + /** + * Executes a compute command for the given compute node. + * + * @param {Node|Array} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @param {ComputePipeline} pipeline - The compute pipeline. + */ compute( computeGroup, computeNode, bindings, pipeline ) { const { passEncoderGPU } = this.get( computeGroup ); @@ -48145,6 +64117,12 @@ class WebGPUBackend extends Backend { } + /** + * This method is executed at the end of a compute call and + * finalizes work after compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ finishCompute( computeGroup ) { const groupData = this.get( computeGroup ); @@ -48157,6 +64135,13 @@ class WebGPUBackend extends Backend { } + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ async waitForGPU() { await this.device.queue.onSubmittedWorkDone(); @@ -48165,6 +64150,12 @@ class WebGPUBackend extends Backend { // render object + /** + * Executes a draw command for the given render object. + * + * @param {RenderObject} renderObject - The render object to draw. + * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. + */ draw( renderObject, info ) { const { object, context, pipeline } = renderObject; @@ -48285,14 +64276,20 @@ class WebGPUBackend extends Backend { 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 ); + if ( hasIndex === true ) { + + passEncoderGPU.drawIndexed( counts[ i ], count, starts[ i ] / index.array.BYTES_PER_ELEMENT, 0, firstInstance ); + + } else { + + passEncoderGPU.draw( counts[ i ], count, starts[ i ], firstInstance ); + + } } @@ -48342,6 +64339,12 @@ class WebGPUBackend extends Backend { // cache key + /** + * Returns `true` if the render pipeline requires an update. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render pipeline requires an update or not. + */ needsRenderUpdate( renderObject ) { const data = this.get( renderObject ); @@ -48398,6 +64401,12 @@ class WebGPUBackend extends Backend { } + /** + * Returns a cache key that is used to identify render pipelines. + * + * @param {RenderObject} renderObject - The render object. + * @return {String} The cache key. + */ getRenderCacheKey( renderObject ) { const { object, material } = renderObject; @@ -48426,83 +64435,142 @@ class WebGPUBackend extends Backend { // textures + /** + * Creates a GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( texture ) { this.textureUtils.createSampler( texture ); } + /** + * Destroys the GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to destroy the sampler for. + */ destroySampler( texture ) { this.textureUtils.destroySampler( texture ); } + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { this.textureUtils.createDefaultTexture( texture ); } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ createTexture( texture, options ) { this.textureUtils.createTexture( texture, options ); } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { this.textureUtils.updateTexture( texture, options ); } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { this.textureUtils.generateMipmaps( texture ); } + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { this.textureUtils.destroyTexture( texture ); } - copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); } - + /** + * Inits a time stamp query for the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object} descriptor - The query descriptor. + */ initTimestampQuery( renderContext, descriptor ) { if ( ! this.trackTimestamp ) return; const renderContextData = this.get( renderContext ); - if ( ! renderContextData.timeStampQuerySet ) { + // init query set if not exists + if ( ! renderContextData.timestampQuerySet ) { const type = renderContext.isComputeNode ? 'compute' : 'render'; - const timeStampQuerySet = this.device.createQuerySet( { type: 'timestamp', count: 2, label: `timestamp_${type}_${renderContext.id}` } ); - const timestampWrites = { - querySet: timeStampQuerySet, - beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins. - endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends. - }; + renderContextData.timestampQuerySet = this.device.createQuerySet( { type: 'timestamp', count: 2, label: `timestamp_${type}_${renderContext.id}` } ); - Object.assign( descriptor, { timestampWrites } ); + } - renderContextData.timeStampQuerySet = timeStampQuerySet; + // augment descriptor - } + descriptor.timestampWrites = { + querySet: renderContextData.timestampQuerySet, + beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins. + endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends. + }; } - // timestamp utils - + /** + * Prepares the timestamp buffer. + * + * @param {RenderContext} renderContext - The render context. + * @param {GPUCommandEncoder} encoder - The command encoder. + */ prepareTimestampBuffer( renderContext, encoder ) { if ( ! this.trackTimestamp ) return; @@ -48510,7 +64578,7 @@ class WebGPUBackend extends Backend { const renderContextData = this.get( renderContext ); - const size = 2 * BigInt64Array.BYTES_PER_ELEMENT; + const size = 2 * BigUint64Array.BYTES_PER_ELEMENT; if ( renderContextData.currentTimestampQueryBuffers === undefined ) { @@ -48532,7 +64600,7 @@ class WebGPUBackend extends Backend { const { resolveBuffer, resultBuffer } = renderContextData.currentTimestampQueryBuffers; - encoder.resolveQuerySet( renderContextData.timeStampQuerySet, 0, 2, resolveBuffer, 0 ); + encoder.resolveQuerySet( renderContextData.timestampQuerySet, 0, 2, resolveBuffer, 0 ); if ( resultBuffer.mapState === 'unmapped' ) { @@ -48542,6 +64610,14 @@ class WebGPUBackend extends Backend { } + /** + * Resolves the time stamp for the given render context and type. + * + * @async + * @param {RenderContext} renderContext - The render context. + * @param {String} type - The render context. + * @return {Promise} A Promise that resolves when the time stamp has been computed. + */ async resolveTimestampAsync( renderContext, type = 'render' ) { if ( ! this.trackTimestamp ) return; @@ -48554,18 +64630,15 @@ class WebGPUBackend extends Backend { if ( resultBuffer.mapState === 'unmapped' ) { - resultBuffer.mapAsync( GPUMapMode.READ ).then( () => { + await resultBuffer.mapAsync( GPUMapMode.READ ); - const times = new BigUint64Array( resultBuffer.getMappedRange() ); - const duration = Number( times[ 1 ] - times[ 0 ] ) / 1000000; + const times = new BigUint64Array( resultBuffer.getMappedRange() ); + const duration = Number( times[ 1 ] - times[ 0 ] ) / 1000000; - this.renderer.info.updateTimestamp( type, duration ); + this.renderer.info.updateTimestamp( type, duration ); - resultBuffer.unmap(); - - - } ); + resultBuffer.unmap(); } @@ -48573,6 +64646,13 @@ class WebGPUBackend extends Backend { // node builder + /** + * Returns a node builder for the given render object. + * + * @param {RenderObject} object - The render object. + * @param {Renderer} renderer - The renderer. + * @return {WGSLNodeBuilder} The node builder. + */ createNodeBuilder( object, renderer ) { return new WGSLNodeBuilder( object, renderer ); @@ -48581,17 +64661,27 @@ class WebGPUBackend extends Backend { // program + /** + * Creates a shader program from the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ createProgram( program ) { const programGPU = this.get( program ); programGPU.module = { - module: this.device.createShaderModule( { code: program.code, label: program.stage } ), + module: this.device.createShaderModule( { code: program.code, label: program.stage + ( program.name !== '' ? `_${ program.name }` : '' ) } ), entryPoint: 'main' }; } + /** + * Destroys the shader program of the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ destroyProgram( program ) { this.delete( program ); @@ -48600,18 +64690,35 @@ class WebGPUBackend extends Backend { // pipelines + /** + * Creates a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ createRenderPipeline( renderObject, promises ) { this.pipelineUtils.createRenderPipeline( renderObject, promises ); } + /** + * Creates a compute pipeline for the given compute node. + * + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ createComputePipeline( computePipeline, bindings ) { this.pipelineUtils.createComputePipeline( computePipeline, bindings ); } + /** + * Prepares the state for encoding render bundles. + * + * @param {RenderContext} renderContext - The render context. + */ beginBundle( renderContext ) { const renderContextData = this.get( renderContext ); @@ -48624,6 +64731,12 @@ class WebGPUBackend extends Backend { } + /** + * After processing render bundles this method finalizes related work. + * + * @param {RenderContext} renderContext - The render context. + * @param {RenderBundle} bundle - The render bundle. + */ finishBundle( renderContext, bundle ) { const renderContextData = this.get( renderContext ); @@ -48640,6 +64753,12 @@ class WebGPUBackend extends Backend { } + /** + * Adds a render bundle to the render context data. + * + * @param {RenderContext} renderContext - The render context. + * @param {RenderBundle} bundle - The render bundle to add. + */ addBundle( renderContext, bundle ) { const renderContextData = this.get( renderContext ); @@ -48650,18 +64769,39 @@ class WebGPUBackend extends Backend { // bindings + /** + * Creates bindings from the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ createBindings( bindGroup, bindings, cacheIndex, version ) { this.bindingUtils.createBindings( bindGroup, bindings, cacheIndex, version ); } + /** + * Updates the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ updateBindings( bindGroup, bindings, cacheIndex, version ) { this.bindingUtils.createBindings( bindGroup, bindings, cacheIndex, version ); } + /** + * Updates a buffer binding. + * + * @param {Buffer} binding - The buffer binding to update. + */ updateBinding( binding ) { this.bindingUtils.updateBinding( binding ); @@ -48670,36 +64810,66 @@ class WebGPUBackend extends Backend { // attributes + /** + * Creates the buffer of an indexed shader attribute. + * + * @param {BufferAttribute} attribute - The indexed buffer attribute. + */ createIndexAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Creates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Creates the GPU buffer of a storage attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createStorageAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Creates the GPU buffer of an indirect storage attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createIndirectStorageAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.STORAGE | GPUBufferUsage.INDIRECT | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Updates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to update. + */ updateAttribute( attribute ) { this.attributeUtils.updateAttribute( attribute ); } + /** + * Destroys the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to destroy. + */ destroyAttribute( attribute ) { this.attributeUtils.destroyAttribute( attribute ); @@ -48708,6 +64878,9 @@ class WebGPUBackend extends Backend { // canvas + /** + * Triggers an update of the default render pass descriptor. + */ updateSize() { this.colorBuffer = this.textureUtils.getColorBuffer(); @@ -48717,18 +64890,38 @@ class WebGPUBackend extends Backend { // utils public + /** + * Returns the maximum anisotropy texture filtering value. + * + * @return {Number} The maximum anisotropy texture filtering value. + */ getMaxAnisotropy() { return 16; } + /** + * Checks if the given feature is supported by the backend. + * + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ hasFeature( name ) { return this.device.features.has( name ); } + /** + * Copies data of the given source texture to the given destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { let dstX = 0; @@ -48787,6 +64980,13 @@ class WebGPUBackend extends Backend { } + /** + * Copies the current bound framebuffer to the given texture. + * + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ copyFramebufferToTexture( texture, renderContext, rectangle ) { const renderContextData = this.get( renderContext ); @@ -48921,8 +65121,18 @@ class IESSpotLight extends SpotLight { } +/** + * This version of a node library represents a basic version + * just focusing on lights and tone mapping techniques. + * + * @private + * @augments NodeLibrary + */ class BasicNodeLibrary extends NodeLibrary { + /** + * Constructs a new basic node library. + */ constructor() { super(); @@ -48947,8 +65157,28 @@ class BasicNodeLibrary extends NodeLibrary { } +/** + * This alternative version of {@link WebGPURenderer} only supports node materials. + * So classes like `MeshBasicMaterial` are not compatible. + * + * @augments module:Renderer~Renderer + */ class WebGPURenderer extends Renderer { + /** + * Constructs a new WebGPU renderer. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 + * to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses it + * WebGL 2 backend no matter if WebGPU is supported or not. + */ constructor( parameters = {} ) { let BackendClass; @@ -48975,29 +65205,100 @@ class WebGPURenderer extends Renderer { super( backend, parameters ); + /** + * The generic default value is overwritten with the + * standard node library for type mapping. Material + * mapping is not supported with this version. + * + * @type {BasicNodeLibrary} + */ this.library = new BasicNodeLibrary(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGPURenderer = true; } } +/** + * A specialized group which enables applications access to the + * Render Bundle API of WebGPU. The group with all its descendant nodes + * are considered as one render bundle and processed as such by + * the renderer. + * + * This module is only fully supported by `WebGPURenderer` with a WebGPU backend. + * With a WebGL backend, the group can technically be rendered but without + * any performance improvements. + * + * @augments Group + */ class BundleGroup extends Group { + /** + * Constructs a new bundle group. + */ constructor() { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBundleGroup = true; + /** + * This property is only relevant for detecting types + * during serialization/deserialization. It should always + * match the class name. + * + * @type {String} + * @readonly + * @default 'BundleGroup' + */ this.type = 'BundleGroup'; + /** + * Whether the bundle is static or not. When set to `true`, the structure + * is assumed to be static and does not change. E.g. no new objects are + * added to the group + * + * If a change is required, an update can still be forced by setting the + * `needsUpdate` flag to `true`. + * + * @type {Boolean} + * @default true + */ this.static = true; + + /** + * The bundle group's version. + * + * @type {Number} + * @readonly + * @default 0 + */ this.version = 0; } + /** + * Set this property to `true` when the bundle group has changed. + * + * @type {Boolean} + * @default false + * @param {Boolean} value + */ set needsUpdate( value ) { if ( value === true ) this.version ++; @@ -49006,27 +65307,93 @@ class BundleGroup extends Group { } -const _material = /*@__PURE__*/ new NodeMaterial(); -const _quadMesh = /*@__PURE__*/ new QuadMesh( _material ); - +/** + * This module is responsible to manage the post processing setups in apps. + * You usually create a single instance of this class and use it to define + * the output of your post processing effect chain. + * ```js + * const postProcessing = new PostProcessing( renderer ); + * + * const scenePass = pass( scene, camera ); + * + * postProcessing.outputNode = scenePass; + * ``` + */ class PostProcessing { + /** + * Constructs a new post processing management module. + * + * @param {Renderer} renderer - A reference to the renderer. + * @param {Node} outputNode - An optional output node. + */ constructor( renderer, outputNode = vec4( 0, 0, 1, 1 ) ) { + /** + * A reference to the renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * A node which defines the final output of the post + * processing. This is usually the last node in a chain + * of effect nodes. + * + * @type {Node} + */ this.outputNode = outputNode; + /** + * Whether the default output tone mapping and color + * space transformation should be enabled or not. + * + * It is enabled by default by it must be disabled when + * effects must be executed after tone mapping and color + * space conversion. A typical example is FXAA which + * requires sRGB input. + * + * When set to `false`, the app must control the output + * transformation with `RenderOutputNode`. + * + * ```js + * const outputPass = renderOutput( scenePass ); + * ``` + * + * @type {Boolean} + */ this.outputColorTransform = true; + /** + * Must be set to `true` when the output node changes. + * + * @type {Node} + */ this.needsUpdate = true; - _material.name = 'PostProcessing'; + const material = new NodeMaterial(); + material.name = 'PostProcessing'; + + /** + * The full screen quad that is used to render + * the effects. + * + * @private + * @type {QuadMesh} + */ + this._quadMesh = new QuadMesh( material ); } + /** + * When `PostProcessing` is used to apply post processing effects, + * the application must use this version of `render()` inside + * its animation loop (not the one from the renderer). + */ render() { - this.update(); + this._update(); const renderer = this.renderer; @@ -49038,7 +65405,7 @@ class PostProcessing { // - _quadMesh.render( renderer ); + this._quadMesh.render( renderer ); // @@ -49047,7 +65414,21 @@ class PostProcessing { } - update() { + /** + * Frees internal resources. + */ + dispose() { + + this._quadMesh.material.dispose(); + + } + + /** + * Updates the state of the module. + * + * @private + */ + _update() { if ( this.needsUpdate === true ) { @@ -49056,8 +65437,8 @@ class PostProcessing { 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._quadMesh.material.fragmentNode = this.outputColorTransform === true ? renderOutput( this.outputNode, toneMapping, outputColorSpace ) : this.outputNode.context( { toneMapping, outputColorSpace } ); + this._quadMesh.material.needsUpdate = true; this.needsUpdate = false; @@ -49065,9 +65446,17 @@ class PostProcessing { } + /** + * When `PostProcessing` is used to apply post processing effects, + * the application must use this version of `renderAsync()` inside + * its animation loop (not the one from the renderer). + * + * @async + * @return {Promise} A Promise that resolves when the render has been finished. + */ async renderAsync() { - this.update(); + this._update(); const renderer = this.renderer; @@ -49079,7 +65468,7 @@ class PostProcessing { // - await _quadMesh.renderAsync( renderer ); + await this._quadMesh.renderAsync( renderer ); // @@ -49090,141 +65479,136 @@ class PostProcessing { } -// renderer state - -function saveRendererState( renderer, state = {} ) { - - state.toneMapping = renderer.toneMapping; - state.toneMappingExposure = renderer.toneMappingExposure; - state.outputColorSpace = renderer.outputColorSpace; - state.renderTarget = renderer.getRenderTarget(); - state.activeCubeFace = renderer.getActiveCubeFace(); - state.activeMipmapLevel = renderer.getActiveMipmapLevel(); - state.renderObjectFunction = renderer.getRenderObjectFunction(); - state.pixelRatio = renderer.getPixelRatio(); - state.mrt = renderer.getMRT(); - state.clearColor = renderer.getClearColor( state.clearColor || new Color() ); - state.clearAlpha = renderer.getClearAlpha(); - state.autoClear = renderer.autoClear; - state.scissorTest = renderer.getScissorTest(); - - return state; - -} - -function resetRendererState( renderer, state ) { - - state = saveRendererState( renderer, state ); - - renderer.setMRT( null ); - renderer.setRenderObjectFunction( null ); - renderer.setClearColor( 0x000000, 1 ); - renderer.autoClear = true; - - return state; - -} - -function restoreRendererState( renderer, state ) { - - renderer.toneMapping = state.toneMapping; - renderer.toneMappingExposure = state.toneMappingExposure; - renderer.outputColorSpace = state.outputColorSpace; - renderer.setRenderTarget( state.renderTarget, state.activeCubeFace, state.activeMipmapLevel ); - renderer.setRenderObjectFunction( state.renderObjectFunction ); - renderer.setPixelRatio( state.pixelRatio ); - renderer.setMRT( state.mrt ); - renderer.setClearColor( state.clearColor, state.clearAlpha ); - renderer.autoClear = state.autoClear; - renderer.setScissorTest( state.scissorTest ); - -} - -// renderer and scene state - -function saveRendererAndSceneState( renderer, scene, state = {} ) { - - state = saveRendererState( renderer, state ); - state.background = scene.background; - state.backgroundNode = scene.backgroundNode; - state.overrideMaterial = scene.overrideMaterial; - - return state; - -} - -function resetRendererAndSceneState( renderer, scene, state ) { - - state = saveRendererAndSceneState( renderer, scene, state ); - - scene.background = null; - scene.backgroundNode = null; - scene.overrideMaterial = null; - - return state; - -} - -function restoreRendererAndSceneState( renderer, scene, state ) { - - restoreRendererState( renderer, state ); - - scene.background = state.background; - scene.backgroundNode = state.backgroundNode; - scene.overrideMaterial = state.overrideMaterial; - -} - -var PostProcessingUtils = /*#__PURE__*/Object.freeze({ - __proto__: null, - resetRendererAndSceneState: resetRendererAndSceneState, - resetRendererState: resetRendererState, - restoreRendererAndSceneState: restoreRendererAndSceneState, - restoreRendererState: restoreRendererState, - saveRendererAndSceneState: saveRendererAndSceneState, - saveRendererState: saveRendererState -}); - +/** + * This special type of texture is intended for compute shaders. + * It can be used to compute the data of a texture with a compute shader. + * + * Note: This type of texture can only be used with `WebGPURenderer` + * and a WebGPU backend. + * + * @augments Texture + */ class StorageTexture extends Texture { + /** + * Constructs a new storage texture. + * + * @param {Number} [width=1] - The storage texture's width. + * @param {Number} [height=1] - The storage texture's height. + */ constructor( width = 1, height = 1 ) { super(); + /** + * The image object which just represents the texture's dimension. + * + * @type {{width: Number, height:Number}} + */ this.image = { width, height }; + /** + * The default `magFilter` for storage textures is `THREE.LinearFilter`. + * + * @type {Number} + */ this.magFilter = LinearFilter; + + /** + * The default `minFilter` for storage textures is `THREE.LinearFilter`. + * + * @type {Number} + */ this.minFilter = LinearFilter; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageTexture = true; } } +/** + * This special type of buffer attribute is intended for compute shaders. + * It can be used to encode draw parameters for indirect draw calls. + * + * Note: This type of buffer attribute can only be used with `WebGPURenderer` + * and a WebGPU backend. + * + * @augments StorageBufferAttribute + */ class IndirectStorageBufferAttribute extends StorageBufferAttribute { - constructor( array, itemSize ) { + /** + * Constructs a new storage buffer attribute. + * + * @param {Number|Uint32Array} count - The item count. It is also valid to pass a `Uint32Array` as an argument. + * The subsequent parameter is then obsolete. + * @param {Number} itemSize - The item size. + */ + constructor( count, itemSize ) { - super( array, itemSize, Uint32Array ); + super( count, itemSize, Uint32Array ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isIndirectStorageBufferAttribute = true; } } +/** + * A loader for loading node objects in the three.js JSON Object/Scene format. + * + * @augments Loader + */ class NodeLoader extends Loader { + /** + * Constructs a new node loader. + * + * @param {LoadingManager?} manager - A reference to a loading manager. + */ constructor( manager ) { super( manager ); + /** + * Represents a dictionary of textures. + * + * @type {Object} + */ this.textures = {}; + + /** + * Represents a dictionary of node types. + * + * @type {Object} + */ this.nodes = {}; } + /** + * Loads the node definitions from the given URL. + * + * @param {String} url - The path/URL of the file to be loaded. + * @param {Function} onLoad - Will be called when load completes. + * @param {Function} onProgress - Will be called while load progresses. + * @param {Function} onError - Will be called when errors are thrown during the loading process. + */ load( url, onLoad, onProgress, onError ) { const loader = new FileLoader( this.manager ); @@ -49257,6 +65641,12 @@ class NodeLoader extends Loader { } + /** + * Parse the node dependencies for the loaded node. + * + * @param {Object} json - The JSON definition + * @return {Object} A dictionary with node dependencies. + */ parseNodes( json ) { const nodes = {}; @@ -49291,6 +65681,12 @@ class NodeLoader extends Loader { } + /** + * Parses the node from the given JSON. + * + * @param {Object} json - The JSON definition + * @return {Node} The parsed node. + */ parse( json ) { const node = this.createNodeFromType( json.type ); @@ -49309,6 +65705,12 @@ class NodeLoader extends Loader { } + /** + * Defines the dictionary of textures. + * + * @param {Object} value - The texture library defines as ``. + * @return {NodeLoader} A reference to this loader. + */ setTextures( value ) { this.textures = value; @@ -49316,6 +65718,12 @@ class NodeLoader extends Loader { } + /** + * Defines the dictionary of node types. + * + * @param {Object} value - The node library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodes( value ) { this.nodes = value; @@ -49323,6 +65731,12 @@ class NodeLoader extends Loader { } + /** + * Creates a node object from the given type. + * + * @param {String} type - The node type. + * @return {Node} The created node instance. + */ createNodeFromType( type ) { if ( this.nodes[ type ] === undefined ) { @@ -49338,17 +65752,44 @@ class NodeLoader extends Loader { } +/** + * A special type of material loader for loading node materials. + * + * @augments MaterialLoader + */ class NodeMaterialLoader extends MaterialLoader { + /** + * Constructs a new node material loader. + * + * @param {LoadingManager?} manager - A reference to a loading manager. + */ constructor( manager ) { super( manager ); + /** + * Represents a dictionary of node types. + * + * @type {Object} + */ this.nodes = {}; + + /** + * Represents a dictionary of node material types. + * + * @type {Object} + */ this.nodeMaterials = {}; } + /** + * Parses the node material from the given JSON. + * + * @param {Object} json - The JSON definition + * @return {NodeMaterial}. The parsed material. + */ parse( json ) { const material = super.parse( json ); @@ -49368,6 +65809,12 @@ class NodeMaterialLoader extends MaterialLoader { } + /** + * Defines the dictionary of node types. + * + * @param {Object} value - The node library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodes( value ) { this.nodes = value; @@ -49375,6 +65822,12 @@ class NodeMaterialLoader extends MaterialLoader { } + /** + * Defines the dictionary of node material types. + * + * @param {Object} value - The node material library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodeMaterials( value ) { this.nodeMaterials = value; @@ -49382,6 +65835,12 @@ class NodeMaterialLoader extends MaterialLoader { } + /** + * Creates a node material from the given type. + * + * @param {String} type - The node material type. + * @return {Node} The created node material instance. + */ createMaterialFromType( type ) { const materialClass = this.nodeMaterials[ type ]; @@ -49398,19 +65857,53 @@ class NodeMaterialLoader extends MaterialLoader { } +/** + * A special type of object loader for loading 3D objects using + * node materials. + * + * @augments ObjectLoader + */ class NodeObjectLoader extends ObjectLoader { + /** + * Constructs a new node object loader. + * + * @param {LoadingManager?} manager - A reference to a loading manager. + */ constructor( manager ) { super( manager ); + /** + * Represents a dictionary of node types. + * + * @type {Object} + */ this.nodes = {}; + + /** + * Represents a dictionary of node material types. + * + * @type {Object} + */ this.nodeMaterials = {}; + /** + * A reference to hold the `nodes` JSON property. + * + * @private + * @type {Object?} + */ this._nodesJSON = null; } + /** + * Defines the dictionary of node types. + * + * @param {Object} value - The node library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodes( value ) { this.nodes = value; @@ -49418,6 +65911,12 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Defines the dictionary of node material types. + * + * @param {Object} value - The node material library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodeMaterials( value ) { this.nodeMaterials = value; @@ -49425,6 +65924,13 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Parses the node objects from the given JSON. + * + * @param {Object} json - The JSON definition + * @param {Function} onLoad - The onLoad callback function. + * @return {Object3D}. The parsed 3D object. + */ parse( json, onLoad ) { this._nodesJSON = json.nodes; @@ -49437,6 +65943,13 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Parses the node objects from the given JSON and textures. + * + * @param {Object} json - The JSON definition + * @param {Object} textures - The texture library. + * @return {Object}. The parsed nodes. + */ parseNodes( json, textures ) { if ( json !== undefined ) { @@ -49453,6 +65966,13 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Parses the node objects from the given JSON and textures. + * + * @param {Object} json - The JSON definition + * @param {Object} textures - The texture library. + * @return {Object}. The parsed materials. + */ parseMaterials( json, textures ) { const materials = {}; @@ -49482,20 +66002,69 @@ class NodeObjectLoader extends ObjectLoader { } +/** + * In earlier three.js versions, clipping was defined globally + * on the renderer or on material level. This special version of + * `THREE.Group` allows to encode the clipping state into the scene + * graph. Meaning if you create an instance of this group, all + * descendant 3D objects will be affected by the respective clipping + * planes. + * + * Note: `ClippingGroup` can only be used with `WebGPURenderer`. + * + * @augments Group + */ class ClippingGroup extends Group { + /** + * Constructs a new clipping group. + */ constructor() { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isClippingGroup = true; + + /** + * An array with clipping planes. + * + * @type {Array} + */ this.clippingPlanes = []; + + /** + * Whether clipping should be enabled or not. + * + * @type {Boolean} + * @default true + */ this.enabled = true; + + /** + * Whether the intersection of the clipping planes is used to clip objects, rather than their union. + * + * @type {Boolean} + * @default false + */ this.clipIntersection = false; + + /** + * Whether shadows should be clipped or not. + * + * @type {Boolean} + * @default false + */ this.clipShadows = false; } } -export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnalyticLightNode, ArrayElementNode, AssignNode, AttributeNode, BackSide, BasicEnvironmentNode, BasicShadowMap, BatchNode, BoxGeometry, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferNode, BumpMapNode, BundleGroup, BypassNode, ByteType, CacheNode, CineonToneMapping, ClampToEdgeWrapping, ClippingGroup, CodeNode, Color, ColorManagement, ColorSpaceNode, ComputeNode, ConstNode, ContextNode, ConvertNode, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureNode, CubeUVReflectionMapping, CullFaceBack, CullFaceFront, CullFaceNone, CustomBlending, DataArrayTexture, DataTexture, DecrementStencilOp, DecrementWrapStencilOp, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicDrawUsage, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectUVNode, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExpressionNode, FileLoader, Float16BufferAttribute, Float32BufferAttribute, FloatType, FogExp2Node, FogNode, FogRangeNode, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLSLNodeParser, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, Group, HalfFloatType, HemisphereLight, HemisphereLightNode, IESSpotLight, IESSpotLightNode, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, IndirectStorageBufferAttribute, InstanceNode, InstancedBufferAttribute, InstancedInterleavedBuffer, InstancedMeshNode, InstancedPointsNodeMaterial, IntType, InterleavedBuffer, InterleavedBufferAttribute, InvertStencilOp, IrradianceNode, JoinNode, KeepStencilOp, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, LightProbe, LightProbeNode, Lighting, LightingContextNode, LightingModel, LightingNode, LightsNode, Line2NodeMaterial, LineBasicMaterial, LineBasicNodeMaterial, LineDashedMaterial, LineDashedNodeMaterial, LinearFilter, LinearMipMapLinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, Loader, LoopNode, LuminanceAlphaFormat, LuminanceFormat, MRTNode, MatcapUVNode, Material, MaterialLoader, MaterialNode, MaterialReferenceNode, MathUtils, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, 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, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, Node, NodeAccess, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalBlending, NormalMapNode, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OneFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, OutputStructNode, PCFShadowMap, PMREMGenerator, PMREMNode, ParameterNode, PassNode, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, Plane, PointLight, PointLightNode, PointUVNode, PointsMaterial, PointsNodeMaterial, PostProcessing, PostProcessingUtils, PosterizeNode, PropertyNode, QuadMesh, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, 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, RGBFormat, RGBIntegerFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RTTNode, RangeNode, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceNode, ReflectorNode, ReinhardToneMapping, RemapNode, RenderOutputNode, RenderTarget, RendererReferenceNode, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RotateNode, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, SceneNode, ScreenNode, ScriptableNode, ScriptableValueNode, SetNode, ShadowBaseNode, ShadowMaterial, ShadowNode, ShadowNodeMaterial, ShortType, SkinningNode, SphereGeometry, SplitNode, SpotLight, SpotLightNode, SpriteMaterial, SpriteNodeMaterial, SpriteSheetUVNode, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StaticDrawUsage, StorageArrayElementNode, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTextureNode, SubtractEquation, SubtractiveBlending, TSL, TangentSpaceNormalMap, TempNode, Texture, Texture3DNode, TextureNode, TextureSizeNode, ToneMappingNode, ToonOutlinePassNode, TriplanarTexturesNode, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, UniformArrayNode, UniformGroupNode, UniformNode, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, VarNode, VaryingNode, Vector2, Vector3, Vector4, VertexColorNode, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGPUCoordinateSystem, WebGPURenderer, ZeroFactor, ZeroStencilOp, createCanvasElement, defaultBuildStages, defaultShaderStages, shaderStages, vectorComponents }; +export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnalyticLightNode, ArrayElementNode, AssignNode, AttributeNode, BackSide, BasicEnvironmentNode, BasicShadowMap, BatchNode, BoxGeometry, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferNode, BumpMapNode, BundleGroup, BypassNode, ByteType, CacheNode, Camera, CineonToneMapping, ClampToEdgeWrapping, ClippingGroup, CodeNode, Color, ColorManagement, ColorSpaceNode, ComputeNode, ConstNode, ContextNode, ConvertNode, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureNode, CubeUVReflectionMapping, CullFaceBack, CullFaceFront, CullFaceNone, CustomBlending, DataArrayTexture, DataTexture, DecrementStencilOp, DecrementWrapStencilOp, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicDrawUsage, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectUVNode, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExpressionNode, FileLoader, Float16BufferAttribute, Float32BufferAttribute, FloatType, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLSLNodeParser, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, Group, HalfFloatType, HemisphereLight, HemisphereLightNode, IESSpotLight, IESSpotLightNode, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, IndirectStorageBufferAttribute, InstanceNode, InstancedBufferAttribute, InstancedInterleavedBuffer, InstancedMeshNode, IntType, InterleavedBuffer, InterleavedBufferAttribute, InvertStencilOp, IrradianceNode, JoinNode, KeepStencilOp, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, LightProbe, LightProbeNode, Lighting, LightingContextNode, LightingModel, LightingNode, LightsNode, Line2NodeMaterial, LineBasicMaterial, LineBasicNodeMaterial, LineDashedMaterial, LineDashedNodeMaterial, LinearFilter, LinearMipMapLinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, Loader, LoopNode, LuminanceAlphaFormat, LuminanceFormat, MRTNode, MatcapUVNode, Material, MaterialLoader, MaterialNode, MaterialReferenceNode, MathUtils, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, MeshLambertMaterial, MeshLambertNodeMaterial, MeshMatcapMaterial, MeshMatcapNodeMaterial, MeshNormalMaterial, MeshNormalNodeMaterial, MeshPhongMaterial, MeshPhongNodeMaterial, MeshPhysicalMaterial, MeshPhysicalNodeMaterial, MeshSSSNodeMaterial, MeshStandardMaterial, MeshStandardNodeMaterial, MeshToonMaterial, MeshToonNodeMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, ModelNode, MorphNode, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, Node, NodeAccess, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalBlending, NormalMapNode, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OneFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, OutputStructNode, PCFShadowMap, PMREMGenerator, PMREMNode, ParameterNode, PassNode, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, Plane, PointLight, PointLightNode, PointUVNode, PointsMaterial, PointsNodeMaterial, PostProcessing, PosterizeNode, PropertyNode, QuadMesh, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, 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, RGBFormat, RGBIntegerFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RTTNode, RangeNode, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceNode, ReflectorNode, ReinhardToneMapping, RemapNode, RenderOutputNode, RenderTarget, RendererReferenceNode, RendererUtils, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RotateNode, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, SceneNode, ScreenNode, ScriptableNode, ScriptableValueNode, SetNode, ShadowBaseNode, ShadowMaterial, ShadowNode, ShadowNodeMaterial, ShortType, SkinningNode, SphereGeometry, SplitNode, SpotLight, SpotLightNode, SpriteMaterial, SpriteNodeMaterial, SpriteSheetUVNode, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StaticDrawUsage, StorageArrayElementNode, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTextureNode, SubtractEquation, SubtractiveBlending, TSL, TangentSpaceNormalMap, TempNode, Texture, Texture3DNode, TextureNode, TextureSizeNode, ToneMappingNode, ToonOutlinePassNode, TriplanarTexturesNode, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, UniformArrayNode, UniformGroupNode, UniformNode, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, VarNode, VaryingNode, Vector2, Vector3, Vector4, VertexColorNode, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGPUCoordinateSystem, WebGPURenderer, ZeroFactor, ZeroStencilOp, createCanvasElement, defaultBuildStages, defaultShaderStages, shaderStages, vectorComponents }; diff --git a/build/three.webgpu.nodes.min.js b/build/three.webgpu.nodes.min.js index 94083b383edbd7..0525abd198e41f 100644 --- a/build/three.webgpu.nodes.min.js +++ b/build/three.webgpu.nodes.min.js @@ -1,6 +1,6 @@ /** * @license - * Copyright 2010-2024 Three.js Authors + * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */ -import{Color as e,Vector2 as t,Vector3 as r,Vector4 as s,Matrix3 as i,Matrix4 as n,EventDispatcher as o,MathUtils as a,ColorManagement as u,SRGBTransfer as l,NoToneMapping as d,StaticDrawUsage as c,InterleavedBuffer as h,DynamicDrawUsage as p,InterleavedBufferAttribute as g,NoColorSpace as m,UnsignedIntType as f,IntType as y,WebGLCoordinateSystem as b,BackSide as x,CubeReflectionMapping as T,CubeRefractionMapping as _,WebGPUCoordinateSystem as v,TangentSpaceNormalMap as N,ObjectSpaceNormalMap as S,InstancedInterleavedBuffer as A,InstancedBufferAttribute as R,DataArrayTexture as C,FloatType as E,FramebufferTexture as w,LinearMipmapLinearFilter as M,DepthTexture as B,Material as U,NormalBlending as F,PointsMaterial as P,LineBasicMaterial as I,LineDashedMaterial as L,NoBlending as D,MeshNormalMaterial as V,WebGLCubeRenderTarget as O,BoxGeometry as G,Mesh as k,Scene as z,LinearFilter as $,CubeCamera as H,CubeTexture as W,EquirectangularReflectionMapping as j,EquirectangularRefractionMapping as q,AddOperation as K,MixOperation as X,MultiplyOperation as Y,MeshBasicMaterial as Q,MeshLambertMaterial as Z,MeshPhongMaterial as J,Texture as ee,MeshStandardMaterial as te,MeshPhysicalMaterial as re,MeshToonMaterial as se,MeshMatcapMaterial as ie,SpriteMaterial as ne,ShadowMaterial as oe,Uint32BufferAttribute as ae,Uint16BufferAttribute as ue,DoubleSide as le,DepthStencilFormat as de,DepthFormat as ce,UnsignedInt248Type as he,UnsignedByteType as pe,RenderTarget as ge,Plane as me,Object3D as fe,HalfFloatType as ye,LinearMipMapLinearFilter as be,OrthographicCamera as xe,BufferGeometry as Te,Float32BufferAttribute as _e,BufferAttribute as ve,UVMapping as Ne,Euler as Se,LinearSRGBColorSpace as Ae,LessCompare as Re,VSMShadowMap as Ce,RGFormat as Ee,BasicShadowMap as we,SphereGeometry as Me,CubeUVReflectionMapping as Be,PerspectiveCamera as Ue,RGBAFormat as Fe,LinearMipmapNearestFilter as Pe,NearestMipmapLinearFilter as Ie,Float16BufferAttribute as Le,REVISION as De,SRGBColorSpace as Ve,PCFShadowMap as Oe,FrontSide as Ge,Frustum as ke,DataTexture as ze,RedIntegerFormat as $e,RedFormat as He,RGIntegerFormat as We,RGBIntegerFormat as je,RGBFormat as qe,RGBAIntegerFormat as Ke,UnsignedShortType as Xe,ByteType as Ye,ShortType as Qe,createCanvasElement as Ze,AddEquation as Je,SubtractEquation as et,ReverseSubtractEquation as tt,ZeroFactor as rt,OneFactor as st,SrcColorFactor as it,SrcAlphaFactor as nt,SrcAlphaSaturateFactor as ot,DstColorFactor as at,DstAlphaFactor as ut,OneMinusSrcColorFactor as lt,OneMinusSrcAlphaFactor as dt,OneMinusDstColorFactor as ct,OneMinusDstAlphaFactor as ht,CullFaceNone as pt,CullFaceBack as gt,CullFaceFront as mt,CustomBlending as ft,MultiplyBlending as yt,SubtractiveBlending as bt,AdditiveBlending as xt,NotEqualDepth as Tt,GreaterDepth as _t,GreaterEqualDepth as vt,EqualDepth as Nt,LessEqualDepth as St,LessDepth as At,AlwaysDepth as Rt,NeverDepth as Ct,UnsignedShort4444Type as Et,UnsignedShort5551Type as wt,UnsignedInt5999Type as Mt,AlphaFormat as Bt,LuminanceFormat as Ut,LuminanceAlphaFormat as Ft,RGB_S3TC_DXT1_Format as Pt,RGBA_S3TC_DXT1_Format as It,RGBA_S3TC_DXT3_Format as Lt,RGBA_S3TC_DXT5_Format as Dt,RGB_PVRTC_4BPPV1_Format as Vt,RGB_PVRTC_2BPPV1_Format as Ot,RGBA_PVRTC_4BPPV1_Format as Gt,RGBA_PVRTC_2BPPV1_Format as kt,RGB_ETC1_Format as zt,RGB_ETC2_Format as $t,RGBA_ETC2_EAC_Format as Ht,RGBA_ASTC_4x4_Format as Wt,RGBA_ASTC_5x4_Format as jt,RGBA_ASTC_5x5_Format as qt,RGBA_ASTC_6x5_Format as Kt,RGBA_ASTC_6x6_Format as Xt,RGBA_ASTC_8x5_Format as Yt,RGBA_ASTC_8x6_Format as Qt,RGBA_ASTC_8x8_Format as Zt,RGBA_ASTC_10x5_Format as Jt,RGBA_ASTC_10x6_Format as er,RGBA_ASTC_10x8_Format as tr,RGBA_ASTC_10x10_Format as rr,RGBA_ASTC_12x10_Format as sr,RGBA_ASTC_12x12_Format as ir,RGBA_BPTC_Format as nr,RED_RGTC1_Format as or,SIGNED_RED_RGTC1_Format as ar,RED_GREEN_RGTC2_Format as ur,SIGNED_RED_GREEN_RGTC2_Format as lr,RepeatWrapping as dr,ClampToEdgeWrapping as cr,MirroredRepeatWrapping as hr,NearestFilter as pr,NearestMipmapNearestFilter as gr,NeverCompare as mr,AlwaysCompare as fr,LessEqualCompare as yr,EqualCompare as br,GreaterEqualCompare as xr,GreaterCompare as Tr,NotEqualCompare as _r,warnOnce as vr,NotEqualStencilFunc as Nr,GreaterStencilFunc as Sr,GreaterEqualStencilFunc as Ar,EqualStencilFunc as Rr,LessEqualStencilFunc as Cr,LessStencilFunc as Er,AlwaysStencilFunc as wr,NeverStencilFunc as Mr,DecrementWrapStencilOp as Br,IncrementWrapStencilOp as Ur,DecrementStencilOp as Fr,IncrementStencilOp as Pr,InvertStencilOp as Ir,ReplaceStencilOp as Lr,ZeroStencilOp as Dr,KeepStencilOp as Vr,MaxEquation as Or,MinEquation as Gr,SpotLight as kr,PointLight as zr,DirectionalLight as $r,RectAreaLight as Hr,AmbientLight as Wr,HemisphereLight as jr,LightProbe as qr,LinearToneMapping as Kr,ReinhardToneMapping as Xr,CineonToneMapping as Yr,ACESFilmicToneMapping as Qr,AgXToneMapping as Zr,NeutralToneMapping as Jr,Group as es,Loader as ts,FileLoader as rs,MaterialLoader as ss,ObjectLoader as is}from"./three.core.min.js";export{AdditiveAnimationBlendMode,AnimationAction,AnimationClip,AnimationLoader,AnimationMixer,AnimationObjectGroup,AnimationUtils,ArcCurve,ArrayCamera,ArrowHelper,AttachedBindMode,Audio,AudioAnalyser,AudioContext,AudioListener,AudioLoader,AxesHelper,BasicDepthPacking,BatchedMesh,Bone,BooleanKeyframeTrack,Box2,Box3,Box3Helper,BoxHelper,BufferGeometryLoader,Cache,Camera,CameraHelper,CanvasTexture,CapsuleGeometry,CatmullRomCurve3,CircleGeometry,Clock,ColorKeyframeTrack,CompressedArrayTexture,CompressedCubeTexture,CompressedTexture,CompressedTextureLoader,ConeGeometry,ConstantAlphaFactor,ConstantColorFactor,Controls,CubeTextureLoader,CubicBezierCurve,CubicBezierCurve3,CubicInterpolant,CullFaceFrontBack,Curve,CurvePath,CustomToneMapping,CylinderGeometry,Cylindrical,Data3DTexture,DataTextureLoader,DataUtils,DefaultLoadingManager,DetachedBindMode,DirectionalLightHelper,DiscreteInterpolant,DodecahedronGeometry,DynamicCopyUsage,DynamicReadUsage,EdgesGeometry,EllipseCurve,ExtrudeGeometry,Fog,FogExp2,GLBufferAttribute,GLSL1,GLSL3,GridHelper,HemisphereLightHelper,IcosahedronGeometry,ImageBitmapLoader,ImageLoader,ImageUtils,InstancedBufferGeometry,InstancedMesh,Int16BufferAttribute,Int32BufferAttribute,Int8BufferAttribute,Interpolant,InterpolateDiscrete,InterpolateLinear,InterpolateSmooth,KeyframeTrack,LOD,LatheGeometry,Layers,Light,Line,Line3,LineCurve,LineCurve3,LineLoop,LineSegments,LinearInterpolant,LinearMipMapNearestFilter,LinearTransfer,LoaderUtils,LoadingManager,LoopOnce,LoopPingPong,LoopRepeat,MOUSE,Matrix2,MeshDepthMaterial,MeshDistanceMaterial,NearestMipMapLinearFilter,NearestMipMapNearestFilter,NormalAnimationBlendMode,NumberKeyframeTrack,OctahedronGeometry,OneMinusConstantAlphaFactor,OneMinusConstantColorFactor,PCFSoftShadowMap,Path,PlaneGeometry,PlaneHelper,PointLightHelper,Points,PolarGridHelper,PolyhedronGeometry,PositionalAudio,PropertyBinding,PropertyMixer,QuadraticBezierCurve,QuadraticBezierCurve3,Quaternion,QuaternionKeyframeTrack,QuaternionLinearInterpolant,RGBADepthPacking,RGBDepthPacking,RGB_BPTC_SIGNED_Format,RGB_BPTC_UNSIGNED_Format,RGDepthPacking,RawShaderMaterial,Ray,Raycaster,RingGeometry,ShaderMaterial,Shape,ShapeGeometry,ShapePath,ShapeUtils,Skeleton,SkeletonHelper,SkinnedMesh,Source,Sphere,Spherical,SphericalHarmonics3,SplineCurve,SpotLightHelper,Sprite,StaticCopyUsage,StaticReadUsage,StereoCamera,StreamCopyUsage,StreamDrawUsage,StreamReadUsage,StringKeyframeTrack,TOUCH,TetrahedronGeometry,TextureLoader,TextureUtils,TorusGeometry,TorusKnotGeometry,Triangle,TriangleFanDrawMode,TriangleStripDrawMode,TrianglesDrawMode,TubeGeometry,Uint8BufferAttribute,Uint8ClampedBufferAttribute,Uniform,UniformsGroup,VectorKeyframeTrack,VideoTexture,WebGL3DRenderTarget,WebGLArrayRenderTarget,WebGLRenderTarget,WireframeGeometry,WrapAroundEnding,ZeroCurvatureEnding,ZeroSlopeEnding}from"./three.core.min.js";const ns=["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 os{constructor(e){this.renderObjects=new WeakMap,this.hasNode=this.containsNode(e),this.hasAnimation=!0===e.object.isSkinnedMesh,this.refreshUniforms=ns,this.renderId=0}firstInitialization(e){return!1===this.renderObjects.has(e)&&(this.getRenderObjectData(e),!0)}getRenderObjectData(e){let t=this.renderObjects.get(e);if(void 0===t){const{geometry:r,material:s,object:i}=e;if(t={material:this.getMaterialData(s),geometry:{attributes:this.getAttributesData(r.attributes),indexVersion:r.index?r.index.version:null,drawRange:{start:r.drawRange.start,count:r.drawRange.count}},worldMatrix:i.matrixWorld.clone()},i.center&&(t.center=i.center.clone()),i.morphTargetInfluences&&(t.morphTargetInfluences=i.morphTargetInfluences.slice()),null!==e.bundle&&(t.version=e.bundle.version),t.material.transmission>0){const{width:r,height:s}=e.context;t.bufferWidth=r,t.bufferHeight=s}this.renderObjects.set(e,t)}return t}getAttributesData(e){const t={};for(const r in e){const s=e[r];t[r]={version:s.version}}return t}containsNode(e){const t=e.material;for(const e in t)if(t[e]&&t[e].isNode)return!0;return null!==e.renderer.nodes.modelViewMatrix||null!==e.renderer.nodes.modelNormalViewMatrix}getMaterialData(e){const t={};for(const r of this.refreshUniforms){const s=e[r];null!=s&&("object"==typeof s&&void 0!==s.clone?!0===s.isTexture?t[r]={id:s.id,version:s.version}:t[r]=s.clone():t[r]=s)}return t}equals(e){const{object:t,material:r,geometry:s}=e,i=this.getRenderObjectData(e);if(!0!==i.worldMatrix.equals(t.matrixWorld))return i.worldMatrix.copy(t.matrixWorld),!1;const n=i.material;for(const e in n){const t=n[e],s=r[e];if(void 0!==t.equals){if(!1===t.equals(s))return t.copy(s),!1}else if(!0===s.isTexture){if(t.id!==s.id||t.version!==s.version)return t.id=s.id,t.version=s.version,!1}else if(t!==s)return n[e]=s,!1}if(n.transmission>0){const{width:t,height:r}=e.context;if(i.bufferWidth!==t||i.bufferHeight!==r)return i.bufferWidth=t,i.bufferHeight=r,!1}const o=i.geometry,a=s.attributes,u=o.attributes,l=Object.keys(u),d=Object.keys(a);if(l.length!==d.length)return i.geometry.attributes=this.getAttributesData(a),!1;for(const e of l){const t=u[e],r=a[e];if(void 0===r)return delete u[e],!1;if(t.version!==r.version)return t.version=r.version,!1}const c=s.index,h=o.indexVersion,p=c?c.version:null;if(h!==p)return o.indexVersion=p,!1;if(o.drawRange.start!==s.drawRange.start||o.drawRange.count!==s.drawRange.count)return o.drawRange.start=s.drawRange.start,o.drawRange.count=s.drawRange.count,!1;if(i.morphTargetInfluences){let e=!1;for(let r=0;r>>16,2246822507),r^=Math.imul(s^s>>>13,3266489909),s=Math.imul(s^s>>>16,2246822507),s^=Math.imul(r^r>>>13,3266489909),4294967296*(2097151&s)+(r>>>0)}const us=e=>as(e),ls=e=>as(e),ds=(...e)=>as(e);function cs(e,t=!1){const r=[];!0===e.isNode&&(r.push(e.id),e=e.getSelf());for(const{property:s,childNode:i}of hs(e))r.push(r,as(s.slice(0,-4)),i.getCacheKey(t));return as(r)}function*hs(e,t=!1){for(const r in e){if(!0===r.startsWith("_"))continue;const s=e[r];if(!0===Array.isArray(s))for(let e=0;ee.charCodeAt(0))).buffer}var Ts=Object.freeze({__proto__:null,arrayBufferToBase64:bs,base64ToArrayBuffer:xs,getCacheKey:cs,getLengthFromType:ms,getNodeChildren:hs,getTypeFromLength:gs,getValueFromType:ys,getValueType:fs,hash:ds,hashArray:ls,hashString:us});const _s={VERTEX:"vertex",FRAGMENT:"fragment"},vs={NONE:"none",FRAME:"frame",RENDER:"render",OBJECT:"object"},Ns={BOOLEAN:"bool",INTEGER:"int",FLOAT:"float",VECTOR2:"vec2",VECTOR3:"vec3",VECTOR4:"vec4",MATRIX2:"mat2",MATRIX3:"mat3",MATRIX4:"mat4"},Ss={READ_ONLY:"readOnly",WRITE_ONLY:"writeOnly",READ_WRITE:"readWrite"},As=["fragment","vertex"],Rs=["setup","analyze","generate"],Cs=[...As,"compute"],Es=["x","y","z","w"];let ws=0;class Ms extends o{static get type(){return"Node"}constructor(e=null){super(),this.nodeType=e,this.updateType=vs.NONE,this.updateBeforeType=vs.NONE,this.updateAfterType=vs.NONE,this.uuid=a.generateUUID(),this.version=0,this.global=!1,this.isNode=!0,this._cacheKey=null,this._cacheKeyVersion=0,Object.defineProperty(this,"id",{value:ws++})}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,vs.FRAME)}onRenderUpdate(e){return this.onUpdate(e,vs.RENDER)}onObjectUpdate(e){return this.onUpdate(e,vs.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 hs(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=ds(cs(this,e),this.customCacheKey()),this._cacheKeyVersion=this.version),this._cacheKey}customCacheKey(){return 0}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 r=0;for(const e of this.getChildren())t["node"+r++]=e;return null}analyze(e){if(1===e.increaseUsage(this)){const t=e.getNodeProperties(this);for(const r of Object.values(t))r&&!0===r.isNode&&r.build(e)}}generate(e,t){const{outputNode:r}=e.getNodeProperties(this);if(r&&!0===r.isNode)return r.build(e,t)}updateBefore(){console.warn("Abstract function.")}updateAfter(){console.warn("Abstract function.")}update(){console.warn("Abstract function.")}build(e,t=null){const r=this.getShared(e);if(this!==r)return r.build(e,t);e.addNode(this),e.addChain(this);let s=null;const i=e.getBuildStage();if("setup"===i){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 r of Object.values(t))r&&!0===r.isNode&&r.build(e)}}else if("analyze"===i)this.analyze(e);else if("generate"===i){if(1===this.generate.length){const r=this.getNodeType(e),i=e.getDataFromNode(this);s=i.snippet,void 0===s?(s=this.generate(e)||"",i.snippet=s):void 0!==i.flowCodes&&void 0!==e.context.nodeBlock&&e.addFlowCodeHierarchy(this,e.context.nodeBlock),s=e.format(s,r,t)}else s=this.generate(e,t)||""}return e.removeChain(this),e.addSequentialNode(this),s}getSerializeChildren(){return hs(this)}serialize(e){const t=this.getSerializeChildren(),r={};for(const{property:s,index:i,childNode:n}of t)void 0!==i?(void 0===r[s]&&(r[s]=Number.isInteger(i)?[]:{}),r[s][i]=n.toJSON(e.meta).uuid):r[s]=n.toJSON(e.meta).uuid;Object.keys(r).length>0&&(e.inputNodes=r)}deserialize(e){if(void 0!==e.inputNodes){const t=e.meta.nodes;for(const r in e.inputNodes)if(Array.isArray(e.inputNodes[r])){const s=[];for(const i of e.inputNodes[r])s.push(t[i]);this[r]=s}else if("object"==typeof e.inputNodes[r]){const s={};for(const i in e.inputNodes[r]){const n=e.inputNodes[r][i];s[i]=t[n]}this[r]=s}else{const s=e.inputNodes[r];this[r]=t[s]}}}toJSON(e){const{uuid:t,type:r}=this,s=void 0===e||"string"==typeof e;s&&(e={textures:{},images:{},nodes:{}});let i=e.nodes[t];function n(e){const t=[];for(const r in e){const s=e[r];delete s.metadata,t.push(s)}return t}if(void 0===i&&(i={uuid:t,type:r,meta:e,metadata:{version:4.6,type:"Node",generator:"Node.toJSON"}},!0!==s&&(e.nodes[i.uuid]=i),this.serialize(i),delete i.meta),s){const t=n(e.textures),r=n(e.images),s=n(e.nodes);t.length>0&&(i.textures=t),r.length>0&&(i.images=r),s.length>0&&(i.nodes=s)}return i}}class Bs extends Ms{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 Us extends Ms{static get type(){return"ConvertNode"}constructor(e,t){super(),this.node=e,this.convertTo=t}getNodeType(e){const t=this.node.getNodeType(e);let r=null;for(const s of this.convertTo.split("|"))null!==r&&e.getTypeLength(t)!==e.getTypeLength(s)||(r=s);return r}serialize(e){super.serialize(e),e.convertTo=this.convertTo}deserialize(e){super.deserialize(e),this.convertTo=e.convertTo}generate(e,t){const r=this.node,s=this.getNodeType(e),i=r.build(e,s);return e.format(i,s,t)}}class Fs extends Ms{static get type(){return"TempNode"}constructor(e=null){super(e),this.isTempNode=!0}hasDependencies(e){return e.getDataFromNode(this).usageCount>1}build(e,t){if("generate"===e.getBuildStage()){const r=e.getVectorType(this.getNodeType(e,t)),s=e.getDataFromNode(this);if(void 0!==s.propertyName)return e.format(s.propertyName,r,t);if("void"!==r&&"void"!==t&&this.hasDependencies(e)){const i=super.build(e,r),n=e.getVarFromNode(this,null,r),o=e.getPropertyName(n);return e.addLineFlowCode(`${o} = ${i}`,this),s.snippet=i,s.propertyName=o,e.format(s.propertyName,r,t)}}return super.build(e,t)}}class Ps extends Fs{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,r)=>t+e.getTypeLength(r.getNodeType(e))),0))}generate(e,t){const r=this.getNodeType(e),s=this.nodes,i=e.getComponentType(r),n=[];for(const t of s){let r=t.build(e);const s=e.getComponentType(t.getNodeType(e));s!==i&&(r=e.format(r,s,i)),n.push(r)}const o=`${e.getType(r)}( ${n.join(", ")} )`;return e.format(o,r,t)}}const Is=Es.join("");class Ls extends Ms{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(Es.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 r=this.node,s=e.getTypeLength(r.getNodeType(e));let i=null;if(s>1){let n=null;this.getVectorLength()>=s&&(n=e.getTypeFromLength(this.getVectorLength(),this.getComponentType(e)));const o=r.build(e,n);i=this.components.length===s&&this.components===Is.slice(0,this.components.length)?e.format(o,n,t):e.format(`${o}.${this.components}`,this.getNodeType(e),t)}else i=r.build(e,t);return i}serialize(e){super.serialize(e),e.components=this.components}deserialize(e){super.deserialize(e),this.components=e.components}}class Ds extends Fs{static get type(){return"SetNode"}constructor(e,t,r){super(),this.sourceNode=e,this.components=t,this.targetNode=r}getNodeType(e){return this.sourceNode.getNodeType(e)}generate(e){const{sourceNode:t,components:r,targetNode:s}=this,i=this.getNodeType(e),n=e.getComponentType(s.getNodeType(e)),o=e.getTypeFromLength(r.length,n),a=s.build(e,o),u=t.build(e,i),l=e.getTypeLength(i),d=[];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"),Ws=e=>Hs(e).split("").sort().join(""),js={setup(e,t){const r=t.shift();return e(yi(r),...t)},get(e,t,r){if("string"==typeof t&&void 0===e[t]){if(!0!==e.isStackNode&&"assign"===t)return(...e)=>(ks.assign(r,...e),r);if(zs.has(t)){const s=zs.get(t);return e.isStackNode?(...e)=>r.add(s(...e)):(...e)=>s(r,...e)}if("self"===t)return e;if(t.endsWith("Assign")&&zs.has(t.slice(0,t.length-6))){const s=zs.get(t.slice(0,t.length-6));return e.isStackNode?(...e)=>r.assign(e[0],s(...e)):(...e)=>r.assign(s(r,...e))}if(!0===/^[xyzwrgbastpq]{1,4}$/.test(t))return t=Hs(t),fi(new Ls(r,t));if(!0===/^set[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Ws(t.slice(3).toLowerCase()),r=>fi(new Ds(e,t,r));if(!0===/^flip[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Ws(t.slice(4).toLowerCase()),()=>fi(new Vs(fi(e),t));if("width"===t||"height"===t||"depth"===t)return"width"===t?t="x":"height"===t?t="y":"depth"===t&&(t="z"),fi(new Ls(e,t));if(!0===/^\d+$/.test(t))return fi(new Bs(r,new Gs(Number(t),"uint")))}return Reflect.get(e,t,r)},set:(e,t,r,s)=>"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,r,s):(s[t].assign(r),!0)},qs=new WeakMap,Ks=new WeakMap,Xs=function(e,t=null){for(const r in e)e[r]=fi(e[r],t);return e},Ys=function(e,t=null){const r=e.length;for(let s=0;sfi(null!==s?Object.assign(e,s):e);return null===t?(...t)=>i(new e(...bi(t))):null!==r?(r=fi(r),(...s)=>i(new e(t,...bi(s),r))):(...r)=>i(new e(t,...bi(r)))},Zs=function(e,...t){return fi(new e(...bi(t)))};class Js extends Ms{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:r}=this,s=e.getNodeProperties(t);if(s.onceOutput)return s.onceOutput;let i=null;if(t.layout){let s=Ks.get(e.constructor);void 0===s&&(s=new WeakMap,Ks.set(e.constructor,s));let n=s.get(t);void 0===n&&(n=fi(e.buildFunctionNode(t)),s.set(t,n)),null!==e.currentFunctionNode&&e.currentFunctionNode.includes.push(n),i=fi(n.call(r))}else{const s=t.jsFunc,n=null!==r?s(r,e):s(e);i=fi(n)}return t.once&&(s.onceOutput=i),i}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 ei extends Ms{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 yi(e),fi(new Js(this,e))}setup(){return this.call()}}const ti=[!1,!0],ri=[0,1,2,3],si=[-1,-2],ii=[.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],ni=new Map;for(const e of ti)ni.set(e,new Gs(e));const oi=new Map;for(const e of ri)oi.set(e,new Gs(e,"uint"));const ai=new Map([...oi].map((e=>new Gs(e.value,"int"))));for(const e of si)ai.set(e,new Gs(e,"int"));const ui=new Map([...ai].map((e=>new Gs(e.value))));for(const e of ii)ui.set(e,new Gs(e));for(const e of ii)ui.set(-e,new Gs(-e));const li={bool:ni,uint:oi,ints:ai,float:ui},di=new Map([...ni,...ui]),ci=(e,t)=>di.has(e)?di.get(e):!0===e.isNode?e:new Gs(e,t),hi=function(e,t=null){return(...r)=>{if((0===r.length||!["bool","float","int","uint"].includes(e)&&r.every((e=>"object"!=typeof e)))&&(r=[ys(e,...r)]),1===r.length&&null!==t&&t.has(r[0]))return fi(t.get(r[0]));if(1===r.length){const t=ci(r[0],e);return(e=>{try{return e.getNodeType()}catch(e){return}})(t)===e?fi(t):fi(new Us(t,e))}const s=r.map((e=>ci(e)));return fi(new Ps(s,e))}},pi=e=>"object"==typeof e&&null!==e?e.value:e,gi=e=>null!=e?e.nodeType||e.convertTo||("string"==typeof e?e:null):null;function mi(e,t){return new Proxy(new ei(e,t),js)}const fi=(e,t=null)=>function(e,t=null){const r=fs(e);if("node"===r){let t=qs.get(e);return void 0===t&&(t=new Proxy(e,js),qs.set(e,t),qs.set(t,t)),t}return null===t&&("float"===r||"boolean"===r)||r&&"shader"!==r&&"string"!==r?fi(ci(e,t)):"shader"===r?_i(e):e}(e,t),yi=(e,t=null)=>new Xs(e,t),bi=(e,t=null)=>new Ys(e,t),xi=(...e)=>new Qs(...e),Ti=(...e)=>new Zs(...e),_i=(e,t)=>{const r=new mi(e,t),s=(...e)=>{let t;return yi(e),t=e[0]&&e[0].isNode?[...e]:e[0],r.call(t)};return s.shaderNode=r,s.setLayout=e=>(r.setLayout(e),s),s.once=()=>(r.once=!0,s),s};$s("toGlobal",(e=>(e.global=!0,e)));const vi=e=>{ks=e},Ni=()=>ks,Si=(...e)=>ks.If(...e);function Ai(e){return ks&&ks.add(e),e}$s("append",Ai);const Ri=new hi("color"),Ci=new hi("float",li.float),Ei=new hi("int",li.ints),wi=new hi("uint",li.uint),Mi=new hi("bool",li.bool),Bi=new hi("vec2"),Ui=new hi("ivec2"),Fi=new hi("uvec2"),Pi=new hi("bvec2"),Ii=new hi("vec3"),Li=new hi("ivec3"),Di=new hi("uvec3"),Vi=new hi("bvec3"),Oi=new hi("vec4"),Gi=new hi("ivec4"),ki=new hi("uvec4"),zi=new hi("bvec4"),$i=new hi("mat2"),Hi=new hi("mat3"),Wi=new hi("mat4");$s("toColor",Ri),$s("toFloat",Ci),$s("toInt",Ei),$s("toUint",wi),$s("toBool",Mi),$s("toVec2",Bi),$s("toIVec2",Ui),$s("toUVec2",Fi),$s("toBVec2",Pi),$s("toVec3",Ii),$s("toIVec3",Li),$s("toUVec3",Di),$s("toBVec3",Vi),$s("toVec4",Oi),$s("toIVec4",Gi),$s("toUVec4",ki),$s("toBVec4",zi),$s("toMat2",$i),$s("toMat3",Hi),$s("toMat4",Wi);const ji=xi(Bs),qi=(e,t)=>fi(new Us(fi(e),t));$s("element",ji),$s("convert",qi);class Ki extends Ms{static get type(){return"UniformGroupNode"}constructor(e,t=!1,r=1){super("string"),this.name=e,this.shared=t,this.order=r,this.isUniformGroup=!0}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 Xi=e=>new Ki(e),Yi=(e,t=0)=>new Ki(e,!0,t),Qi=Yi("frame"),Zi=Yi("render"),Ji=Xi("object");class en extends Os{static get type(){return"UniformNode"}constructor(e,t=null){super(e,t),this.isUniformNode=!0,this.name="",this.groupNode=Ji}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 r=this.getSelf();return e=e.bind(r),super.onUpdate((t=>{const s=e(t,r);void 0!==s&&(this.value=s)}),t)}generate(e,t){const r=this.getNodeType(e),s=this.getUniformHash(e);let i=e.getNodeFromHash(s);void 0===i&&(e.setHashNode(this,s),i=this);const n=i.getInputType(e),o=e.getUniformFromNode(i,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,r,t)}}const tn=(e,t)=>{const r=gi(t||e),s=e&&!0===e.isNode?e.node&&e.node.value||e.value:e;return fi(new en(s,r))};class rn extends Ms{static get type(){return"PropertyNode"}constructor(e,t=null,r=!1){super(e),this.name=t,this.varying=r,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 sn=(e,t)=>fi(new rn(e,t)),nn=(e,t)=>fi(new rn(e,t,!0)),on=Ti(rn,"vec4","DiffuseColor"),an=Ti(rn,"vec3","EmissiveColor"),un=Ti(rn,"float","Roughness"),ln=Ti(rn,"float","Metalness"),dn=Ti(rn,"float","Clearcoat"),cn=Ti(rn,"float","ClearcoatRoughness"),hn=Ti(rn,"vec3","Sheen"),pn=Ti(rn,"float","SheenRoughness"),gn=Ti(rn,"float","Iridescence"),mn=Ti(rn,"float","IridescenceIOR"),fn=Ti(rn,"float","IridescenceThickness"),yn=Ti(rn,"float","AlphaT"),bn=Ti(rn,"float","Anisotropy"),xn=Ti(rn,"vec3","AnisotropyT"),Tn=Ti(rn,"vec3","AnisotropyB"),_n=Ti(rn,"color","SpecularColor"),vn=Ti(rn,"float","SpecularF90"),Nn=Ti(rn,"float","Shininess"),Sn=Ti(rn,"vec4","Output"),An=Ti(rn,"float","dashSize"),Rn=Ti(rn,"float","gapSize"),Cn=Ti(rn,"float","pointWidth"),En=Ti(rn,"float","IOR"),wn=Ti(rn,"float","Transmission"),Mn=Ti(rn,"float","Thickness"),Bn=Ti(rn,"float","AttenuationDistance"),Un=Ti(rn,"color","AttenuationColor"),Fn=Ti(rn,"float","Dispersion");class Pn extends Fs{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 r=e.getTypeLength(t.node.getNodeType(e));return Es.join("").slice(0,r)!==t.components}return!1}generate(e,t){const{targetNode:r,sourceNode:s}=this,i=this.needsSplitAssign(e),n=r.getNodeType(e),o=r.context({assign:!0}).build(e),a=s.build(e,n),u=s.getNodeType(e),l=e.getDataFromNode(this);let d;if(!0===l.initialized)"void"!==t&&(d=o);else if(i){const s=e.getVarFromNode(this,null,n),i=e.getPropertyName(s);e.addLineFlowCode(`${i} = ${a}`,this);const u=r.node.context({assign:!0}).build(e);for(let t=0;t{const s=r.type;let i;return i="pointer"===s?"&"+t.build(e):t.build(e,s),i};if(Array.isArray(i))for(let e=0;e(t=t.length>1||t[0]&&!0===t[0].isNode?bi(t):yi(t[0]),fi(new Ln(fi(e),t)));$s("call",Dn);class Vn extends Fs{static get type(){return"OperatorNode"}constructor(e,t,r,...s){if(super(),s.length>0){let i=new Vn(e,t,r);for(let t=0;t>"===r||"<<"===r)return e.getIntegerType(n);if("!"===r||"=="===r||"&&"===r||"||"===r||"^^"===r)return"bool";if("<"===r||">"===r||"<="===r||">="===r){const r=t?e.getTypeLength(t):Math.max(e.getTypeLength(n),e.getTypeLength(o));return r>1?`bvec${r}`:"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 r=this.op,s=this.aNode,i=this.bNode,n=this.getNodeType(e,t);let o=null,a=null;"void"!==n?(o=s.getNodeType(e),a=void 0!==i?i.getNodeType(e):null,"<"===r||">"===r||"<="===r||">="===r||"=="===r?e.isVector(o)?a=o:o!==a&&(o=a="float"):">>"===r||"<<"===r?(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 u=s.build(e,o),l=void 0!==i?i.build(e,a):null,d=e.getTypeLength(t),c=e.getFunctionOperator(r);return"void"!==t?"<"===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThan",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} < ${l} )`,n,t):"<="===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThanEqual",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} <= ${l} )`,n,t):">"===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThan",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} > ${l} )`,n,t):">="===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThanEqual",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} >= ${l} )`,n,t):"!"===r||"~"===r?e.format(`(${r}${u})`,o,t):c?e.format(`${c}( ${u}, ${l} )`,n,t):e.format(`( ${u} ${r} ${l} )`,n,t):"void"!==o?c?e.format(`${c}( ${u}, ${l} )`,n,t):e.format(`${u} ${r} ${l}`,n,t):void 0}serialize(e){super.serialize(e),e.op=this.op}deserialize(e){super.deserialize(e),this.op=e.op}}const On=xi(Vn,"+"),Gn=xi(Vn,"-"),kn=xi(Vn,"*"),zn=xi(Vn,"/"),$n=xi(Vn,"%"),Hn=xi(Vn,"=="),Wn=xi(Vn,"!="),jn=xi(Vn,"<"),qn=xi(Vn,">"),Kn=xi(Vn,"<="),Xn=xi(Vn,">="),Yn=xi(Vn,"&&"),Qn=xi(Vn,"||"),Zn=xi(Vn,"!"),Jn=xi(Vn,"^^"),eo=xi(Vn,"&"),to=xi(Vn,"~"),ro=xi(Vn,"|"),so=xi(Vn,"^"),io=xi(Vn,"<<"),no=xi(Vn,">>");$s("add",On),$s("sub",Gn),$s("mul",kn),$s("div",zn),$s("modInt",$n),$s("equal",Hn),$s("notEqual",Wn),$s("lessThan",jn),$s("greaterThan",qn),$s("lessThanEqual",Kn),$s("greaterThanEqual",Xn),$s("and",Yn),$s("or",Qn),$s("not",Zn),$s("xor",Jn),$s("bitAnd",eo),$s("bitNot",to),$s("bitOr",ro),$s("bitXor",so),$s("shiftLeft",io),$s("shiftRight",no);const oo=(...e)=>(console.warn("TSL.OperatorNode: .remainder() has been renamed to .modInt()."),$n(...e));$s("remainder",oo);class ao extends Fs{static get type(){return"MathNode"}constructor(e,t,r=null,s=null){super(),this.method=e,this.aNode=t,this.bNode=r,this.cNode=s}getInputType(e){const t=this.aNode.getNodeType(e),r=this.bNode?this.bNode.getNodeType(e):null,s=this.cNode?this.cNode.getNodeType(e):null,i=e.isMatrix(t)?0:e.getTypeLength(t),n=e.isMatrix(r)?0:e.getTypeLength(r),o=e.isMatrix(s)?0:e.getTypeLength(s);return i>n&&i>o?t:n>o?r:o>i?s:t}getNodeType(e){const t=this.method;return t===ao.LENGTH||t===ao.DISTANCE||t===ao.DOT?"float":t===ao.CROSS?"vec3":t===ao.ALL?"bool":t===ao.EQUALS?e.changeComponentType(this.aNode.getNodeType(e),"bool"):t===ao.MOD?this.aNode.getNodeType(e):this.getInputType(e)}generate(e,t){const r=this.method,s=this.getNodeType(e),i=this.getInputType(e),n=this.aNode,o=this.bNode,a=this.cNode,u=!0===e.renderer.isWebGLRenderer;if(r===ao.TRANSFORM_DIRECTION){let r=n,s=o;e.isMatrix(r.getNodeType(e))?s=Oi(Ii(s),0):r=Oi(Ii(r),0);const i=kn(r,s).xyz;return Ro(i).build(e,t)}if(r===ao.NEGATE)return e.format("( - "+n.build(e,i)+" )",s,t);if(r===ao.ONE_MINUS)return Gn(1,n).build(e,t);if(r===ao.RECIPROCAL)return zn(1,n).build(e,t);if(r===ao.DIFFERENCE)return Po(Gn(n,o)).build(e,t);{const l=[];return r===ao.CROSS||r===ao.MOD?l.push(n.build(e,s),o.build(e,s)):u&&r===ao.STEP?l.push(n.build(e,1===e.getTypeLength(n.getNodeType(e))?"float":i),o.build(e,i)):u&&(r===ao.MIN||r===ao.MAX)||r===ao.MOD?l.push(n.build(e,i),o.build(e,1===e.getTypeLength(o.getNodeType(e))?"float":i)):r===ao.REFRACT?l.push(n.build(e,i),o.build(e,i),a.build(e,"float")):r===ao.MIX?l.push(n.build(e,i),o.build(e,i),a.build(e,1===e.getTypeLength(a.getNodeType(e))?"float":i)):(l.push(n.build(e,i)),null!==o&&l.push(o.build(e,i)),null!==a&&l.push(a.build(e,i))),e.format(`${e.getMethod(r,s)}( ${l.join(", ")} )`,s,t)}}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}ao.ALL="all",ao.ANY="any",ao.EQUALS="equals",ao.RADIANS="radians",ao.DEGREES="degrees",ao.EXP="exp",ao.EXP2="exp2",ao.LOG="log",ao.LOG2="log2",ao.SQRT="sqrt",ao.INVERSE_SQRT="inversesqrt",ao.FLOOR="floor",ao.CEIL="ceil",ao.NORMALIZE="normalize",ao.FRACT="fract",ao.SIN="sin",ao.COS="cos",ao.TAN="tan",ao.ASIN="asin",ao.ACOS="acos",ao.ATAN="atan",ao.ABS="abs",ao.SIGN="sign",ao.LENGTH="length",ao.NEGATE="negate",ao.ONE_MINUS="oneMinus",ao.DFDX="dFdx",ao.DFDY="dFdy",ao.ROUND="round",ao.RECIPROCAL="reciprocal",ao.TRUNC="trunc",ao.FWIDTH="fwidth",ao.BITCAST="bitcast",ao.TRANSPOSE="transpose",ao.ATAN2="atan2",ao.MIN="min",ao.MAX="max",ao.MOD="mod",ao.STEP="step",ao.REFLECT="reflect",ao.DISTANCE="distance",ao.DIFFERENCE="difference",ao.DOT="dot",ao.CROSS="cross",ao.POW="pow",ao.TRANSFORM_DIRECTION="transformDirection",ao.MIX="mix",ao.CLAMP="clamp",ao.REFRACT="refract",ao.SMOOTHSTEP="smoothstep",ao.FACEFORWARD="faceforward";const uo=Ci(1e-6),lo=Ci(1e6),co=Ci(Math.PI),ho=Ci(2*Math.PI),po=xi(ao,ao.ALL),go=xi(ao,ao.ANY),mo=xi(ao,ao.EQUALS),fo=xi(ao,ao.RADIANS),yo=xi(ao,ao.DEGREES),bo=xi(ao,ao.EXP),xo=xi(ao,ao.EXP2),To=xi(ao,ao.LOG),_o=xi(ao,ao.LOG2),vo=xi(ao,ao.SQRT),No=xi(ao,ao.INVERSE_SQRT),So=xi(ao,ao.FLOOR),Ao=xi(ao,ao.CEIL),Ro=xi(ao,ao.NORMALIZE),Co=xi(ao,ao.FRACT),Eo=xi(ao,ao.SIN),wo=xi(ao,ao.COS),Mo=xi(ao,ao.TAN),Bo=xi(ao,ao.ASIN),Uo=xi(ao,ao.ACOS),Fo=xi(ao,ao.ATAN),Po=xi(ao,ao.ABS),Io=xi(ao,ao.SIGN),Lo=xi(ao,ao.LENGTH),Do=xi(ao,ao.NEGATE),Vo=xi(ao,ao.ONE_MINUS),Oo=xi(ao,ao.DFDX),Go=xi(ao,ao.DFDY),ko=xi(ao,ao.ROUND),zo=xi(ao,ao.RECIPROCAL),$o=xi(ao,ao.TRUNC),Ho=xi(ao,ao.FWIDTH),Wo=xi(ao,ao.BITCAST),jo=xi(ao,ao.TRANSPOSE),qo=xi(ao,ao.ATAN2),Ko=xi(ao,ao.MIN),Xo=xi(ao,ao.MAX),Yo=xi(ao,ao.MOD),Qo=xi(ao,ao.STEP),Zo=xi(ao,ao.REFLECT),Jo=xi(ao,ao.DISTANCE),ea=xi(ao,ao.DIFFERENCE),ta=xi(ao,ao.DOT),ra=xi(ao,ao.CROSS),sa=xi(ao,ao.POW),ia=xi(ao,ao.POW,2),na=xi(ao,ao.POW,3),oa=xi(ao,ao.POW,4),aa=xi(ao,ao.TRANSFORM_DIRECTION),ua=e=>kn(Io(e),sa(Po(e),1/3)),la=e=>ta(e,e),da=xi(ao,ao.MIX),ca=(e,t=0,r=1)=>fi(new ao(ao.CLAMP,fi(e),fi(t),fi(r))),ha=e=>ca(e),pa=xi(ao,ao.REFRACT),ga=xi(ao,ao.SMOOTHSTEP),ma=xi(ao,ao.FACEFORWARD),fa=_i((([e])=>{const t=ta(e.xy,Bi(12.9898,78.233)),r=Yo(t,co);return Co(Eo(r).mul(43758.5453))})),ya=(e,t,r)=>da(t,r,e),ba=(e,t,r)=>ga(t,r,e);$s("all",po),$s("any",go),$s("equals",mo),$s("radians",fo),$s("degrees",yo),$s("exp",bo),$s("exp2",xo),$s("log",To),$s("log2",_o),$s("sqrt",vo),$s("inverseSqrt",No),$s("floor",So),$s("ceil",Ao),$s("normalize",Ro),$s("fract",Co),$s("sin",Eo),$s("cos",wo),$s("tan",Mo),$s("asin",Bo),$s("acos",Uo),$s("atan",Fo),$s("abs",Po),$s("sign",Io),$s("length",Lo),$s("lengthSq",la),$s("negate",Do),$s("oneMinus",Vo),$s("dFdx",Oo),$s("dFdy",Go),$s("round",ko),$s("reciprocal",zo),$s("trunc",$o),$s("fwidth",Ho),$s("atan2",qo),$s("min",Ko),$s("max",Xo),$s("mod",Yo),$s("step",Qo),$s("reflect",Zo),$s("distance",Jo),$s("dot",ta),$s("cross",ra),$s("pow",sa),$s("pow2",ia),$s("pow3",na),$s("pow4",oa),$s("transformDirection",aa),$s("mix",ya),$s("clamp",ca),$s("refract",pa),$s("smoothstep",ba),$s("faceForward",ma),$s("difference",ea),$s("saturate",ha),$s("cbrt",ua),$s("transpose",jo),$s("rand",fa);class xa extends Ms{static get type(){return"ConditionalNode"}constructor(e,t,r=null){super(),this.condNode=e,this.ifNode=t,this.elseNode=r}getNodeType(e){const t=this.ifNode.getNodeType(e);if(null!==this.elseNode){const r=this.elseNode.getNodeType(e);if(e.getTypeLength(r)>e.getTypeLength(t))return r}return t}setup(e){const t=this.condNode.cache(),r=this.ifNode.cache(),s=this.elseNode?this.elseNode.cache():null,i=e.context.nodeBlock;e.getDataFromNode(r).parentNodeBlock=i,null!==s&&(e.getDataFromNode(s).parentNodeBlock=i);const n=e.getNodeProperties(this);n.condNode=t,n.ifNode=r.context({nodeBlock:r}),n.elseNode=s?s.context({nodeBlock:s}):null}generate(e,t){const r=this.getNodeType(e),s=e.getDataFromNode(this);if(void 0!==s.nodeProperty)return s.nodeProperty;const{condNode:i,ifNode:n,elseNode:o}=e.getNodeProperties(this),a="void"!==t,u=a?sn(r).build(e):"";s.nodeProperty=u;const l=i.build(e,"bool");e.addFlowCode(`\n${e.tab}if ( ${l} ) {\n\n`).addFlowTab();let d=n.build(e,r);if(d&&(d=a?u+" = "+d+";":"return "+d+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+d+"\n\n"+e.tab+"}"),null!==o){e.addFlowCode(" else {\n\n").addFlowTab();let t=o.build(e,r);t&&(t=a?u+" = "+t+";":"return "+t+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+t+"\n\n"+e.tab+"}\n\n")}else e.addFlowCode("\n\n");return e.format(u,r,t)}}const Ta=xi(xa);$s("select",Ta);const _a=(...e)=>(console.warn("TSL.ConditionalNode: cond() has been renamed to select()."),Ta(...e));$s("cond",_a);class va extends Ms{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 r=this.node.build(e);return e.setContext(t),r}generate(e,t){const r=e.getContext();e.setContext({...e.context,...this.value});const s=this.node.build(e,t);return e.setContext(r),s}}const Na=xi(va),Sa=(e,t)=>Na(e,{label:t});$s("context",Na),$s("label",Sa);class Aa extends Ms{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:r}=this,s=e.getVarFromNode(this,r,e.getVectorType(this.getNodeType(e))),i=e.getPropertyName(s),n=t.build(e,s.type);return e.addLineFlowCode(`${i} = ${n}`,this),i}}const Ra=xi(Aa);$s("toVar",((...e)=>Ra(...e).append()));const Ca=e=>(console.warn('TSL: "temp" is deprecated. Use ".toVar()" instead.'),Ra(e));$s("temp",Ca);class Ea extends Ms{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 r=t.varying;if(void 0===r){const s=this.name,i=this.getNodeType(e);t.varying=r=e.getVaryingFromNode(this,s,i),t.node=this.node}return r.needsInterpolation||(r.needsInterpolation="fragment"===e.shaderStage),r}setup(e){this.setupVarying(e)}analyze(e){return this.setupVarying(e),this.node.analyze(e)}generate(e){const t=e.getNodeProperties(this),r=this.setupVarying(e);if(void 0===t.propertyName){const s=this.getNodeType(e),i=e.getPropertyName(r,_s.VERTEX);e.flowNodeFromShaderStage(_s.VERTEX,this.node,s,i),t.propertyName=i}return e.getPropertyName(r)}}const wa=xi(Ea);$s("varying",wa);const Ma=_i((([e])=>{const t=e.mul(.9478672986).add(.0521327014).pow(2.4),r=e.mul(.0773993808),s=e.lessThanEqual(.04045);return da(t,r,s)})).setLayout({name:"sRGBTransferEOTF",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),Ba=_i((([e])=>{const t=e.pow(.41666).mul(1.055).sub(.055),r=e.mul(12.92),s=e.lessThanEqual(.0031308);return da(t,r,s)})).setLayout({name:"sRGBTransferOETF",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),Ua="WorkingColorSpace",Fa="OutputColorSpace";class Pa extends Fs{static get type(){return"ColorSpaceNode"}constructor(e,t,r){super("vec4"),this.colorNode=e,this.source=t,this.target=r}resolveColorSpace(e,t){return t===Ua?u.workingColorSpace:t===Fa?e.context.outputColorSpace||e.renderer.outputColorSpace:t}setup(e){const{colorNode:t}=this,r=this.resolveColorSpace(e,this.source),s=this.resolveColorSpace(e,this.target);let n=t;return!1!==u.enabled&&r!==s&&r&&s?(u.getTransfer(r)===l&&(n=Oi(Ma(n.rgb),n.a)),u.getPrimaries(r)!==u.getPrimaries(s)&&(n=Oi(Hi(u._getMatrix(new i,r,s)).mul(n.rgb),n.a)),u.getTransfer(s)===l&&(n=Oi(Ba(n.rgb),n.a)),n):n}}const Ia=e=>fi(new Pa(fi(e),Ua,Fa)),La=e=>fi(new Pa(fi(e),Fa,Ua)),Da=(e,t)=>fi(new Pa(fi(e),Ua,t)),Va=(e,t)=>fi(new Pa(fi(e),t,Ua));$s("toOutputColorSpace",Ia),$s("toWorkingColorSpace",La),$s("workingToColorSpace",Da),$s("colorSpaceToWorking",Va);let Oa=class extends Bs{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),r=this.referenceNode.getNodeType(),s=this.getNodeType();return e.format(t,r,s)}};class Ga extends Ms{static get type(){return"ReferenceBaseNode"}constructor(e,t,r=null,s=null){super(),this.property=e,this.uniformType=t,this.object=r,this.count=s,this.properties=e.split("."),this.reference=r,this.node=null,this.group=null,this.updateType=vs.OBJECT}setGroup(e){return this.group=e,this}element(e){return fi(new Oa(this,fi(e)))}setNodeType(e){const t=tn(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 r=e[t[0]];for(let e=1;efi(new ka(e,t,r));class $a extends Fs{static get type(){return"ToneMappingNode"}constructor(e,t=Wa,r=null){super("vec3"),this.toneMapping=e,this.exposureNode=t,this.colorNode=r}customCacheKey(){return ds(this.toneMapping)}setup(e){const t=this.colorNode||e.context.color,r=this.toneMapping;if(r===d)return t;let s=null;const i=e.renderer.library.getToneMappingFunction(r);return null!==i?s=Oi(i(t.rgb,this.exposureNode),t.a):(console.error("ToneMappingNode: Unsupported Tone Mapping configuration.",r),s=t),s}}const Ha=(e,t,r)=>fi(new $a(e,fi(t),fi(r))),Wa=za("toneMappingExposure","float");$s("toneMapping",((e,t,r)=>Ha(t,r,e)));class ja extends Os{static get type(){return"BufferAttributeNode"}constructor(e,t=null,r=0,s=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferStride=r,this.bufferOffset=s,this.usage=c,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),r=this.value,s=e.getTypeLength(t),i=this.bufferStride||s,n=this.bufferOffset,o=!0===r.isInterleavedBuffer?r:new h(r,i),a=new g(o,s,n);o.setUsage(this.usage),this.attribute=a,this.attribute.isInstancedBufferAttribute=this.instanced}generate(e){const t=this.getNodeType(e),r=e.getBufferAttributeFromNode(this,t),s=e.getPropertyName(r);let i=null;if("vertex"===e.shaderStage||"compute"===e.shaderStage)this.name=s,i=s;else{i=wa(this).build(e,t)}return i}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 qa=(e,t,r,s)=>fi(new ja(e,t,r,s)),Ka=(e,t,r,s)=>qa(e,t,r,s).setUsage(p),Xa=(e,t,r,s)=>qa(e,t,r,s).setInstanced(!0),Ya=(e,t,r,s)=>Ka(e,t,r,s).setInstanced(!0);$s("toAttribute",(e=>qa(e.value)));class Qa extends Ms{static get type(){return"ComputeNode"}constructor(e,t,r=[64]){super("void"),this.isComputeNode=!0,this.computeNode=e,this.count=t,this.workgroupSize=r,this.dispatchCount=0,this.version=1,this.updateBeforeType=vs.OBJECT,this.onInitFunction=null,this.updateDispatchCount()}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){!0===e&&this.version++}updateDispatchCount(){const{count:e,workgroupSize:t}=this;let r=t[0];for(let e=1;efi(new Qa(fi(e),t,r));$s("compute",Za);class Ja extends Ms{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 r=e.getCache(),s=e.getCacheFromNode(this,this.parent);e.setCache(s);const i=this.node.build(e,...t);return e.setCache(r),i}}const eu=(e,...t)=>fi(new Ja(fi(e),...t));$s("cache",eu);class tu extends Ms{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 ru=xi(tu);$s("bypass",ru);class su extends Ms{static get type(){return"RemapNode"}constructor(e,t,r,s=Ci(0),i=Ci(1)){super(),this.node=e,this.inLowNode=t,this.inHighNode=r,this.outLowNode=s,this.outHighNode=i,this.doClamp=!0}setup(){const{node:e,inLowNode:t,inHighNode:r,outLowNode:s,outHighNode:i,doClamp:n}=this;let o=e.sub(t).div(r.sub(t));return!0===n&&(o=o.clamp()),o.mul(i.sub(s)).add(s)}}const iu=xi(su,null,null,{doClamp:!1}),nu=xi(su);$s("remap",iu),$s("remapClamp",nu);class ou extends Ms{static get type(){return"ExpressionNode"}constructor(e="",t="void"){super(t),this.snippet=e}generate(e,t){const r=this.getNodeType(e),s=this.snippet;if("void"!==r)return e.format(`( ${s} )`,r,t);e.addLineFlowCode(s,this)}}const au=xi(ou),uu=e=>(e?Ta(e,au("discard")):au("discard")).append();$s("discard",uu);class lu extends Fs{static get type(){return"RenderOutputNode"}constructor(e,t,r){super("vec4"),this.colorNode=e,this.toneMapping=t,this.outputColorSpace=r,this.isRenderOutputNode=!0}setup({context:e}){let t=this.colorNode||e.color;const r=(null!==this.toneMapping?this.toneMapping:e.toneMapping)||d,s=(null!==this.outputColorSpace?this.outputColorSpace:e.outputColorSpace)||m;return r!==d&&(t=t.toneMapping(r)),s!==m&&s!==u.workingColorSpace&&(t=t.workingToColorSpace(s)),t}}const du=(e,t=null,r=null)=>fi(new lu(fi(e),t,r));$s("renderOutput",du);class cu extends Ms{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 r=this.getAttributeName(e);if(e.hasGeometryAttribute(r)){const s=e.geometry.getAttribute(r);t=e.getTypeFromAttribute(s)}else t="float"}return t}setAttributeName(e){return this._attributeName=e,this}getAttributeName(){return this._attributeName}generate(e){const t=this.getAttributeName(e),r=this.getNodeType(e);if(!0===e.hasGeometryAttribute(t)){const s=e.geometry.getAttribute(t),i=e.getTypeFromAttribute(s),n=e.getAttribute(t,i);if("vertex"===e.shaderStage)return e.format(n.name,i,r);return wa(this).build(e,r)}return console.warn(`AttributeNode: Vertex attribute "${t}" not found on geometry.`),e.generateConst(r)}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 hu=(e,t)=>fi(new cu(e,t)),pu=e=>hu("uv"+(e>0?e:""),"vec2");class gu extends Ms{static get type(){return"TextureSizeNode"}constructor(e,t=null){super("uvec2"),this.isTextureSizeNode=!0,this.textureNode=e,this.levelNode=t}generate(e,t){const r=this.textureNode.build(e,"property"),s=null===this.levelNode?"0":this.levelNode.build(e,"int");return e.format(`${e.getMethod("textureDimensions")}( ${r}, ${s} )`,this.getNodeType(e),t)}}const mu=xi(gu);class fu extends en{static get type(){return"MaxMipLevelNode"}constructor(e){super(0),this._textureNode=e,this.updateType=vs.FRAME}get textureNode(){return this._textureNode}get texture(){return this._textureNode.value}update(){const e=this.texture,t=e.images,r=t&&t.length>0?t[0]&&t[0].image||t[0]:e.image;if(r&&void 0!==r.width){const{width:e,height:t}=r;this.value=Math.log2(Math.max(e,t))}}}const yu=xi(fu);class bu extends en{static get type(){return"TextureNode"}constructor(e,t=null,r=null,s=null){super(e),this.isTextureNode=!0,this.uvNode=t,this.levelNode=r,this.biasNode=s,this.compareNode=null,this.depthNode=null,this.gradNode=null,this.sampler=!0,this.updateMatrix=!1,this.updateType=vs.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===f?"uvec4":this.value.type===y?"ivec4":"vec4"}getInputType(){return"texture"}getDefaultUV(){return pu(this.value.channel)}updateReference(){return this.value}getTransformedUV(e){return null===this._matrixUniform&&(this._matrixUniform=tn(this.value.matrix)),this._matrixUniform.mul(Ii(e,1)).xy}setUpdateMatrix(e){return this.updateMatrix=e,this.updateType=e?vs.FRAME:vs.NONE,this}setupUV(e,t){const r=this.value;return e.isFlipY()&&(r.image instanceof ImageBitmap&&!0===r.flipY||!0===r.isRenderTargetTexture||!0===r.isFramebufferTexture||!0===r.isDepthTexture)&&(t=this.sampler?t.flipY():t.setY(Ei(mu(this,this.levelNode).y).sub(t.y).sub(1))),t}setup(e){const t=e.getNodeProperties(this);t.referenceNode=this.referenceNode;let r=this.uvNode;null!==r&&!0!==e.context.forceUVContext||!e.context.getUV||(r=e.context.getUV(this)),r||(r=this.getDefaultUV()),!0===this.updateMatrix&&(r=this.getTransformedUV(r)),r=this.setupUV(e,r);let s=this.levelNode;null===s&&e.context.getTextureLevel&&(s=e.context.getTextureLevel(this)),t.uvNode=r,t.levelNode=s,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,r,s,i,n,o,a){const u=this.value;let l;return l=s?e.generateTextureLevel(u,t,r,s,n):i?e.generateTextureBias(u,t,r,i,n):a?e.generateTextureGrad(u,t,r,a,n):o?e.generateTextureCompare(u,t,r,o,n):!1===this.sampler?e.generateTextureLoad(u,t,r,n):e.generateTexture(u,t,r,n),l}generate(e,t){const r=e.getNodeProperties(this),s=this.value;if(!s||!0!==s.isTexture)throw new Error("TextureNode: Need a three.js texture.");const i=super.generate(e,"property");if("sampler"===t)return i+"_sampler";if(e.isReference(t))return i;{const n=e.getDataFromNode(this);let o=n.propertyName;if(void 0===o){const{uvNode:t,levelNode:s,biasNode:a,compareNode:u,depthNode:l,gradNode:d}=r,c=this.generateUV(e,t),h=s?s.build(e,"float"):null,p=a?a.build(e,"float"):null,g=l?l.build(e,"int"):null,m=u?u.build(e,"float"):null,f=d?[d[0].build(e,"vec2"),d[1].build(e,"vec2")]:null,y=e.getVarFromNode(this);o=e.getPropertyName(y);const b=this.generateSnippet(e,i,c,h,p,g,m,f);e.addLineFlowCode(`${o} = ${b}`,this),n.snippet=b,n.propertyName=o}let a=o;const u=this.getNodeType(e);return e.needsToWorkingColorSpace(s)&&(a=Va(au(a,u),s.colorSpace).setup(e).build(e,u)),e.format(a,u,t)}}setSampler(e){return this.sampler=e,this}getSampler(){return this.sampler}uv(e){return console.warn("THREE.TextureNode: .uv() has been renamed. Use .sample() instead."),this.sample(e)}sample(e){const t=this.clone();return t.uvNode=fi(e),t.referenceNode=this.getSelf(),fi(t)}blur(e){const t=this.clone();return t.biasNode=fi(e).mul(yu(t)),t.referenceNode=this.getSelf(),fi(t)}level(e){const t=this.clone();return t.levelNode=fi(e),t.referenceNode=this.getSelf(),fi(t)}size(e){return mu(this,e)}bias(e){const t=this.clone();return t.biasNode=fi(e),t.referenceNode=this.getSelf(),fi(t)}compare(e){const t=this.clone();return t.compareNode=fi(e),t.referenceNode=this.getSelf(),fi(t)}grad(e,t){const r=this.clone();return r.gradNode=[fi(e),fi(t)],r.referenceNode=this.getSelf(),fi(r)}depth(e){const t=this.clone();return t.depthNode=fi(e),t.referenceNode=this.getSelf(),fi(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 xu=xi(bu),Tu=(...e)=>xu(...e).setSampler(!1),_u=tn("float").label("cameraNear").setGroup(Zi).onRenderUpdate((({camera:e})=>e.near)),vu=tn("float").label("cameraFar").setGroup(Zi).onRenderUpdate((({camera:e})=>e.far)),Nu=tn("mat4").label("cameraProjectionMatrix").setGroup(Zi).onRenderUpdate((({camera:e})=>e.projectionMatrix)),Su=tn("mat4").label("cameraProjectionMatrixInverse").setGroup(Zi).onRenderUpdate((({camera:e})=>e.projectionMatrixInverse)),Au=tn("mat4").label("cameraViewMatrix").setGroup(Zi).onRenderUpdate((({camera:e})=>e.matrixWorldInverse)),Ru=tn("mat4").label("cameraWorldMatrix").setGroup(Zi).onRenderUpdate((({camera:e})=>e.matrixWorld)),Cu=tn("mat3").label("cameraNormalMatrix").setGroup(Zi).onRenderUpdate((({camera:e})=>e.normalMatrix)),Eu=tn(new r).label("cameraPosition").setGroup(Zi).onRenderUpdate((({camera:e},t)=>t.value.setFromMatrixPosition(e.matrixWorld)));class wu extends Ms{static get type(){return"Object3DNode"}constructor(e,t=null){super(),this.scope=e,this.object3d=t,this.updateType=vs.OBJECT,this._uniformNode=new en(null)}getNodeType(){const e=this.scope;return e===wu.WORLD_MATRIX?"mat4":e===wu.POSITION||e===wu.VIEW_POSITION||e===wu.DIRECTION||e===wu.SCALE?"vec3":void 0}update(e){const t=this.object3d,s=this._uniformNode,i=this.scope;if(i===wu.WORLD_MATRIX)s.value=t.matrixWorld;else if(i===wu.POSITION)s.value=s.value||new r,s.value.setFromMatrixPosition(t.matrixWorld);else if(i===wu.SCALE)s.value=s.value||new r,s.value.setFromMatrixScale(t.matrixWorld);else if(i===wu.DIRECTION)s.value=s.value||new r,t.getWorldDirection(s.value);else if(i===wu.VIEW_POSITION){const i=e.camera;s.value=s.value||new r,s.value.setFromMatrixPosition(t.matrixWorld),s.value.applyMatrix4(i.matrixWorldInverse)}}generate(e){const t=this.scope;return t===wu.WORLD_MATRIX?this._uniformNode.nodeType="mat4":t!==wu.POSITION&&t!==wu.VIEW_POSITION&&t!==wu.DIRECTION&&t!==wu.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}}wu.WORLD_MATRIX="worldMatrix",wu.POSITION="position",wu.SCALE="scale",wu.VIEW_POSITION="viewPosition",wu.DIRECTION="direction";const Mu=xi(wu,wu.DIRECTION),Bu=xi(wu,wu.WORLD_MATRIX),Uu=xi(wu,wu.POSITION),Fu=xi(wu,wu.SCALE),Pu=xi(wu,wu.VIEW_POSITION);class Iu extends wu{static get type(){return"ModelNode"}constructor(e){super(e)}update(e){this.object3d=e.object,super.update(e)}}const Lu=Ti(Iu,Iu.DIRECTION),Du=Ti(Iu,Iu.WORLD_MATRIX),Vu=Ti(Iu,Iu.POSITION),Ou=Ti(Iu,Iu.SCALE),Gu=Ti(Iu,Iu.VIEW_POSITION),ku=tn(new i).onObjectUpdate((({object:e},t)=>t.value.getNormalMatrix(e.matrixWorld))),zu=tn(new n).onObjectUpdate((({object:e},t)=>t.value.copy(e.matrixWorld).invert())),$u=Au.mul(Du).toVar("modelViewMatrix"),Hu=_i((e=>(e.context.isHighPrecisionModelViewMatrix=!0,tn("mat4").onObjectUpdate((({object:e,camera:t})=>e.modelViewMatrix.multiplyMatrices(t.matrixWorldInverse,e.matrixWorld)))))).once()().toVar("highPrecisionModelViewMatrix"),Wu=_i((e=>{const t=e.context.isHighPrecisionModelViewMatrix;return tn("mat3").onObjectUpdate((({object:e,camera:r})=>(!0!==t&&e.modelViewMatrix.multiplyMatrices(r.matrixWorldInverse,e.matrixWorld),e.normalMatrix.getNormalMatrix(e.modelViewMatrix))))})).once()().toVar("highPrecisionModelNormalMatrix"),ju=hu("position","vec3"),qu=ju.varying("positionLocal"),Ku=ju.varying("positionPrevious"),Xu=Du.mul(qu).xyz.varying("v_positionWorld"),Yu=qu.transformDirection(Du).varying("v_positionWorldDirection").normalize().toVar("positionWorldDirection"),Qu=$u.mul(qu).xyz.varying("v_positionView"),Zu=Qu.negate().varying("v_positionViewDirection").normalize().toVar("positionViewDirection");class Ju extends Ms{static get type(){return"FrontFacingNode"}constructor(){super("bool"),this.isFrontFacingNode=!0}generate(e){const{renderer:t,material:r}=e;return t.coordinateSystem===b&&r.side===x?"false":e.getFrontFacing()}}const el=Ti(Ju),tl=Ci(el).mul(2).sub(1),rl=hu("normal","vec3"),sl=_i((e=>!1===e.geometry.hasAttribute("normal")?(console.warn('TSL.NormalNode: Vertex attribute "normal" not found on geometry.'),Ii(0,1,0)):rl),"vec3").once()().toVar("normalLocal"),il=Qu.dFdx().cross(Qu.dFdy()).normalize().toVar("normalFlat"),nl=_i((e=>{let t;return t=!0===e.material.flatShading?il:wa(cl(sl),"v_normalView").normalize(),t}),"vec3").once()().toVar("normalView"),ol=wa(nl.transformDirection(Au),"v_normalWorld").normalize().toVar("normalWorld"),al=_i((e=>e.context.setupNormal()),"vec3").once()().mul(tl).toVar("transformedNormalView"),ul=al.transformDirection(Au).toVar("transformedNormalWorld"),ll=_i((e=>e.context.setupClearcoatNormal()),"vec3").once()().mul(tl).toVar("transformedClearcoatNormalView"),dl=_i((([e,t=Du])=>{const r=Hi(t),s=e.div(Ii(r[0].dot(r[0]),r[1].dot(r[1]),r[2].dot(r[2])));return r.mul(s).xyz})),cl=_i((([e],t)=>{const r=t.renderer.nodes.modelNormalViewMatrix;if(null!==r)return r.transformDirection(e);const s=ku.mul(e);return Au.transformDirection(s)})),hl=tn(0).onReference((({material:e})=>e)).onRenderUpdate((({material:e})=>e.refractionRatio)),pl=Zu.negate().reflect(al),gl=Zu.negate().refract(al,hl),ml=pl.transformDirection(Au).toVar("reflectVector"),fl=gl.transformDirection(Au).toVar("reflectVector");class yl extends bu{static get type(){return"CubeTextureNode"}constructor(e,t=null,r=null,s=null){super(e,t,r,s),this.isCubeTextureNode=!0}getInputType(){return"cubeTexture"}getDefaultUV(){const e=this.value;return e.mapping===T?ml:e.mapping===_?fl:(console.error('THREE.CubeTextureNode: Mapping "%s" not supported.',e.mapping),Ii(0,0,0))}setUpdateMatrix(){}setupUV(e,t){const r=this.value;return e.renderer.coordinateSystem!==v&&r.isRenderTargetTexture?t:Ii(t.x.negate(),t.yz)}generateUV(e,t){return t.build(e,"vec3")}}const bl=xi(yl);class xl extends en{static get type(){return"BufferNode"}constructor(e,t,r=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferCount=r}getElementType(e){return this.getNodeType(e)}getInputType(){return"buffer"}}const Tl=(e,t,r)=>fi(new xl(e,t,r));class _l extends Bs{static get type(){return"UniformArrayElementNode"}constructor(e,t){super(e,t),this.isArrayBufferElementNode=!0}generate(e){const t=super.generate(e),r=this.getNodeType(),s=this.node.getPaddedType();return e.format(t,s,r)}}class vl extends xl{static get type(){return"UniformArrayNode"}constructor(e,t=null){super(null),this.array=e,this.elementType=null===t?fs(e[0]):t,this.paddedType=this.getPaddedType(),this.updateType=vs.RENDER,this.isArrayBufferNode=!0}getNodeType(){return this.paddedType}getElementType(){return this.elementType}getPaddedType(){const e=this.elementType;let t="vec4";return"mat2"===e?t="mat2":!0===/mat/.test(e)?t="mat4":"i"===e.charAt(0)?t="ivec4":"u"===e.charAt(0)&&(t="uvec4"),t}update(){const{array:e,value:t}=this,r=this.elementType;if("float"===r||"int"===r||"uint"===r)for(let r=0;rfi(new vl(e,t));class Sl extends Bs{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),r=this.referenceNode.getNodeType(),s=this.getNodeType();return e.format(t,r,s)}}class Al extends Ms{static get type(){return"ReferenceNode"}constructor(e,t,r=null,s=null){super(),this.property=e,this.uniformType=t,this.object=r,this.count=s,this.properties=e.split("."),this.reference=r,this.node=null,this.group=null,this.name=null,this.updateType=vs.OBJECT}element(e){return fi(new Sl(this,fi(e)))}setGroup(e){return this.group=e,this}label(e){return this.name=e,this}setNodeType(e){let t=null;t=null!==this.count?Tl(null,e,this.count):Array.isArray(this.getValueFromReference())?Nl(null,e):"texture"===e?xu(null):"cubeTexture"===e?bl(null):tn(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 r=e[t[0]];for(let e=1;efi(new Al(e,t,r)),Cl=(e,t,r,s)=>fi(new Al(e,t,s,r));class El extends Al{static get type(){return"MaterialReferenceNode"}constructor(e,t,r=null){super(e,t,r),this.material=r,this.isMaterialReferenceNode=!0}updateReference(e){return this.reference=null!==this.material?this.material:e.material,this.reference}}const wl=(e,t,r)=>fi(new El(e,t,r)),Ml=_i((e=>(!1===e.geometry.hasAttribute("tangent")&&e.geometry.computeTangents(),hu("tangent","vec4"))))(),Bl=Ml.xyz.toVar("tangentLocal"),Ul=$u.mul(Oi(Bl,0)).xyz.varying("v_tangentView").normalize().toVar("tangentView"),Fl=Ul.transformDirection(Au).varying("v_tangentWorld").normalize().toVar("tangentWorld"),Pl=Ul.toVar("transformedTangentView"),Il=Pl.transformDirection(Au).normalize().toVar("transformedTangentWorld"),Ll=e=>e.mul(Ml.w).xyz,Dl=wa(Ll(rl.cross(Ml)),"v_bitangentGeometry").normalize().toVar("bitangentGeometry"),Vl=wa(Ll(sl.cross(Bl)),"v_bitangentLocal").normalize().toVar("bitangentLocal"),Ol=wa(Ll(nl.cross(Ul)),"v_bitangentView").normalize().toVar("bitangentView"),Gl=wa(Ll(ol.cross(Fl)),"v_bitangentWorld").normalize().toVar("bitangentWorld"),kl=Ll(al.cross(Pl)).normalize().toVar("transformedBitangentView"),zl=kl.transformDirection(Au).normalize().toVar("transformedBitangentWorld"),$l=Hi(Ul,Ol,nl),Hl=Zu.mul($l),Wl=(()=>{let e=Tn.cross(Zu);return e=e.cross(Tn).normalize(),e=da(e,al,bn.mul(un.oneMinus()).oneMinus().pow2().pow2()).normalize(),e})(),jl=_i((e=>{const{eye_pos:t,surf_norm:r,mapN:s,uv:i}=e,n=t.dFdx(),o=t.dFdy(),a=i.dFdx(),u=i.dFdy(),l=r,d=o.cross(l),c=l.cross(n),h=d.mul(a.x).add(c.mul(u.x)),p=d.mul(a.y).add(c.mul(u.y)),g=h.dot(h).max(p.dot(p)),m=tl.mul(g.inverseSqrt());return On(h.mul(s.x,m),p.mul(s.y,m),l.mul(s.z)).normalize()}));class ql extends Fs{static get type(){return"NormalMapNode"}constructor(e,t=null){super("vec3"),this.node=e,this.scaleNode=t,this.normalMapType=N}setup(e){const{normalMapType:t,scaleNode:r}=this;let s=this.node.mul(2).sub(1);null!==r&&(s=Ii(s.xy.mul(r),s.z));let i=null;if(t===S)i=cl(s);else if(t===N){i=!0===e.hasGeometryAttribute("tangent")?$l.mul(s).normalize():jl({eye_pos:Qu,surf_norm:nl,mapN:s,uv:pu()})}return i}}const Kl=xi(ql),Xl=_i((({textureNode:e,bumpScale:t})=>{const r=t=>e.cache().context({getUV:e=>t(e.uvNode||pu()),forceUVContext:!0}),s=Ci(r((e=>e)));return Bi(Ci(r((e=>e.add(e.dFdx())))).sub(s),Ci(r((e=>e.add(e.dFdy())))).sub(s)).mul(t)})),Yl=_i((e=>{const{surf_pos:t,surf_norm:r,dHdxy:s}=e,i=t.dFdx().normalize(),n=r,o=t.dFdy().normalize().cross(n),a=n.cross(i),u=i.dot(o).mul(tl),l=u.sign().mul(s.x.mul(o).add(s.y.mul(a)));return u.abs().mul(r).sub(l).normalize()}));class Ql extends Fs{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=Xl({textureNode:this.textureNode,bumpScale:e});return Yl({surf_pos:Qu,surf_norm:nl,dHdxy:t})}}const Zl=xi(Ql),Jl=new Map;class ed extends Ms{static get type(){return"MaterialNode"}constructor(e){super(),this.scope=e}getCache(e,t){let r=Jl.get(e);return void 0===r&&(r=wl(e,t),Jl.set(e,r)),r}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,r=this.scope;let s=null;if(r===ed.COLOR){const e=void 0!==t.color?this.getColor(r):Ii();s=t.map&&!0===t.map.isTexture?e.mul(this.getTexture("map")):e}else if(r===ed.OPACITY){const e=this.getFloat(r);s=t.alphaMap&&!0===t.alphaMap.isTexture?e.mul(this.getTexture("alpha")):e}else if(r===ed.SPECULAR_STRENGTH)s=t.specularMap&&!0===t.specularMap.isTexture?this.getTexture("specular").r:Ci(1);else if(r===ed.SPECULAR_INTENSITY){const e=this.getFloat(r);s=t.specularMap?e.mul(this.getTexture(r).a):e}else if(r===ed.SPECULAR_COLOR){const e=this.getColor(r);s=t.specularColorMap&&!0===t.specularColorMap.isTexture?e.mul(this.getTexture(r).rgb):e}else if(r===ed.ROUGHNESS){const e=this.getFloat(r);s=t.roughnessMap&&!0===t.roughnessMap.isTexture?e.mul(this.getTexture(r).g):e}else if(r===ed.METALNESS){const e=this.getFloat(r);s=t.metalnessMap&&!0===t.metalnessMap.isTexture?e.mul(this.getTexture(r).b):e}else if(r===ed.EMISSIVE){const e=this.getFloat("emissiveIntensity"),i=this.getColor(r).mul(e);s=t.emissiveMap&&!0===t.emissiveMap.isTexture?i.mul(this.getTexture(r)):i}else if(r===ed.NORMAL)t.normalMap?(s=Kl(this.getTexture("normal"),this.getCache("normalScale","vec2")),s.normalMapType=t.normalMapType):s=t.bumpMap?Zl(this.getTexture("bump").r,this.getFloat("bumpScale")):nl;else if(r===ed.CLEARCOAT){const e=this.getFloat(r);s=t.clearcoatMap&&!0===t.clearcoatMap.isTexture?e.mul(this.getTexture(r).r):e}else if(r===ed.CLEARCOAT_ROUGHNESS){const e=this.getFloat(r);s=t.clearcoatRoughnessMap&&!0===t.clearcoatRoughnessMap.isTexture?e.mul(this.getTexture(r).r):e}else if(r===ed.CLEARCOAT_NORMAL)s=t.clearcoatNormalMap?Kl(this.getTexture(r),this.getCache(r+"Scale","vec2")):nl;else if(r===ed.SHEEN){const e=this.getColor("sheenColor").mul(this.getFloat("sheen"));s=t.sheenColorMap&&!0===t.sheenColorMap.isTexture?e.mul(this.getTexture("sheenColor").rgb):e}else if(r===ed.SHEEN_ROUGHNESS){const e=this.getFloat(r);s=t.sheenRoughnessMap&&!0===t.sheenRoughnessMap.isTexture?e.mul(this.getTexture(r).a):e,s=s.clamp(.07,1)}else if(r===ed.ANISOTROPY)if(t.anisotropyMap&&!0===t.anisotropyMap.isTexture){const e=this.getTexture(r);s=$i(Vd.x,Vd.y,Vd.y.negate(),Vd.x).mul(e.rg.mul(2).sub(Bi(1)).normalize().mul(e.b))}else s=Vd;else if(r===ed.IRIDESCENCE_THICKNESS){const e=Rl("1","float",t.iridescenceThicknessRange);if(t.iridescenceThicknessMap){const i=Rl("0","float",t.iridescenceThicknessRange);s=e.sub(i).mul(this.getTexture(r).g).add(i)}else s=e}else if(r===ed.TRANSMISSION){const e=this.getFloat(r);s=t.transmissionMap?e.mul(this.getTexture(r).r):e}else if(r===ed.THICKNESS){const e=this.getFloat(r);s=t.thicknessMap?e.mul(this.getTexture(r).g):e}else if(r===ed.IOR)s=this.getFloat(r);else if(r===ed.LIGHT_MAP)s=this.getTexture(r).rgb.mul(this.getFloat("lightMapIntensity"));else if(r===ed.AO_MAP)s=this.getTexture(r).r.sub(1).mul(this.getFloat("aoMapIntensity")).add(1);else{const t=this.getNodeType(e);s=this.getCache(r,t)}return s}}ed.ALPHA_TEST="alphaTest",ed.COLOR="color",ed.OPACITY="opacity",ed.SHININESS="shininess",ed.SPECULAR="specular",ed.SPECULAR_STRENGTH="specularStrength",ed.SPECULAR_INTENSITY="specularIntensity",ed.SPECULAR_COLOR="specularColor",ed.REFLECTIVITY="reflectivity",ed.ROUGHNESS="roughness",ed.METALNESS="metalness",ed.NORMAL="normal",ed.CLEARCOAT="clearcoat",ed.CLEARCOAT_ROUGHNESS="clearcoatRoughness",ed.CLEARCOAT_NORMAL="clearcoatNormal",ed.EMISSIVE="emissive",ed.ROTATION="rotation",ed.SHEEN="sheen",ed.SHEEN_ROUGHNESS="sheenRoughness",ed.ANISOTROPY="anisotropy",ed.IRIDESCENCE="iridescence",ed.IRIDESCENCE_IOR="iridescenceIOR",ed.IRIDESCENCE_THICKNESS="iridescenceThickness",ed.IOR="ior",ed.TRANSMISSION="transmission",ed.THICKNESS="thickness",ed.ATTENUATION_DISTANCE="attenuationDistance",ed.ATTENUATION_COLOR="attenuationColor",ed.LINE_SCALE="scale",ed.LINE_DASH_SIZE="dashSize",ed.LINE_GAP_SIZE="gapSize",ed.LINE_WIDTH="linewidth",ed.LINE_DASH_OFFSET="dashOffset",ed.POINT_WIDTH="pointWidth",ed.DISPERSION="dispersion",ed.LIGHT_MAP="light",ed.AO_MAP="ao";const td=Ti(ed,ed.ALPHA_TEST),rd=Ti(ed,ed.COLOR),sd=Ti(ed,ed.SHININESS),id=Ti(ed,ed.EMISSIVE),nd=Ti(ed,ed.OPACITY),od=Ti(ed,ed.SPECULAR),ad=Ti(ed,ed.SPECULAR_INTENSITY),ud=Ti(ed,ed.SPECULAR_COLOR),ld=Ti(ed,ed.SPECULAR_STRENGTH),dd=Ti(ed,ed.REFLECTIVITY),cd=Ti(ed,ed.ROUGHNESS),hd=Ti(ed,ed.METALNESS),pd=Ti(ed,ed.NORMAL).context({getUV:null}),gd=Ti(ed,ed.CLEARCOAT),md=Ti(ed,ed.CLEARCOAT_ROUGHNESS),fd=Ti(ed,ed.CLEARCOAT_NORMAL).context({getUV:null}),yd=Ti(ed,ed.ROTATION),bd=Ti(ed,ed.SHEEN),xd=Ti(ed,ed.SHEEN_ROUGHNESS),Td=Ti(ed,ed.ANISOTROPY),_d=Ti(ed,ed.IRIDESCENCE),vd=Ti(ed,ed.IRIDESCENCE_IOR),Nd=Ti(ed,ed.IRIDESCENCE_THICKNESS),Sd=Ti(ed,ed.TRANSMISSION),Ad=Ti(ed,ed.THICKNESS),Rd=Ti(ed,ed.IOR),Cd=Ti(ed,ed.ATTENUATION_DISTANCE),Ed=Ti(ed,ed.ATTENUATION_COLOR),wd=Ti(ed,ed.LINE_SCALE),Md=Ti(ed,ed.LINE_DASH_SIZE),Bd=Ti(ed,ed.LINE_GAP_SIZE),Ud=Ti(ed,ed.LINE_WIDTH),Fd=Ti(ed,ed.LINE_DASH_OFFSET),Pd=Ti(ed,ed.POINT_WIDTH),Id=Ti(ed,ed.DISPERSION),Ld=Ti(ed,ed.LIGHT_MAP),Dd=Ti(ed,ed.AO_MAP),Vd=tn(new t).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 Od extends Fs{static get type(){return"ModelViewProjectionNode"}constructor(e=null){super("vec4"),this.positionNode=e}setup(e){if("fragment"===e.shaderStage)return wa(e.context.mvp);const t=this.positionNode||qu,r=e.renderer.nodes.modelViewMatrix||$u;return Nu.mul(r).mul(t)}}const Gd=xi(Od);class kd extends Ms{static get type(){return"IndexNode"}constructor(e){super("uint"),this.scope=e,this.isIndexNode=!0}generate(e){const t=this.getNodeType(e),r=this.scope;let s,i;if(r===kd.VERTEX)s=e.getVertexIndex();else if(r===kd.INSTANCE)s=e.getInstanceIndex();else if(r===kd.DRAW)s=e.getDrawIndex();else if(r===kd.INVOCATION_LOCAL)s=e.getInvocationLocalIndex();else if(r===kd.INVOCATION_SUBGROUP)s=e.getInvocationSubgroupIndex();else{if(r!==kd.SUBGROUP)throw new Error("THREE.IndexNode: Unknown scope: "+r);s=e.getSubgroupIndex()}if("vertex"===e.shaderStage||"compute"===e.shaderStage)i=s;else{i=wa(this).build(e,t)}return i}}kd.VERTEX="vertex",kd.INSTANCE="instance",kd.SUBGROUP="subgroup",kd.INVOCATION_LOCAL="invocationLocal",kd.INVOCATION_SUBGROUP="invocationSubgroup",kd.DRAW="draw";const zd=Ti(kd,kd.VERTEX),$d=Ti(kd,kd.INSTANCE),Hd=Ti(kd,kd.SUBGROUP),Wd=Ti(kd,kd.INVOCATION_SUBGROUP),jd=Ti(kd,kd.INVOCATION_LOCAL),qd=Ti(kd,kd.DRAW);class Kd extends Ms{static get type(){return"InstanceNode"}constructor(e,t,r){super("void"),this.count=e,this.instanceMatrix=t,this.instanceColor=r,this.instanceMatrixNode=null,this.instanceColorNode=null,this.updateType=vs.FRAME,this.buffer=null,this.bufferColor=null}setup(e){const{count:t,instanceMatrix:r,instanceColor:s}=this;let{instanceMatrixNode:i,instanceColorNode:n}=this;if(null===i){if(t<=1e3)i=Tl(r.array,"mat4",Math.max(t,1)).element($d);else{const e=new A(r.array,16,1);this.buffer=e;const t=r.usage===p?Ya:Xa,s=[t(e,"vec4",16,0),t(e,"vec4",16,4),t(e,"vec4",16,8),t(e,"vec4",16,12)];i=Wi(...s)}this.instanceMatrixNode=i}if(s&&null===n){const e=new R(s.array,3),t=s.usage===p?Ya:Xa;this.bufferColor=e,n=Ii(t(e,"vec3",3,0)),this.instanceColorNode=n}const o=i.mul(qu).xyz;if(qu.assign(o),e.hasGeometryAttribute("normal")){const e=dl(sl,i);sl.assign(e)}null!==this.instanceColorNode&&nn("vec3","vInstanceColor").assign(this.instanceColorNode)}update(){this.instanceMatrix.usage!==p&&null!==this.buffer&&this.instanceMatrix.version!==this.buffer.version&&(this.buffer.version=this.instanceMatrix.version),this.instanceColor&&this.instanceColor.usage!==p&&null!==this.bufferColor&&this.instanceColor.version!==this.bufferColor.version&&(this.bufferColor.version=this.instanceColor.version)}}const Xd=xi(Kd);class Yd extends Kd{static get type(){return"InstancedMeshNode"}constructor(e){const{count:t,instanceMatrix:r,instanceColor:s}=e;super(t,r,s),this.instanceMesh=e}}const Qd=xi(Yd);class Zd extends Ms{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=$d:this.batchingIdNode=qd);const t=_i((([e])=>{const t=mu(Tu(this.batchMesh._indirectTexture),0),r=Ei(e).modInt(Ei(t)),s=Ei(e).div(Ei(t));return Tu(this.batchMesh._indirectTexture,Ui(r,s)).x})).setLayout({name:"getIndirectIndex",type:"uint",inputs:[{name:"id",type:"int"}]}),r=t(Ei(this.batchingIdNode)),s=this.batchMesh._matricesTexture,i=mu(Tu(s),0),n=Ci(r).mul(4).toInt().toVar(),o=n.modInt(i),a=n.div(Ei(i)),u=Wi(Tu(s,Ui(o,a)),Tu(s,Ui(o.add(1),a)),Tu(s,Ui(o.add(2),a)),Tu(s,Ui(o.add(3),a))),l=this.batchMesh._colorsTexture;if(null!==l){const e=_i((([e])=>{const t=mu(Tu(l),0).x,r=e,s=r.modInt(t),i=r.div(t);return Tu(l,Ui(s,i)).rgb})).setLayout({name:"getBatchingColor",type:"vec3",inputs:[{name:"id",type:"int"}]}),t=e(r);nn("vec3","vBatchColor").assign(t)}const d=Hi(u);qu.assign(u.mul(qu));const c=sl.div(Ii(d[0].dot(d[0]),d[1].dot(d[1]),d[2].dot(d[2]))),h=d.mul(c).xyz;sl.assign(h),e.hasGeometryAttribute("tangent")&&Bl.mulAssign(d)}}const Jd=xi(Zd),ec=new WeakMap;class tc extends Ms{static get type(){return"SkinningNode"}constructor(e,t=!1){let r,s,i;super("void"),this.skinnedMesh=e,this.useReference=t,this.updateType=vs.OBJECT,this.skinIndexNode=hu("skinIndex","uvec4"),this.skinWeightNode=hu("skinWeight","vec4"),t?(r=Rl("bindMatrix","mat4"),s=Rl("bindMatrixInverse","mat4"),i=Cl("skeleton.boneMatrices","mat4",e.skeleton.bones.length)):(r=tn(e.bindMatrix,"mat4"),s=tn(e.bindMatrixInverse,"mat4"),i=Tl(e.skeleton.boneMatrices,"mat4",e.skeleton.bones.length)),this.bindMatrixNode=r,this.bindMatrixInverseNode=s,this.boneMatricesNode=i,this.previousBoneMatricesNode=null}getSkinnedPosition(e=this.boneMatricesNode,t=qu){const{skinIndexNode:r,skinWeightNode:s,bindMatrixNode:i,bindMatrixInverseNode:n}=this,o=e.element(r.x),a=e.element(r.y),u=e.element(r.z),l=e.element(r.w),d=i.mul(t),c=On(o.mul(s.x).mul(d),a.mul(s.y).mul(d),u.mul(s.z).mul(d),l.mul(s.w).mul(d));return n.mul(c).xyz}getSkinnedNormal(e=this.boneMatricesNode,t=sl){const{skinIndexNode:r,skinWeightNode:s,bindMatrixNode:i,bindMatrixInverseNode:n}=this,o=e.element(r.x),a=e.element(r.y),u=e.element(r.z),l=e.element(r.w);let d=On(s.x.mul(o),s.y.mul(a),s.z.mul(u),s.w.mul(l));return d=n.mul(d).mul(i),d.transformDirection(t).xyz}getPreviousSkinnedPosition(e){const t=e.object;return null===this.previousBoneMatricesNode&&(t.skeleton.previousBoneMatrices=new Float32Array(t.skeleton.boneMatrices),this.previousBoneMatricesNode=Cl("skeleton.previousBoneMatrices","mat4",t.skeleton.bones.length)),this.getSkinnedPosition(this.previousBoneMatricesNode,Ku)}needsPreviousBoneMatrices(e){const t=e.renderer.getMRT();return t&&t.has("velocity")}setup(e){this.needsPreviousBoneMatrices(e)&&Ku.assign(this.getPreviousSkinnedPosition(e));const t=this.getSkinnedPosition();if(qu.assign(t),e.hasGeometryAttribute("normal")){const t=this.getSkinnedNormal();sl.assign(t),e.hasGeometryAttribute("tangent")&&Bl.assign(t)}}generate(e,t){if("void"!==t)return qu.build(e,t)}update(e){const t=(this.useReference?e.object:this.skinnedMesh).skeleton;ec.get(t)!==e.frameId&&(ec.set(t,e.frameId),null!==this.previousBoneMatricesNode&&t.previousBoneMatrices.set(t.boneMatrices),t.update())}}const rc=e=>fi(new tc(e,!0));class sc extends Ms{static get type(){return"LoopNode"}constructor(e=[]){super(),this.params=e}getVarName(e){return String.fromCharCode("i".charCodeAt(0)+e)}getProperties(e){const t=e.getNodeProperties(this);if(void 0!==t.stackNode)return t;const r={};for(let e=0,t=this.params.length-1;eNumber(n)?">=":"<"));const d={start:i,end:n,condition:u},c=d.start,h=d.end;let p="",g="",m="";l||(l="int"===a||"uint"===a?u.includes("<")?"++":"--":u.includes("<")?"+= 1.":"-= 1."),p+=e.getVar(a,o)+" = "+c,g+=o+" "+u+" "+h,m+=o+" "+l;const f=`for ( ${p}; ${g}; ${m} )`;e.addFlowCode((0===t?"\n":"")+e.tab+f+" {\n\n").addFlowTab()}const i=s.build(e,"void"),n=t.returnsNode?t.returnsNode.build(e):"";e.removeFlowTab().addFlowCode("\n"+e.tab+i);for(let t=0,r=this.params.length-1;tfi(new sc(bi(e,"int"))).append(),nc=()=>au("break").append(),oc=new WeakMap,ac=new s,uc=_i((({bufferMap:e,influence:t,stride:r,width:s,depth:i,offset:n})=>{const o=Ei(zd).mul(r).add(n),a=o.div(s),u=o.sub(a.mul(s));return Tu(e,Ui(u,a)).depth(i).mul(t)}));class lc extends Ms{static get type(){return"MorphNode"}constructor(e){super("void"),this.mesh=e,this.morphBaseInfluence=tn(1),this.updateType=vs.OBJECT}setup(e){const{geometry:r}=e,s=void 0!==r.morphAttributes.position,i=r.hasAttribute("normal")&&void 0!==r.morphAttributes.normal,n=r.morphAttributes.position||r.morphAttributes.normal||r.morphAttributes.color,o=void 0!==n?n.length:0,{texture:a,stride:u,size:l}=function(e){const r=void 0!==e.morphAttributes.position,s=void 0!==e.morphAttributes.normal,i=void 0!==e.morphAttributes.color,n=e.morphAttributes.position||e.morphAttributes.normal||e.morphAttributes.color,o=void 0!==n?n.length:0;let a=oc.get(e);if(void 0===a||a.count!==o){void 0!==a&&a.texture.dispose();const u=e.morphAttributes.position||[],l=e.morphAttributes.normal||[],d=e.morphAttributes.color||[];let c=0;!0===r&&(c=1),!0===s&&(c=2),!0===i&&(c=3);let h=e.attributes.position.count*c,p=1;const g=4096;h>g&&(p=Math.ceil(h/g),h=g);const m=new Float32Array(h*p*4*o),f=new C(m,h,p,o);f.type=E,f.needsUpdate=!0;const y=4*c;for(let x=0;x{const t=Ci(0).toVar();this.mesh.count>1&&null!==this.mesh.morphTexture&&void 0!==this.mesh.morphTexture?t.assign(Tu(this.mesh.morphTexture,Ui(Ei(e).add(1),Ei($d))).r):t.assign(Rl("morphTargetInfluences","float").element(e).toVar()),!0===s&&qu.addAssign(uc({bufferMap:a,influence:t,stride:u,width:d,depth:e,offset:Ei(0)})),!0===i&&sl.addAssign(uc({bufferMap:a,influence:t,stride:u,width:d,depth:e,offset:Ei(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 dc=xi(lc);class cc extends Ms{static get type(){return"LightingNode"}constructor(){super("vec3"),this.isLightingNode=!0}}class hc extends cc{static get type(){return"AONode"}constructor(e=null){super(),this.aoNode=e}setup(e){e.context.ambientOcclusion.mulAssign(this.aoNode)}}class pc extends va{static get type(){return"LightingContextNode"}constructor(e,t=null,r=null,s=null){super(e),this.lightingModel=t,this.backdropNode=r,this.backdropAlphaNode=s,this._value=null}getContext(){const{backdropNode:e,backdropAlphaNode:t}=this,r={directDiffuse:Ii().toVar("directDiffuse"),directSpecular:Ii().toVar("directSpecular"),indirectDiffuse:Ii().toVar("indirectDiffuse"),indirectSpecular:Ii().toVar("indirectSpecular")};return{radiance:Ii().toVar("radiance"),irradiance:Ii().toVar("irradiance"),iblIrradiance:Ii().toVar("iblIrradiance"),ambientOcclusion:Ci(1).toVar("ambientOcclusion"),reflectedLight:r,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 gc=xi(pc);class mc extends cc{static get type(){return"IrradianceNode"}constructor(e){super(),this.node=e}setup(e){e.context.irradiance.addAssign(this.node)}}let fc,yc;class bc extends Ms{static get type(){return"ScreenNode"}constructor(e){super(),this.scope=e,this.isViewportNode=!0}getNodeType(){return this.scope===bc.VIEWPORT?"vec4":"vec2"}getUpdateType(){let e=vs.NONE;return this.scope!==bc.SIZE&&this.scope!==bc.VIEWPORT||(e=vs.RENDER),this.updateType=e,e}update({renderer:e}){const t=e.getRenderTarget();this.scope===bc.VIEWPORT?null!==t?yc.copy(t.viewport):(e.getViewport(yc),yc.multiplyScalar(e.getPixelRatio())):null!==t?(fc.width=t.width,fc.height=t.height):e.getDrawingBufferSize(fc)}setup(){const e=this.scope;let r=null;return r=e===bc.SIZE?tn(fc||(fc=new t)):e===bc.VIEWPORT?tn(yc||(yc=new s)):Bi(_c.div(Tc)),r}generate(e){if(this.scope===bc.COORDINATE){let t=e.getFragCoord();if(e.isFlipY()){const r=e.getNodeProperties(Tc).outputNode.build(e);t=`${e.getType("vec2")}( ${t}.x, ${r}.y - ${t}.y )`}return t}return super.generate(e)}}bc.COORDINATE="coordinate",bc.VIEWPORT="viewport",bc.SIZE="size",bc.UV="uv";const xc=Ti(bc,bc.UV),Tc=Ti(bc,bc.SIZE),_c=Ti(bc,bc.COORDINATE),vc=Ti(bc,bc.VIEWPORT),Nc=vc.zw,Sc=_c.sub(vc.xy),Ac=Sc.div(Nc),Rc=_i((()=>(console.warn('TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.'),Tc)),"vec2").once()(),Cc=_i((()=>(console.warn('TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.'),xc)),"vec2").once()(),Ec=_i((()=>(console.warn('TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.'),xc.flipY())),"vec2").once()(),wc=new t;class Mc extends bu{static get type(){return"ViewportTextureNode"}constructor(e=xc,t=null,r=null){null===r&&((r=new w).minFilter=M),super(r,e,t),this.generateMipmaps=!1,this.isOutputTextureNode=!0,this.updateBeforeType=vs.FRAME}updateBefore(e){const t=e.renderer;t.getDrawingBufferSize(wc);const r=this.value;r.image.width===wc.width&&r.image.height===wc.height||(r.image.width=wc.width,r.image.height=wc.height,r.needsUpdate=!0);const s=r.generateMipmaps;r.generateMipmaps=this.generateMipmaps,t.copyFramebufferToTexture(r),r.generateMipmaps=s}clone(){const e=new this.constructor(this.uvNode,this.levelNode,this.value);return e.generateMipmaps=this.generateMipmaps,e}}const Bc=xi(Mc),Uc=xi(Mc,null,null,{generateMipmaps:!0});let Fc=null;class Pc extends Mc{static get type(){return"ViewportDepthTextureNode"}constructor(e=xc,t=null){null===Fc&&(Fc=new B),super(e,t,Fc)}}const Ic=xi(Pc);class Lc extends Ms{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===Lc.DEPTH_BASE?e.getFragDepth():super.generate(e)}setup({camera:e}){const{scope:t}=this,r=this.valueNode;let s=null;if(t===Lc.DEPTH_BASE)null!==r&&(s=kc().assign(r));else if(t===Lc.DEPTH)s=e.isPerspectiveCamera?Vc(Qu.z,_u,vu):Dc(Qu.z,_u,vu);else if(t===Lc.LINEAR_DEPTH)if(null!==r)if(e.isPerspectiveCamera){const e=Oc(r,_u,vu);s=Dc(e,_u,vu)}else s=r;else s=Dc(Qu.z,_u,vu);return s}}Lc.DEPTH_BASE="depthBase",Lc.DEPTH="depth",Lc.LINEAR_DEPTH="linearDepth";const Dc=(e,t,r)=>e.add(t).div(t.sub(r)),Vc=(e,t,r)=>t.add(e).mul(r).div(r.sub(t).mul(e)),Oc=(e,t,r)=>t.mul(r).div(r.sub(t).mul(e).sub(r)),Gc=(e,t,r)=>{t=t.max(1e-6).toVar();const s=_o(e.negate().div(t)),i=_o(r.div(t));return s.div(i)},kc=xi(Lc,Lc.DEPTH_BASE),zc=Ti(Lc,Lc.DEPTH),$c=xi(Lc,Lc.LINEAR_DEPTH),Hc=$c(Ic());zc.assign=e=>kc(e);const Wc=xi(class extends Ms{constructor(e){super("float"),this.name=e,this.isBuiltinNode=!0}generate(){return this.name}});class jc extends Ms{static get type(){return"ClippingNode"}constructor(e=jc.DEFAULT){super(),this.scope=e}setup(e){super.setup(e);const t=e.clippingContext,{intersectionPlanes:r,unionPlanes:s}=t;return this.hardwareClipping=e.material.hardwareClipping,this.scope===jc.ALPHA_TO_COVERAGE?this.setupAlphaToCoverage(r,s):this.scope===jc.HARDWARE?this.setupHardwareClipping(s,e):this.setupDefault(r,s)}setupAlphaToCoverage(e,t){return _i((()=>{const r=Ci().toVar("distanceToPlane"),s=Ci().toVar("distanceToGradient"),i=Ci(1).toVar("clipOpacity"),n=t.length;if(!this.hardwareClipping&&n>0){const e=Nl(t);ic(n,(({i:t})=>{const n=e.element(t);r.assign(Qu.dot(n.xyz).negate().add(n.w)),s.assign(r.fwidth().div(2)),i.mulAssign(ga(s.negate(),s,r))}))}const o=e.length;if(o>0){const t=Nl(e),n=Ci(1).toVar("intersectionClipOpacity");ic(o,(({i:e})=>{const i=t.element(e);r.assign(Qu.dot(i.xyz).negate().add(i.w)),s.assign(r.fwidth().div(2)),n.mulAssign(ga(s.negate(),s,r).oneMinus())})),i.mulAssign(n.oneMinus())}on.a.mulAssign(i),on.a.equal(0).discard()}))()}setupDefault(e,t){return _i((()=>{const r=t.length;if(!this.hardwareClipping&&r>0){const e=Nl(t);ic(r,(({i:t})=>{const r=e.element(t);Qu.dot(r.xyz).greaterThan(r.w).discard()}))}const s=e.length;if(s>0){const t=Nl(e),r=Mi(!0).toVar("clipped");ic(s,(({i:e})=>{const s=t.element(e);r.assign(Qu.dot(s.xyz).greaterThan(s.w).and(r))})),r.discard()}}))()}setupHardwareClipping(e,t){const r=e.length;return t.enableHardwareClipping(r),_i((()=>{const s=Nl(e),i=Wc(t.getClipDistance());ic(r,(({i:e})=>{const t=s.element(e),r=Qu.dot(t.xyz).sub(t.w).negate();i.element(e).assign(r)}))}))()}}jc.ALPHA_TO_COVERAGE="alphaToCoverage",jc.DEFAULT="default",jc.HARDWARE="hardware";const qc=_i((([e])=>Co(kn(1e4,Eo(kn(17,e.x).add(kn(.1,e.y)))).mul(On(.1,Po(Eo(kn(13,e.y).add(e.x)))))))),Kc=_i((([e])=>qc(Bi(qc(e.xy),e.z)))),Xc=_i((([e])=>{const t=Xo(Lo(Oo(e.xyz)),Lo(Go(e.xyz))),r=Ci(1).div(Ci(.05).mul(t)).toVar("pixScale"),s=Bi(xo(So(_o(r))),xo(Ao(_o(r)))),i=Bi(Kc(So(s.x.mul(e.xyz))),Kc(So(s.y.mul(e.xyz)))),n=Co(_o(r)),o=On(kn(n.oneMinus(),i.x),kn(n,i.y)),a=Ko(n,n.oneMinus()),u=Ii(o.mul(o).div(kn(2,a).mul(Gn(1,a))),o.sub(kn(.5,a)).div(Gn(1,a)),Gn(1,Gn(1,o).mul(Gn(1,o)).div(kn(2,a).mul(Gn(1,a))))),l=o.lessThan(a.oneMinus()).select(o.lessThan(a).select(u.x,u.y),u.z);return ca(l,1e-6,1)})).setLayout({name:"getAlphaHashThreshold",type:"float",inputs:[{name:"position",type:"vec3"}]});class Yc extends U{static get type(){return"NodeMaterial"}get type(){return this.constructor.type}set type(e){}constructor(){super(),this.isNodeMaterial=!0,this.forceSinglePass=!1,this.fog=!0,this.lights=!1,this.hardwareClipping=!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.geometryNode=null,this.depthNode=null,this.shadowPositionNode=null,this.receivedShadowNode=null,this.castShadowNode=null,this.outputNode=null,this.mrtNode=null,this.fragmentNode=null,this.vertexNode=null}customProgramCacheKey(){return this.type+cs(this)}build(e){this.setup(e)}setupObserver(e){return new os(e)}setup(e){e.context.setupNormal=()=>this.setupNormal(e);const t=e.renderer,r=t.getRenderTarget();let s;e.addStack(),e.stack.outputNode=this.vertexNode||this.setupPosition(e),null!==this.geometryNode&&(e.stack.outputNode=e.stack.outputNode.bypass(this.geometryNode)),e.addFlow("vertex",e.removeStack()),e.addStack();const i=this.setupClipping(e);if(!0===this.depthWrite&&(null!==r?!0===r.depthBuffer&&this.setupDepth(e):!0===t.depth&&this.setupDepth(e)),null===this.fragmentNode){this.setupDiffuseColor(e),this.setupVariants(e);const n=this.setupLighting(e);null!==i&&e.stack.add(i);const o=Oi(n,on.a).max(0);if(s=this.setupOutput(e,o),Sn.assign(s),null!==this.outputNode&&(s=this.outputNode),null!==r){const e=t.getMRT(),r=this.mrtNode;null!==e?(s=e,null!==r&&(s=e.merge(r))):null!==r&&(s=r)}}else{let t=this.fragmentNode;!0!==t.isOutputStructNode&&(t=Oi(t)),s=this.setupOutput(e,t)}e.stack.outputNode=s,e.addFlow("fragment",e.removeStack()),e.monitor=this.setupObserver(e)}setupClipping(e){if(null===e.clippingContext)return null;const{unionPlanes:t,intersectionPlanes:r}=e.clippingContext;let s=null;if(t.length>0||r.length>0){const t=e.renderer.samples;this.alphaToCoverage&&t>1?s=fi(new jc(jc.ALPHA_TO_COVERAGE)):e.stack.add(fi(new jc))}return s}setupHardwareClipping(e){if(this.hardwareClipping=!1,null===e.clippingContext)return;const t=e.clippingContext.unionPlanes.length;t>0&&t<=8&&e.isAvailable("clipDistance")&&(e.stack.add(fi(new jc(jc.HARDWARE))),this.hardwareClipping=!0)}setupDepth(e){const{renderer:t,camera:r}=e;let s=this.depthNode;if(null===s){const e=t.getMRT();e&&e.has("depth")?s=e.get("depth"):!0===t.logarithmicDepthBuffer&&(s=r.isPerspectiveCamera?Gc(Qu.z,_u,vu):Dc(Qu.z,_u,vu))}null!==s&&zc.assign(s).append()}setupPosition(e){const{object:t}=e,r=t.geometry;if(e.addStack(),(r.morphAttributes.position||r.morphAttributes.normal||r.morphAttributes.color)&&dc(t).append(),!0===t.isSkinnedMesh&&rc(t).append(),this.displacementMap){const e=wl("displacementMap","texture"),t=wl("displacementScale","float"),r=wl("displacementBias","float");qu.addAssign(sl.normalize().mul(e.x.mul(t).add(r)))}t.isBatchedMesh&&Jd(t).append(),t.isInstancedMesh&&t.instanceMatrix&&!0===t.instanceMatrix.isInstancedBufferAttribute&&Qd(t).append(),null!==this.positionNode&&qu.assign(this.positionNode),this.setupHardwareClipping(e);const s=Gd();return e.context.vertex=e.removeStack(),e.context.mvp=s,s}setupDiffuseColor({object:e,geometry:t}){let r=this.colorNode?Oi(this.colorNode):rd;if(!0===this.vertexColors&&t.hasAttribute("color")&&(r=Oi(r.xyz.mul(hu("color","vec3")),r.a)),e.instanceColor){r=nn("vec3","vInstanceColor").mul(r)}if(e.isBatchedMesh&&e._colorsTexture){r=nn("vec3","vBatchColor").mul(r)}on.assign(r);const s=this.opacityNode?Ci(this.opacityNode):nd;if(on.a.assign(on.a.mul(s)),null!==this.alphaTestNode||this.alphaTest>0){const e=null!==this.alphaTestNode?Ci(this.alphaTestNode):td;on.a.lessThanEqual(e).discard()}!0===this.alphaHash&&on.a.lessThan(Xc(qu)).discard(),!1===this.transparent&&this.blending===F&&!1===this.alphaToCoverage&&on.a.assign(1)}setupVariants(){}setupOutgoingLight(){return!0===this.lights?Ii(0):on.rgb}setupNormal(){return this.normalNode?Ii(this.normalNode):pd}setupEnvironment(){let e=null;return this.envNode?e=this.envNode:this.envMap&&(e=this.envMap.isCubeTexture?wl("envMap","cubeTexture"):wl("envMap","texture")),e}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new mc(Ld)),t}setupLights(e){const t=[],r=this.setupEnvironment(e);r&&r.isLightingNode&&t.push(r);const s=this.setupLightMap(e);if(s&&s.isLightingNode&&t.push(s),null!==this.aoNode||e.material.aoMap){const e=null!==this.aoNode?this.aoNode:Dd;t.push(new hc(e))}let i=this.lightsNode||e.lightsNode;return t.length>0&&(i=e.renderer.lighting.createNode([...i.getLights(),...t])),i}setupLightingModel(){}setupLighting(e){const{material:t}=e,{backdropNode:r,backdropAlphaNode:s,emissiveNode:i}=this,n=!0===this.lights||null!==this.lightsNode?this.setupLights(e):null;let o=this.setupOutgoingLight(e);if(n&&n.getScope().hasLights){const t=this.setupLightingModel(e);o=gc(n,t,r,s)}else null!==r&&(o=Ii(null!==s?da(o,r,s):r));return(i&&!0===i.isNode||t.emissive&&!0===t.emissive.isColor)&&(an.assign(Ii(i||id)),o=o.add(an)),o}setupOutput(e,t){if(!0===this.fog){const r=e.fogNode;r&&(t=Oi(r.mix(t.rgb,r.colorNode),t.a))}return t}setDefaultValues(e){for(const t in e){const r=e[t];void 0===this[t]&&(this[t]=r,r&&r.clone&&(this[t]=r.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 r=U.prototype.toJSON.call(this,e),s=hs(this);r.inputNodes={};for(const{property:t,childNode:i}of s)r.inputNodes[t]=i.toJSON(e).uuid;function i(e){const t=[];for(const r in e){const s=e[r];delete s.metadata,t.push(s)}return t}if(t){const t=i(e.textures),s=i(e.images),n=i(e.nodes);t.length>0&&(r.textures=t),s.length>0&&(r.images=s),n.length>0&&(r.nodes=n)}return r}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.geometryNode=e.geometryNode,this.depthNode=e.depthNode,this.shadowPositionNode=e.shadowPositionNode,this.receivedShadowNode=e.receivedShadowNode,this.castShadowNode=e.castShadowNode,this.outputNode=e.outputNode,this.mrtNode=e.mrtNode,this.fragmentNode=e.fragmentNode,this.vertexNode=e.vertexNode,super.copy(e)}}const Qc=new P;class Zc extends Yc{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(Qc),this.setValues(e)}setup(e){this.setupShaders(e),super.setup(e)}setupShaders({renderer:e}){const t=this.alphaToCoverage,r=this.useColor;this.vertexNode=_i((()=>{const e=hu("instancePosition").xyz,t=Oi($u.mul(Oi(e,1))),r=vc.z.div(vc.w),s=Nu.mul(t),i=ju.xy.toVar();return i.mulAssign(this.pointWidthNode?this.pointWidthNode:Pd),i.assign(i.div(vc.z)),i.y.assign(i.y.mul(r)),i.assign(i.mul(s.w)),s.addAssign(Oi(i,0,0)),s}))(),this.fragmentNode=_i((()=>{const s=Ci(1).toVar(),i=la(pu().mul(2).sub(1));if(t&&e.samples>1){const e=Ci(i.fwidth()).toVar();s.assign(ga(e.oneMinus(),e.add(1),i).oneMinus())}else i.greaterThan(1).discard();let n;if(this.pointColorNode)n=this.pointColorNode;else if(r){n=hu("instanceColor").mul(rd)}else n=rd;return s.mulAssign(nd),Oi(n,s)}))()}get alphaToCoverage(){return this.useAlphaToCoverage}set alphaToCoverage(e){this.useAlphaToCoverage!==e&&(this.useAlphaToCoverage=e,this.needsUpdate=!0)}}const Jc=new I;class eh extends Yc{static get type(){return"LineBasicNodeMaterial"}constructor(e){super(),this.isLineBasicNodeMaterial=!0,this.lights=!1,this.setDefaultValues(Jc),this.setValues(e)}}const th=new L;class rh extends Yc{static get type(){return"LineDashedNodeMaterial"}constructor(e){super(),this.isLineDashedNodeMaterial=!0,this.lights=!1,this.setDefaultValues(th),this.dashOffset=0,this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setupVariants(){const e=this.offsetNode?Ci(this.offsetNodeNode):Fd,t=this.dashScaleNode?Ci(this.dashScaleNode):wd,r=this.dashSizeNode?Ci(this.dashSizeNode):Md,s=this.dashSizeNode?Ci(this.dashGapNode):Bd;An.assign(r),Rn.assign(s);const i=wa(hu("lineDistance").mul(t));(e?i.add(e):i).mod(An.add(Rn)).greaterThan(An).discard()}}let sh=null;class ih extends Mc{static get type(){return"ViewportSharedTextureNode"}constructor(e=xc,t=null){null===sh&&(sh=new w),super(e,t,sh)}updateReference(){return this}}const nh=xi(ih),oh=new L;class ah extends Yc{static get type(){return"Line2NodeMaterial"}constructor(e={}){super(),this.lights=!1,this.setDefaultValues(oh),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.blending=D,this.setValues(e)}setup(e){this.setupShaders(e),super.setup(e)}setupShaders({renderer:e}){const t=this.alphaToCoverage,r=this.useColor,s=this.dashed,i=this.worldUnits,n=_i((({start:e,end:t})=>{const r=Nu.element(2).element(2),s=Nu.element(3).element(2).mul(-.5).div(r).sub(e.z).div(t.z.sub(e.z));return Oi(da(e.xyz,t.xyz,s),t.w)})).setLayout({name:"trimSegment",type:"vec4",inputs:[{name:"start",type:"vec4"},{name:"end",type:"vec4"}]});this.vertexNode=_i((()=>{const e=hu("instanceStart"),t=hu("instanceEnd"),r=Oi($u.mul(Oi(e,1))).toVar("start"),o=Oi($u.mul(Oi(t,1))).toVar("end");if(s){const e=this.dashScaleNode?Ci(this.dashScaleNode):wd,t=this.offsetNode?Ci(this.offsetNodeNode):Fd,r=hu("instanceDistanceStart"),s=hu("instanceDistanceEnd");let i=ju.y.lessThan(.5).select(e.mul(r),e.mul(s));i=i.add(t),nn("float","lineDistance").assign(i)}i&&(nn("vec3","worldStart").assign(r.xyz),nn("vec3","worldEnd").assign(o.xyz));const a=vc.z.div(vc.w),u=Nu.element(2).element(3).equal(-1);Si(u,(()=>{Si(r.z.lessThan(0).and(o.z.greaterThan(0)),(()=>{o.assign(n({start:r,end:o}))})).ElseIf(o.z.lessThan(0).and(r.z.greaterThanEqual(0)),(()=>{r.assign(n({start:o,end:r}))}))}));const l=Nu.mul(r),d=Nu.mul(o),c=l.xyz.div(l.w),h=d.xyz.div(d.w),p=h.xy.sub(c.xy).toVar();p.x.assign(p.x.mul(a)),p.assign(p.normalize());const g=Oi().toVar();if(i){const e=o.xyz.sub(r.xyz).normalize(),t=da(r.xyz,o.xyz,.5).normalize(),i=e.cross(t).normalize(),n=e.cross(i),a=nn("vec4","worldPos");a.assign(ju.y.lessThan(.5).select(r,o));const u=Ud.mul(.5);a.addAssign(Oi(ju.x.lessThan(0).select(i.mul(u),i.mul(u).negate()),0)),s||(a.addAssign(Oi(ju.y.lessThan(.5).select(e.mul(u).negate(),e.mul(u)),0)),a.addAssign(Oi(n.mul(u),0)),Si(ju.y.greaterThan(1).or(ju.y.lessThan(0)),(()=>{a.subAssign(Oi(n.mul(2).mul(u),0))}))),g.assign(Nu.mul(a));const l=Ii().toVar();l.assign(ju.y.lessThan(.5).select(c,h)),g.z.assign(l.z.mul(g.w))}else{const e=Bi(p.y,p.x.negate()).toVar("offset");p.x.assign(p.x.div(a)),e.x.assign(e.x.div(a)),e.assign(ju.x.lessThan(0).select(e.negate(),e)),Si(ju.y.lessThan(0),(()=>{e.assign(e.sub(p))})).ElseIf(ju.y.greaterThan(1),(()=>{e.assign(e.add(p))})),e.assign(e.mul(Ud)),e.assign(e.div(vc.w)),g.assign(ju.y.lessThan(.5).select(l,d)),e.assign(e.mul(g.w)),g.assign(g.add(Oi(e,0,0)))}return g}))();const o=_i((({p1:e,p2:t,p3:r,p4:s})=>{const i=e.sub(r),n=s.sub(r),o=t.sub(e),a=i.dot(n),u=n.dot(o),l=i.dot(o),d=n.dot(n),c=o.dot(o).mul(d).sub(u.mul(u)),h=a.mul(u).sub(l.mul(d)).div(c).clamp(),p=a.add(u.mul(h)).div(d).clamp();return Bi(h,p)}));if(this.colorNode=_i((()=>{const n=pu();if(s){const e=this.dashSizeNode?Ci(this.dashSizeNode):Md,t=this.dashSizeNode?Ci(this.dashGapNode):Bd;An.assign(e),Rn.assign(t);const r=nn("float","lineDistance");n.y.lessThan(-1).or(n.y.greaterThan(1)).discard(),r.mod(An.add(Rn)).greaterThan(An).discard()}const a=Ci(1).toVar("alpha");if(i){const r=nn("vec3","worldStart"),i=nn("vec3","worldEnd"),n=nn("vec4","worldPos").xyz.normalize().mul(1e5),u=i.sub(r),l=o({p1:r,p2:i,p3:Ii(0,0,0),p4:n}),d=r.add(u.mul(l.x)),c=n.mul(l.y),h=d.sub(c).length().div(Ud);if(!s)if(t&&e.samples>1){const e=h.fwidth();a.assign(ga(e.negate().add(.5),e.add(.5),h).oneMinus())}else h.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)),r=e.mul(e).add(t.mul(t)),s=Ci(r.fwidth()).toVar("dlen");Si(n.y.abs().greaterThan(1),(()=>{a.assign(ga(s.oneMinus(),s.add(1),r).oneMinus())}))}else Si(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 u;if(this.lineColorNode)u=this.lineColorNode;else if(r){const e=hu("instanceColorStart"),t=hu("instanceColorEnd");u=ju.y.lessThan(.5).select(e,t).mul(rd)}else u=rd;return Oi(u,a)}))(),this.transparent){const e=this.opacityNode?Ci(this.opacityNode):nd;this.outputNode=Oi(this.colorNode.rgb.mul(e).add(nh().rgb.mul(e.oneMinus())),this.colorNode.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 uh=e=>fi(e).mul(.5).add(.5),lh=new V;class dh extends Yc{static get type(){return"MeshNormalNodeMaterial"}constructor(e){super(),this.lights=!1,this.isMeshNormalNodeMaterial=!0,this.setDefaultValues(lh),this.setValues(e)}setupDiffuseColor(){const e=this.opacityNode?Ci(this.opacityNode):nd;on.assign(Oi(uh(al),e))}}class ch extends Fs{static get type(){return"EquirectUVNode"}constructor(e=Yu){super("vec2"),this.dirNode=e}setup(){const e=this.dirNode,t=e.z.atan2(e.x).mul(1/(2*Math.PI)).add(.5),r=e.y.clamp(-1,1).asin().mul(1/Math.PI).add(.5);return Bi(t,r)}}const hh=xi(ch);class ph extends O{constructor(e=1,t={}){super(e,t),this.isCubeRenderTarget=!0}fromEquirectangularTexture(e,t){const r=t.minFilter,s=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 i=new G(5,5,5),n=hh(Yu),o=new Yc;o.colorNode=xu(t,n,0),o.side=x,o.blending=D;const a=new k(i,o),u=new z;u.add(a),t.minFilter===M&&(t.minFilter=$);const l=new H(1,10,this),d=e.getMRT();return e.setMRT(null),l.update(e,u),e.setMRT(d),t.minFilter=r,t.currentGenerateMipmaps=s,a.geometry.dispose(),a.material.dispose(),this}}const gh=new WeakMap;class mh extends Fs{static get type(){return"CubeMapNode"}constructor(e){super("vec3"),this.envNode=e,this._cubeTexture=null,this._cubeTextureNode=bl();const t=new W;t.isRenderTargetTexture=!0,this._defaultTexture=t,this.updateBeforeType=vs.RENDER}updateBefore(e){const{renderer:t,material:r}=e,s=this.envNode;if(s.isTextureNode||s.isMaterialReferenceNode){const e=s.isTextureNode?s.value:r[s.property];if(e&&e.isTexture){const r=e.mapping;if(r===j||r===q){if(gh.has(e)){const t=gh.get(e);yh(t,e.mapping),this._cubeTexture=t}else{const r=e.image;if(function(e){return null!=e&&e.height>0}(r)){const s=new ph(r.height);s.fromEquirectangularTexture(t,e),yh(s.texture,e.mapping),this._cubeTexture=s.texture,gh.set(e,s.texture),e.addEventListener("dispose",fh)}else this._cubeTexture=this._defaultTexture}this._cubeTextureNode.value=this._cubeTexture}else this._cubeTextureNode=this.envNode}}}setup(e){return this.updateBefore(e),this._cubeTextureNode}}function fh(e){const t=e.target;t.removeEventListener("dispose",fh);const r=gh.get(t);void 0!==r&&(gh.delete(t),r.dispose())}function yh(e,t){t===j?e.mapping=T:t===q&&(e.mapping=_)}const bh=xi(mh);class xh extends cc{static get type(){return"BasicEnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){e.context.environment=bh(this.envNode)}}class Th extends cc{static get type(){return"BasicLightMapNode"}constructor(e=null){super(),this.lightMapNode=e}setup(e){const t=Ci(1/Math.PI);e.context.irradianceLightMap=this.lightMapNode.mul(t)}}class _h{start(){}finish(){}direct(){}directRectArea(){}indirect(){}ambientOcclusion(){}}class vh extends _h{constructor(){super()}indirect(e,t,r){const s=e.ambientOcclusion,i=e.reflectedLight,n=r.context.irradianceLightMap;i.indirectDiffuse.assign(Oi(0)),n?i.indirectDiffuse.addAssign(n):i.indirectDiffuse.addAssign(Oi(1,1,1,0)),i.indirectDiffuse.mulAssign(s),i.indirectDiffuse.mulAssign(on.rgb)}finish(e,t,r){const s=r.material,i=e.outgoingLight,n=r.context.environment;if(n)switch(s.combine){case Y:i.rgb.assign(da(i.rgb,i.rgb.mul(n.rgb),ld.mul(dd)));break;case X:i.rgb.assign(da(i.rgb,n.rgb,ld.mul(dd)));break;case K:i.rgb.addAssign(n.rgb.mul(ld.mul(dd)));break;default:console.warn("THREE.BasicLightingModel: Unsupported .combine value:",s.combine)}}}const Nh=new Q;class Sh extends Yc{static get type(){return"MeshBasicNodeMaterial"}constructor(e){super(),this.isMeshBasicNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Nh),this.setValues(e)}setupNormal(){return nl}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new xh(t):null}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new Th(Ld)),t}setupOutgoingLight(){return on.rgb}setupLightingModel(){return new vh}}const Ah=_i((({f0:e,f90:t,dotVH:r})=>{const s=r.mul(-5.55473).sub(6.98316).mul(r).exp2();return e.mul(s.oneMinus()).add(t.mul(s))})),Rh=_i((e=>e.diffuseColor.mul(1/Math.PI))),Ch=_i((({dotNH:e})=>Nn.mul(Ci(.5)).add(1).mul(Ci(1/Math.PI)).mul(e.pow(Nn)))),Eh=_i((({lightDirection:e})=>{const t=e.add(Zu).normalize(),r=al.dot(t).clamp(),s=Zu.dot(t).clamp(),i=Ah({f0:_n,f90:1,dotVH:s}),n=Ci(.25),o=Ch({dotNH:r});return i.mul(n).mul(o)}));class wh extends vh{constructor(e=!0){super(),this.specular=e}direct({lightDirection:e,lightColor:t,reflectedLight:r}){const s=al.dot(e).clamp().mul(t);r.directDiffuse.addAssign(s.mul(Rh({diffuseColor:on.rgb}))),!0===this.specular&&r.directSpecular.addAssign(s.mul(Eh({lightDirection:e})).mul(ld))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:r}){r.indirectDiffuse.addAssign(t.mul(Rh({diffuseColor:on}))),r.indirectDiffuse.mulAssign(e)}}const Mh=new Z;class Bh extends Yc{static get type(){return"MeshLambertNodeMaterial"}constructor(e){super(),this.isMeshLambertNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Mh),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new xh(t):null}setupLightingModel(){return new wh(!1)}}const Uh=new J;class Fh extends Yc{static get type(){return"MeshPhongNodeMaterial"}constructor(e){super(),this.isMeshPhongNodeMaterial=!0,this.lights=!0,this.shininessNode=null,this.specularNode=null,this.setDefaultValues(Uh),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new xh(t):null}setupLightingModel(){return new wh}setupVariants(){const e=(this.shininessNode?Ci(this.shininessNode):sd).max(1e-4);Nn.assign(e);const t=this.specularNode||od;_n.assign(t)}copy(e){return this.shininessNode=e.shininessNode,this.specularNode=e.specularNode,super.copy(e)}}const Ph=_i((e=>{if(!1===e.geometry.hasAttribute("normal"))return Ci(0);const t=nl.dFdx().abs().max(nl.dFdy().abs());return t.x.max(t.y).max(t.z)})),Ih=_i((e=>{const{roughness:t}=e,r=Ph();let s=t.max(.0525);return s=s.add(r),s=s.min(1),s})),Lh=_i((({alpha:e,dotNL:t,dotNV:r})=>{const s=e.pow2(),i=t.mul(s.add(s.oneMinus().mul(r.pow2())).sqrt()),n=r.mul(s.add(s.oneMinus().mul(t.pow2())).sqrt());return zn(.5,i.add(n).max(uo))})).setLayout({name:"V_GGX_SmithCorrelated",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNL",type:"float"},{name:"dotNV",type:"float"}]}),Dh=_i((({alphaT:e,alphaB:t,dotTV:r,dotBV:s,dotTL:i,dotBL:n,dotNV:o,dotNL:a})=>{const u=a.mul(Ii(e.mul(r),t.mul(s),o).length()),l=o.mul(Ii(e.mul(i),t.mul(n),a).length());return zn(.5,u.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"}]}),Vh=_i((({alpha:e,dotNH:t})=>{const r=e.pow2(),s=t.pow2().mul(r.oneMinus()).oneMinus();return r.div(s.pow2()).mul(1/Math.PI)})).setLayout({name:"D_GGX",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNH",type:"float"}]}),Oh=Ci(1/Math.PI),Gh=_i((({alphaT:e,alphaB:t,dotNH:r,dotTH:s,dotBH:i})=>{const n=e.mul(t),o=Ii(t.mul(s),e.mul(i),n.mul(r)),a=o.dot(o),u=n.div(a);return Oh.mul(n.mul(u.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"}]}),kh=_i((e=>{const{lightDirection:t,f0:r,f90:s,roughness:i,f:n,USE_IRIDESCENCE:o,USE_ANISOTROPY:a}=e,u=e.normalView||al,l=i.pow2(),d=t.add(Zu).normalize(),c=u.dot(t).clamp(),h=u.dot(Zu).clamp(),p=u.dot(d).clamp(),g=Zu.dot(d).clamp();let m,f,y=Ah({f0:r,f90:s,dotVH:g});if(pi(o)&&(y=gn.mix(y,n)),pi(a)){const e=xn.dot(t),r=xn.dot(Zu),s=xn.dot(d),i=Tn.dot(t),n=Tn.dot(Zu),o=Tn.dot(d);m=Dh({alphaT:yn,alphaB:l,dotTV:r,dotBV:n,dotTL:e,dotBL:i,dotNV:h,dotNL:c}),f=Gh({alphaT:yn,alphaB:l,dotNH:p,dotTH:s,dotBH:o})}else m=Lh({alpha:l,dotNL:c,dotNV:h}),f=Vh({alpha:l,dotNH:p});return y.mul(m).mul(f)})),zh=_i((({roughness:e,dotNV:t})=>{const r=Oi(-1,-.0275,-.572,.022),s=Oi(1,.0425,1.04,-.04),i=e.mul(r).add(s),n=i.x.mul(i.x).min(t.mul(-9.28).exp2()).mul(i.x).add(i.y);return Bi(-1.04,1.04).mul(n).add(i.zw)})).setLayout({name:"DFGApprox",type:"vec2",inputs:[{name:"roughness",type:"float"},{name:"dotNV",type:"vec3"}]}),$h=_i((e=>{const{dotNV:t,specularColor:r,specularF90:s,roughness:i}=e,n=zh({dotNV:t,roughness:i});return r.mul(n.x).add(s.mul(n.y))})),Hh=_i((({f:e,f90:t,dotVH:r})=>{const s=r.oneMinus().saturate(),i=s.mul(s),n=s.mul(i,i).clamp(0,.9999);return e.sub(Ii(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"}]}),Wh=_i((({roughness:e,dotNH:t})=>{const r=e.pow2(),s=Ci(1).div(r),i=t.pow2().oneMinus().max(.0078125);return Ci(2).add(s).mul(i.pow(s.mul(.5))).div(2*Math.PI)})).setLayout({name:"D_Charlie",type:"float",inputs:[{name:"roughness",type:"float"},{name:"dotNH",type:"float"}]}),jh=_i((({dotNV:e,dotNL:t})=>Ci(1).div(Ci(4).mul(t.add(e).sub(t.mul(e)))))).setLayout({name:"V_Neubelt",type:"float",inputs:[{name:"dotNV",type:"float"},{name:"dotNL",type:"float"}]}),qh=_i((({lightDirection:e})=>{const t=e.add(Zu).normalize(),r=al.dot(e).clamp(),s=al.dot(Zu).clamp(),i=al.dot(t).clamp(),n=Wh({roughness:pn,dotNH:i}),o=jh({dotNV:s,dotNL:r});return hn.mul(n).mul(o)})),Kh=_i((({N:e,V:t,roughness:r})=>{const s=e.dot(t).saturate(),i=Bi(r,s.oneMinus().sqrt());return i.assign(i.mul(.984375).add(.0078125)),i})).setLayout({name:"LTC_Uv",type:"vec2",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"roughness",type:"float"}]}),Xh=_i((({f:e})=>{const t=e.length();return Xo(t.mul(t).add(e.z).div(t.add(1)),0)})).setLayout({name:"LTC_ClippedSphereFormFactor",type:"float",inputs:[{name:"f",type:"vec3"}]}),Yh=_i((({v1:e,v2:t})=>{const r=e.dot(t),s=r.abs().toVar(),i=s.mul(.0145206).add(.4965155).mul(s).add(.8543985).toVar(),n=s.add(4.1616724).mul(s).add(3.417594).toVar(),o=i.div(n),a=r.greaterThan(0).select(o,Xo(r.mul(r).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"}]}),Qh=_i((({N:e,V:t,P:r,mInv:s,p0:i,p1:n,p2:o,p3:a})=>{const u=n.sub(i).toVar(),l=a.sub(i).toVar(),d=u.cross(l),c=Ii().toVar();return Si(d.dot(r.sub(i)).greaterThanEqual(0),(()=>{const u=t.sub(e.mul(t.dot(e))).normalize(),l=e.cross(u).negate(),d=s.mul(Hi(u,l,e).transpose()).toVar(),h=d.mul(i.sub(r)).normalize().toVar(),p=d.mul(n.sub(r)).normalize().toVar(),g=d.mul(o.sub(r)).normalize().toVar(),m=d.mul(a.sub(r)).normalize().toVar(),f=Ii(0).toVar();f.addAssign(Yh({v1:h,v2:p})),f.addAssign(Yh({v1:p,v2:g})),f.addAssign(Yh({v1:g,v2:m})),f.addAssign(Yh({v1:m,v2:h})),c.assign(Ii(Xh({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"}]}),Zh=1/6,Jh=e=>kn(Zh,kn(e,kn(e,e.negate().add(3)).sub(3)).add(1)),ep=e=>kn(Zh,kn(e,kn(e,kn(3,e).sub(6))).add(4)),tp=e=>kn(Zh,kn(e,kn(e,kn(-3,e).add(3)).add(3)).add(1)),rp=e=>kn(Zh,sa(e,3)),sp=e=>Jh(e).add(ep(e)),ip=e=>tp(e).add(rp(e)),np=e=>On(-1,ep(e).div(Jh(e).add(ep(e)))),op=e=>On(1,rp(e).div(tp(e).add(rp(e)))),ap=(e,t,r)=>{const s=e.uvNode,i=kn(s,t.zw).add(.5),n=So(i),o=Co(i),a=sp(o.x),u=ip(o.x),l=np(o.x),d=op(o.x),c=np(o.y),h=op(o.y),p=Bi(n.x.add(l),n.y.add(c)).sub(.5).mul(t.xy),g=Bi(n.x.add(d),n.y.add(c)).sub(.5).mul(t.xy),m=Bi(n.x.add(l),n.y.add(h)).sub(.5).mul(t.xy),f=Bi(n.x.add(d),n.y.add(h)).sub(.5).mul(t.xy),y=sp(o.y).mul(On(a.mul(e.sample(p).level(r)),u.mul(e.sample(g).level(r)))),b=ip(o.y).mul(On(a.mul(e.sample(m).level(r)),u.mul(e.sample(f).level(r))));return y.add(b)},up=_i((([e,t=Ci(3)])=>{const r=Bi(e.size(Ei(t))),s=Bi(e.size(Ei(t.add(1)))),i=zn(1,r),n=zn(1,s),o=ap(e,Oi(i,r),So(t)),a=ap(e,Oi(n,s),Ao(t));return Co(t).mix(o,a)})),lp=_i((([e,t,r,s,i])=>{const n=Ii(pa(t.negate(),Ro(e),zn(1,s))),o=Ii(Lo(i[0].xyz),Lo(i[1].xyz),Lo(i[2].xyz));return Ro(n).mul(r.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"}]}),dp=_i((([e,t])=>e.mul(ca(t.mul(2).sub(2),0,1)))).setLayout({name:"applyIorToRoughness",type:"float",inputs:[{name:"roughness",type:"float"},{name:"ior",type:"float"}]}),cp=Uc(),hp=Uc(),pp=_i((([e,t,r],{material:s})=>{const i=(s.side===x?cp:hp).sample(e),n=_o(Tc.x).mul(dp(t,r));return up(i,n)})),gp=_i((([e,t,r])=>(Si(r.notEqual(0),(()=>{const s=To(t).negate().div(r);return bo(s.negate().mul(e))})),Ii(1)))).setLayout({name:"volumeAttenuation",type:"vec3",inputs:[{name:"transmissionDistance",type:"float"},{name:"attenuationColor",type:"vec3"},{name:"attenuationDistance",type:"float"}]}),mp=_i((([e,t,r,s,i,n,o,a,u,l,d,c,h,p,g])=>{let m,f;if(g){m=Oi().toVar(),f=Ii().toVar();const i=d.sub(1).mul(g.mul(.025)),n=Ii(d.sub(i),d,d.add(i));ic({start:0,end:3},(({i:i})=>{const d=n.element(i),g=lp(e,t,c,d,a),y=o.add(g),b=l.mul(u.mul(Oi(y,1))),x=Bi(b.xy.div(b.w)).toVar();x.addAssign(1),x.divAssign(2),x.assign(Bi(x.x,x.y.oneMinus()));const T=pp(x,r,d);m.element(i).assign(T.element(i)),m.a.addAssign(T.a),f.element(i).assign(s.element(i).mul(gp(Lo(g),h,p).element(i)))})),m.a.divAssign(3)}else{const i=lp(e,t,c,d,a),n=o.add(i),g=l.mul(u.mul(Oi(n,1))),y=Bi(g.xy.div(g.w)).toVar();y.addAssign(1),y.divAssign(2),y.assign(Bi(y.x,y.y.oneMinus())),m=pp(y,r,d),f=s.mul(gp(Lo(i),h,p))}const y=f.rgb.mul(m.rgb),b=e.dot(t).clamp(),x=Ii($h({dotNV:b,specularColor:i,specularF90:n,roughness:r})),T=f.r.add(f.g,f.b).div(3);return Oi(x.oneMinus().mul(y),m.a.oneMinus().mul(T).oneMinus())})),fp=Hi(3.2404542,-.969266,.0556434,-1.5371385,1.8760108,-.2040259,-.4985314,.041556,1.0572252),yp=(e,t)=>e.sub(t).div(e.add(t)).pow2(),bp=_i((({outsideIOR:e,eta2:t,cosTheta1:r,thinFilmThickness:s,baseF0:i})=>{const n=da(e,t,ga(0,.03,s)),o=e.div(n).pow2().mul(r.pow2().oneMinus()).oneMinus();Si(o.lessThan(0),(()=>Ii(1)));const a=o.sqrt(),u=yp(n,e),l=Ah({f0:u,f90:1,dotVH:r}),d=l.oneMinus(),c=n.lessThan(e).select(Math.PI,0),h=Ci(Math.PI).sub(c),p=(e=>{const t=e.sqrt();return Ii(1).add(t).div(Ii(1).sub(t))})(i.clamp(0,.9999)),g=yp(p,n.toVec3()),m=Ah({f0:g,f90:1,dotVH:a}),f=Ii(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(s,a,2),b=Ii(h).add(f),x=l.mul(m).clamp(1e-5,.9999),T=x.sqrt(),_=d.pow2().mul(m).div(Ii(1).sub(x)),v=l.add(_).toVar(),N=_.sub(d).toVar();return ic({start:1,end:2,condition:"<=",name:"m"},(({m:e})=>{N.mulAssign(T);const t=((e,t)=>{const r=e.mul(2*Math.PI*1e-9),s=Ii(54856e-17,44201e-17,52481e-17),i=Ii(1681e3,1795300,2208400),n=Ii(43278e5,93046e5,66121e5),o=Ci(9747e-17*Math.sqrt(2*Math.PI*45282e5)).mul(r.mul(2239900).add(t.x).cos()).mul(r.pow2().mul(-45282e5).exp());let a=s.mul(n.mul(2*Math.PI).sqrt()).mul(i.mul(r).add(t).cos()).mul(r.pow2().negate().mul(n).exp());return a=Ii(a.x.add(o),a.y,a.z).div(1.0685e-7),fp.mul(a)})(Ci(e).mul(y),Ci(e).mul(b)).mul(2);v.addAssign(N.mul(t))})),v.max(Ii(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"}]}),xp=_i((({normal:e,viewDir:t,roughness:r})=>{const s=e.dot(t).saturate(),i=r.pow2(),n=Ta(r.lessThan(.25),Ci(-339.2).mul(i).add(Ci(161.4).mul(r)).sub(25.9),Ci(-8.48).mul(i).add(Ci(14.3).mul(r)).sub(9.95)),o=Ta(r.lessThan(.25),Ci(44).mul(i).sub(Ci(23.7).mul(r)).add(3.26),Ci(1.97).mul(i).sub(Ci(3.27).mul(r)).add(.72));return Ta(r.lessThan(.25),0,Ci(.1).mul(r).sub(.025)).add(n.mul(s).add(o).exp()).mul(1/Math.PI).saturate()})),Tp=Ii(.04),_p=Ci(1);class vp extends _h{constructor(e=!1,t=!1,r=!1,s=!1,i=!1,n=!1){super(),this.clearcoat=e,this.sheen=t,this.iridescence=r,this.anisotropy=s,this.transmission=i,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=Ii().toVar("clearcoatRadiance"),this.clearcoatSpecularDirect=Ii().toVar("clearcoatSpecularDirect"),this.clearcoatSpecularIndirect=Ii().toVar("clearcoatSpecularIndirect")),!0===this.sheen&&(this.sheenSpecularDirect=Ii().toVar("sheenSpecularDirect"),this.sheenSpecularIndirect=Ii().toVar("sheenSpecularIndirect")),!0===this.iridescence){const e=al.dot(Zu).clamp();this.iridescenceFresnel=bp({outsideIOR:Ci(1),eta2:mn,cosTheta1:e,thinFilmThickness:fn,baseF0:_n}),this.iridescenceF0=Hh({f:this.iridescenceFresnel,f90:1,dotVH:e})}if(!0===this.transmission){const t=Xu,r=Eu.sub(Xu).normalize(),s=ul;e.backdrop=mp(s,r,un,on,_n,vn,t,Du,Au,Nu,En,Mn,Un,Bn,this.dispersion?Fn:null),e.backdropAlpha=wn,on.a.mulAssign(da(1,e.backdrop.a,wn))}}computeMultiscattering(e,t,r){const s=al.dot(Zu).clamp(),i=zh({roughness:un,dotNV:s}),n=(this.iridescenceF0?gn.mix(_n,this.iridescenceF0):_n).mul(i.x).add(r.mul(i.y)),o=i.x.add(i.y).oneMinus(),a=_n.add(_n.oneMinus().mul(.047619)),u=n.mul(a).div(o.mul(a).oneMinus());e.addAssign(n),t.addAssign(u.mul(o))}direct({lightDirection:e,lightColor:t,reflectedLight:r}){const s=al.dot(e).clamp().mul(t);if(!0===this.sheen&&this.sheenSpecularDirect.addAssign(s.mul(qh({lightDirection:e}))),!0===this.clearcoat){const r=ll.dot(e).clamp().mul(t);this.clearcoatSpecularDirect.addAssign(r.mul(kh({lightDirection:e,f0:Tp,f90:_p,roughness:cn,normalView:ll})))}r.directDiffuse.addAssign(s.mul(Rh({diffuseColor:on.rgb}))),r.directSpecular.addAssign(s.mul(kh({lightDirection:e,f0:_n,f90:1,roughness:un,iridescence:this.iridescence,f:this.iridescenceFresnel,USE_IRIDESCENCE:this.iridescence,USE_ANISOTROPY:this.anisotropy})))}directRectArea({lightColor:e,lightPosition:t,halfWidth:r,halfHeight:s,reflectedLight:i,ltc_1:n,ltc_2:o}){const a=t.add(r).sub(s),u=t.sub(r).sub(s),l=t.sub(r).add(s),d=t.add(r).add(s),c=al,h=Zu,p=Qu.toVar(),g=Kh({N:c,V:h,roughness:un}),m=n.sample(g).toVar(),f=o.sample(g).toVar(),y=Hi(Ii(m.x,0,m.y),Ii(0,1,0),Ii(m.z,0,m.w)).toVar(),b=_n.mul(f.x).add(_n.oneMinus().mul(f.y)).toVar();i.directSpecular.addAssign(e.mul(b).mul(Qh({N:c,V:h,P:p,mInv:y,p0:a,p1:u,p2:l,p3:d}))),i.directDiffuse.addAssign(e.mul(on).mul(Qh({N:c,V:h,P:p,mInv:Hi(1,0,0,0,1,0,0,0,1),p0:a,p1:u,p2:l,p3:d})))}indirect(e,t,r){this.indirectDiffuse(e,t,r),this.indirectSpecular(e,t,r),this.ambientOcclusion(e,t,r)}indirectDiffuse({irradiance:e,reflectedLight:t}){t.indirectDiffuse.addAssign(e.mul(Rh({diffuseColor:on})))}indirectSpecular({radiance:e,iblIrradiance:t,reflectedLight:r}){if(!0===this.sheen&&this.sheenSpecularIndirect.addAssign(t.mul(hn,xp({normal:al,viewDir:Zu,roughness:pn}))),!0===this.clearcoat){const e=ll.dot(Zu).clamp(),t=$h({dotNV:e,specularColor:Tp,specularF90:_p,roughness:cn});this.clearcoatSpecularIndirect.addAssign(this.clearcoatRadiance.mul(t))}const s=Ii().toVar("singleScattering"),i=Ii().toVar("multiScattering"),n=t.mul(1/Math.PI);this.computeMultiscattering(s,i,vn);const o=s.add(i),a=on.mul(o.r.max(o.g).max(o.b).oneMinus());r.indirectSpecular.addAssign(e.mul(s)),r.indirectSpecular.addAssign(i.mul(n)),r.indirectDiffuse.addAssign(a.mul(n))}ambientOcclusion({ambientOcclusion:e,reflectedLight:t}){const r=al.dot(Zu).clamp().add(e),s=un.mul(-16).oneMinus().negate().exp2(),i=e.sub(r.pow(s).oneMinus()).clamp();!0===this.clearcoat&&this.clearcoatSpecularIndirect.mulAssign(e),!0===this.sheen&&this.sheenSpecularIndirect.mulAssign(e),t.indirectDiffuse.mulAssign(e),t.indirectSpecular.mulAssign(i)}finish(e){const{outgoingLight:t}=e;if(!0===this.clearcoat){const e=ll.dot(Zu).clamp(),r=Ah({dotVH:e,f0:Tp,f90:_p}),s=t.mul(dn.mul(r).oneMinus()).add(this.clearcoatSpecularDirect.add(this.clearcoatSpecularIndirect).mul(dn));t.assign(s)}if(!0===this.sheen){const e=hn.r.max(hn.g).max(hn.b).mul(.157).oneMinus(),r=t.mul(e).add(this.sheenSpecularDirect,this.sheenSpecularIndirect);t.assign(r)}}}const Np=Ci(1),Sp=Ci(-2),Ap=Ci(.8),Rp=Ci(-1),Cp=Ci(.4),Ep=Ci(2),wp=Ci(.305),Mp=Ci(3),Bp=Ci(.21),Up=Ci(4),Fp=Ci(4),Pp=Ci(16),Ip=_i((([e])=>{const t=Ii(Po(e)).toVar(),r=Ci(-1).toVar();return Si(t.x.greaterThan(t.z),(()=>{Si(t.x.greaterThan(t.y),(()=>{r.assign(Ta(e.x.greaterThan(0),0,3))})).Else((()=>{r.assign(Ta(e.y.greaterThan(0),1,4))}))})).Else((()=>{Si(t.z.greaterThan(t.y),(()=>{r.assign(Ta(e.z.greaterThan(0),2,5))})).Else((()=>{r.assign(Ta(e.y.greaterThan(0),1,4))}))})),r})).setLayout({name:"getFace",type:"float",inputs:[{name:"direction",type:"vec3"}]}),Lp=_i((([e,t])=>{const r=Bi().toVar();return Si(t.equal(0),(()=>{r.assign(Bi(e.z,e.y).div(Po(e.x)))})).ElseIf(t.equal(1),(()=>{r.assign(Bi(e.x.negate(),e.z.negate()).div(Po(e.y)))})).ElseIf(t.equal(2),(()=>{r.assign(Bi(e.x.negate(),e.y).div(Po(e.z)))})).ElseIf(t.equal(3),(()=>{r.assign(Bi(e.z.negate(),e.y).div(Po(e.x)))})).ElseIf(t.equal(4),(()=>{r.assign(Bi(e.x.negate(),e.z).div(Po(e.y)))})).Else((()=>{r.assign(Bi(e.x,e.y).div(Po(e.z)))})),kn(.5,r.add(1))})).setLayout({name:"getUV",type:"vec2",inputs:[{name:"direction",type:"vec3"},{name:"face",type:"float"}]}),Dp=_i((([e])=>{const t=Ci(0).toVar();return Si(e.greaterThanEqual(Ap),(()=>{t.assign(Np.sub(e).mul(Rp.sub(Sp)).div(Np.sub(Ap)).add(Sp))})).ElseIf(e.greaterThanEqual(Cp),(()=>{t.assign(Ap.sub(e).mul(Ep.sub(Rp)).div(Ap.sub(Cp)).add(Rp))})).ElseIf(e.greaterThanEqual(wp),(()=>{t.assign(Cp.sub(e).mul(Mp.sub(Ep)).div(Cp.sub(wp)).add(Ep))})).ElseIf(e.greaterThanEqual(Bp),(()=>{t.assign(wp.sub(e).mul(Up.sub(Mp)).div(wp.sub(Bp)).add(Mp))})).Else((()=>{t.assign(Ci(-2).mul(_o(kn(1.16,e))))})),t})).setLayout({name:"roughnessToMip",type:"float",inputs:[{name:"roughness",type:"float"}]}),Vp=_i((([e,t])=>{const r=e.toVar();r.assign(kn(2,r).sub(1));const s=Ii(r,1).toVar();return Si(t.equal(0),(()=>{s.assign(s.zyx)})).ElseIf(t.equal(1),(()=>{s.assign(s.xzy),s.xz.mulAssign(-1)})).ElseIf(t.equal(2),(()=>{s.x.mulAssign(-1)})).ElseIf(t.equal(3),(()=>{s.assign(s.zyx),s.xz.mulAssign(-1)})).ElseIf(t.equal(4),(()=>{s.assign(s.xzy),s.xy.mulAssign(-1)})).ElseIf(t.equal(5),(()=>{s.z.mulAssign(-1)})),s})).setLayout({name:"getDirection",type:"vec3",inputs:[{name:"uv",type:"vec2"},{name:"face",type:"float"}]}),Op=_i((([e,t,r,s,i,n])=>{const o=Ci(r),a=Ii(t),u=ca(Dp(o),Sp,n),l=Co(u),d=So(u),c=Ii(Gp(e,a,d,s,i,n)).toVar();return Si(l.notEqual(0),(()=>{const t=Ii(Gp(e,a,d.add(1),s,i,n)).toVar();c.assign(da(c,t,l))})),c})),Gp=_i((([e,t,r,s,i,n])=>{const o=Ci(r).toVar(),a=Ii(t),u=Ci(Ip(a)).toVar(),l=Ci(Xo(Fp.sub(o),0)).toVar();o.assign(Xo(o,Fp));const d=Ci(xo(o)).toVar(),c=Bi(Lp(a,u).mul(d.sub(2)).add(1)).toVar();return Si(u.greaterThan(2),(()=>{c.y.addAssign(d),u.subAssign(3)})),c.x.addAssign(u.mul(d)),c.x.addAssign(l.mul(kn(3,Pp))),c.y.addAssign(kn(4,xo(n).sub(d))),c.x.mulAssign(s),c.y.mulAssign(i),e.sample(c).grad(Bi(),Bi())})),kp=_i((({envMap:e,mipInt:t,outputDirection:r,theta:s,axis:i,CUBEUV_TEXEL_WIDTH:n,CUBEUV_TEXEL_HEIGHT:o,CUBEUV_MAX_MIP:a})=>{const u=wo(s),l=r.mul(u).add(i.cross(r).mul(Eo(s))).add(i.mul(i.dot(r).mul(u.oneMinus())));return Gp(e,l,t,n,o,a)})),zp=_i((({n:e,latitudinal:t,poleAxis:r,outputDirection:s,weights:i,samples:n,dTheta:o,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c})=>{const h=Ii(Ta(t,r,ra(r,s))).toVar();Si(po(h.equals(Ii(0))),(()=>{h.assign(Ii(s.z,0,s.x.negate()))})),h.assign(Ro(h));const p=Ii().toVar();return p.addAssign(i.element(Ei(0)).mul(kp({theta:0,axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c}))),ic({start:Ei(1),end:e},(({i:e})=>{Si(e.greaterThanEqual(n),(()=>{nc()}));const t=Ci(o.mul(Ci(e))).toVar();p.addAssign(i.element(e).mul(kp({theta:t.mul(-1),axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c}))),p.addAssign(i.element(e).mul(kp({theta:t,axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c})))})),Oi(p,1)}));let $p=null;const Hp=new WeakMap;function Wp(e){let t=Hp.get(e);if((void 0!==t?t.pmremVersion:-1)!==e.pmremVersion){const r=e.image;if(e.isCubeTexture){if(!function(e){if(null==e)return!1;let t=0;const r=6;for(let s=0;s0}(r))return null;t=$p.fromEquirectangular(e,t)}t.pmremVersion=e.pmremVersion,Hp.set(e,t)}return t.texture}class jp extends Fs{static get type(){return"PMREMNode"}constructor(e,t=null,r=null){super("vec3"),this._value=e,this._pmrem=null,this.uvNode=t,this.levelNode=r,this._generator=null;const s=new ee;s.isRenderTargetTexture=!0,this._texture=xu(s),this._width=tn(0),this._height=tn(0),this._maxMip=tn(0),this.updateBeforeType=vs.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,r=1/e;return{texelWidth:1/(3*Math.max(Math.pow(2,t),112)),texelHeight:r,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,r=this._value;t!==r.pmremVersion&&(e=!0===r.isPMREMTexture?r:Wp(r),null!==e&&(this._pmrem=e,this.updateFromTexture(e)))}setup(e){null===$p&&($p=e.createPMREMGenerator()),this.updateBefore(e);let t=this.uvNode;null===t&&e.context.getUV&&(t=e.context.getUV(this));const r=this.value;e.renderer.coordinateSystem===b&&!0!==r.isPMREMTexture&&!0===r.isRenderTargetTexture&&(t=Ii(t.x.negate(),t.yz)),t=Ii(t.x,t.y.negate(),t.z);let s=this.levelNode;return null===s&&e.context.getTextureLevel&&(s=e.context.getTextureLevel(this)),Op(this._texture,t,s,this._width,this._height,this._maxMip)}}const qp=xi(jp),Kp=new WeakMap;class Xp extends cc{static get type(){return"EnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){const{material:t}=e;let r=this.envNode;if(r.isTextureNode||r.isMaterialReferenceNode){const e=r.isTextureNode?r.value:t[r.property];let s=Kp.get(e);void 0===s&&(s=qp(e),Kp.set(e,s)),r=s}const s=t.envMap?Rl("envMapIntensity","float",e.material):Rl("environmentIntensity","float",e.scene),i=!0===t.useAnisotropy||t.anisotropy>0?Wl:al,n=r.context(Yp(un,i)).mul(s),o=r.context(Qp(ul)).mul(Math.PI).mul(s),a=eu(n),u=eu(o);e.context.radiance.addAssign(a),e.context.iblIrradiance.addAssign(u);const l=e.context.lightingModel.clearcoatRadiance;if(l){const e=r.context(Yp(cn,ll)).mul(s),t=eu(e);l.addAssign(t)}}}const Yp=(e,t)=>{let r=null;return{getUV:()=>(null===r&&(r=Zu.negate().reflect(t),r=e.mul(e).mix(r,t).normalize(),r=r.transformDirection(Au)),r),getTextureLevel:()=>e}},Qp=e=>({getUV:()=>e,getTextureLevel:()=>Ci(1)}),Zp=new te;class Jp extends Yc{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(Zp),this.setValues(e)}setupEnvironment(e){let t=super.setupEnvironment(e);return null===t&&e.environmentNode&&(t=e.environmentNode),t?new Xp(t):null}setupLightingModel(){return new vp}setupSpecular(){const e=da(Ii(.04),on.rgb,ln);_n.assign(e),vn.assign(1)}setupVariants(){const e=this.metalnessNode?Ci(this.metalnessNode):hd;ln.assign(e);let t=this.roughnessNode?Ci(this.roughnessNode):cd;t=Ih({roughness:t}),un.assign(t),this.setupSpecular(),on.assign(Oi(on.rgb.mul(e.oneMinus()),on.a))}copy(e){return this.emissiveNode=e.emissiveNode,this.metalnessNode=e.metalnessNode,this.roughnessNode=e.roughnessNode,super.copy(e)}}const eg=new re;class tg extends Jp{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(eg),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?Ci(this.iorNode):Rd;En.assign(e),_n.assign(da(Ko(ia(En.sub(1).div(En.add(1))).mul(ud),Ii(1)).mul(ad),on.rgb,ln)),vn.assign(da(ad,1,ln))}setupLightingModel(){return new vp(this.useClearcoat,this.useSheen,this.useIridescence,this.useAnisotropy,this.useTransmission,this.useDispersion)}setupVariants(e){if(super.setupVariants(e),this.useClearcoat){const e=this.clearcoatNode?Ci(this.clearcoatNode):gd,t=this.clearcoatRoughnessNode?Ci(this.clearcoatRoughnessNode):md;dn.assign(e),cn.assign(Ih({roughness:t}))}if(this.useSheen){const e=this.sheenNode?Ii(this.sheenNode):bd,t=this.sheenRoughnessNode?Ci(this.sheenRoughnessNode):xd;hn.assign(e),pn.assign(t)}if(this.useIridescence){const e=this.iridescenceNode?Ci(this.iridescenceNode):_d,t=this.iridescenceIORNode?Ci(this.iridescenceIORNode):vd,r=this.iridescenceThicknessNode?Ci(this.iridescenceThicknessNode):Nd;gn.assign(e),mn.assign(t),fn.assign(r)}if(this.useAnisotropy){const e=(this.anisotropyNode?Bi(this.anisotropyNode):Td).toVar();bn.assign(e.length()),Si(bn.equal(0),(()=>{e.assign(Bi(1,0))})).Else((()=>{e.divAssign(Bi(bn)),bn.assign(bn.saturate())})),yn.assign(bn.pow2().mix(un.pow2(),1)),xn.assign($l[0].mul(e.x).add($l[1].mul(e.y))),Tn.assign($l[1].mul(e.x).sub($l[0].mul(e.y)))}if(this.useTransmission){const e=this.transmissionNode?Ci(this.transmissionNode):Sd,t=this.thicknessNode?Ci(this.thicknessNode):Ad,r=this.attenuationDistanceNode?Ci(this.attenuationDistanceNode):Cd,s=this.attenuationColorNode?Ii(this.attenuationColorNode):Ed;if(wn.assign(e),Mn.assign(t),Bn.assign(r),Un.assign(s),this.useDispersion){const e=this.dispersionNode?Ci(this.dispersionNode):Id;Fn.assign(e)}}}setupClearcoatNormal(){return this.clearcoatNormalNode?Ii(this.clearcoatNormalNode):fd}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 rg extends vp{constructor(e,t,r,s){super(e,t,r),this.useSSS=s}direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i){if(!0===this.useSSS){const s=i.material,{thicknessColorNode:n,thicknessDistortionNode:o,thicknessAmbientNode:a,thicknessAttenuationNode:u,thicknessPowerNode:l,thicknessScaleNode:d}=s,c=e.add(al.mul(o)).normalize(),h=Ci(Zu.dot(c.negate()).saturate().pow(l).mul(d)),p=Ii(h.add(a).mul(n));r.directDiffuse.addAssign(p.mul(u.mul(t)))}super.direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i)}}class sg extends tg{static get type(){return"MeshSSSNodeMaterial"}constructor(e){super(e),this.thicknessColorNode=null,this.thicknessDistortionNode=Ci(.1),this.thicknessAmbientNode=Ci(0),this.thicknessAttenuationNode=Ci(.1),this.thicknessPowerNode=Ci(2),this.thicknessScaleNode=Ci(10)}get useSSS(){return null!==this.thicknessColorNode}setupLightingModel(){return new rg(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 ig=_i((({normal:e,lightDirection:t,builder:r})=>{const s=e.dot(t),i=Bi(s.mul(.5).add(.5),0);if(r.material.gradientMap){const e=wl("gradientMap","texture").context({getUV:()=>i});return Ii(e.r)}{const e=i.fwidth().mul(.5);return da(Ii(.7),Ii(1),ga(Ci(.7).sub(e.x),Ci(.7).add(e.x),i.x))}}));class ng extends _h{direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i){const n=ig({normal:rl,lightDirection:e,builder:i}).mul(t);r.directDiffuse.addAssign(n.mul(Rh({diffuseColor:on.rgb})))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:r}){r.indirectDiffuse.addAssign(t.mul(Rh({diffuseColor:on}))),r.indirectDiffuse.mulAssign(e)}}const og=new se;class ag extends Yc{static get type(){return"MeshToonNodeMaterial"}constructor(e){super(),this.isMeshToonNodeMaterial=!0,this.lights=!0,this.setDefaultValues(og),this.setValues(e)}setupLightingModel(){return new ng}}class ug extends Fs{static get type(){return"MatcapUVNode"}constructor(){super("vec2")}setup(){const e=Ii(Zu.z,0,Zu.x.negate()).normalize(),t=Zu.cross(e);return Bi(e.dot(al),t.dot(al)).mul(.495).add(.5)}}const lg=Ti(ug),dg=new ie;class cg extends Yc{static get type(){return"MeshMatcapNodeMaterial"}constructor(e){super(),this.lights=!1,this.isMeshMatcapNodeMaterial=!0,this.setDefaultValues(dg),this.setValues(e)}setupVariants(e){const t=lg;let r;r=e.material.matcap?wl("matcap","texture").context({getUV:()=>t}):Ii(da(.2,.8,t.y)),on.rgb.mulAssign(r.rgb)}}const hg=new P;class pg extends Yc{static get type(){return"PointsNodeMaterial"}constructor(e){super(),this.isPointsNodeMaterial=!0,this.lights=!1,this.transparent=!0,this.sizeNode=null,this.setDefaultValues(hg),this.setValues(e)}copy(e){return this.sizeNode=e.sizeNode,super.copy(e)}}class gg extends Fs{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:r}=this;if("vec2"===this.getNodeType(e)){const e=t.cos(),s=t.sin();return $i(e,s,s.negate(),e).mul(r)}{const e=t,s=Wi(Oi(1,0,0,0),Oi(0,wo(e.x),Eo(e.x).negate(),0),Oi(0,Eo(e.x),wo(e.x),0),Oi(0,0,0,1)),i=Wi(Oi(wo(e.y),0,Eo(e.y),0),Oi(0,1,0,0),Oi(Eo(e.y).negate(),0,wo(e.y),0),Oi(0,0,0,1)),n=Wi(Oi(wo(e.z),Eo(e.z).negate(),0,0),Oi(Eo(e.z),wo(e.z),0,0),Oi(0,0,1,0),Oi(0,0,0,1));return s.mul(i).mul(n).mul(Oi(r,1)).xyz}}}const mg=xi(gg),fg=new ne;class yg extends Yc{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(fg),this.setValues(e)}setupPosition({object:e,camera:t,context:r}){const s=this.sizeAttenuation,{positionNode:i,rotationNode:n,scaleNode:o}=this,a=qu;let u=$u.mul(Ii(i||0)),l=Bi(Du[0].xyz.length(),Du[1].xyz.length());if(null!==o&&(l=l.mul(o)),!s)if(t.isPerspectiveCamera)l=l.mul(u.z.negate());else{const e=Ci(2).div(Nu.element(1).element(1));l=l.mul(e.mul(2))}let d=a.xy;if(e.center&&!0===e.center.isVector2){const e=((e,t,r)=>fi(new Ga(e,t,r)))("center","vec2");d=d.sub(e.sub(.5))}d=d.mul(l);const c=Ci(n||yd),h=mg(d,c);u=Oi(u.xy.add(h),u.zw);const p=Nu.mul(u);return r.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 bg extends _h{constructor(){super(),this.shadowNode=Ci(1).toVar("shadowMask")}direct({shadowMask:e}){this.shadowNode.mulAssign(e)}finish(e){on.a.mulAssign(this.shadowNode.oneMinus()),e.outgoingLight.rgb.assign(on.rgb)}}const xg=new oe;class Tg extends Yc{static get type(){return"ShadowNodeMaterial"}constructor(e){super(),this.isShadowNodeMaterial=!0,this.lights=!0,this.setDefaultValues(xg),this.setValues(e)}setupLightingModel(){return new bg}}const _g=_i((({texture:e,uv:t})=>{const r=1e-4,s=Ii().toVar();return Si(t.x.lessThan(r),(()=>{s.assign(Ii(1,0,0))})).ElseIf(t.y.lessThan(r),(()=>{s.assign(Ii(0,1,0))})).ElseIf(t.z.lessThan(r),(()=>{s.assign(Ii(0,0,1))})).ElseIf(t.x.greaterThan(.9999),(()=>{s.assign(Ii(-1,0,0))})).ElseIf(t.y.greaterThan(.9999),(()=>{s.assign(Ii(0,-1,0))})).ElseIf(t.z.greaterThan(.9999),(()=>{s.assign(Ii(0,0,-1))})).Else((()=>{const r=.01,i=e.sample(t.add(Ii(-.01,0,0))).r.sub(e.sample(t.add(Ii(r,0,0))).r),n=e.sample(t.add(Ii(0,-.01,0))).r.sub(e.sample(t.add(Ii(0,r,0))).r),o=e.sample(t.add(Ii(0,0,-.01))).r.sub(e.sample(t.add(Ii(0,0,r))).r);s.assign(Ii(i,n,o))})),s.normalize()}));class vg extends bu{static get type(){return"Texture3DNode"}constructor(e,t=null,r=null){super(e,t,r),this.isTexture3DNode=!0}getInputType(){return"texture3D"}getDefaultUV(){return Ii(.5,.5,.5)}setUpdateMatrix(){}setupUV(e,t){return t}generateUV(e,t){return t.build(e,"vec3")}normal(e){return _g({texture:this,uv:e})}}const Ng=xi(vg);class Sg extends Yc{static get type(){return"VolumeNodeMaterial"}constructor(e={}){super(),this.lights=!1,this.isVolumeNodeMaterial=!0,this.testNode=null,this.setValues(e)}setup(e){const t=Ng(this.map,null,0),r=_i((({orig:e,dir:t})=>{const r=Ii(-.5),s=Ii(.5),i=t.reciprocal(),n=r.sub(e).mul(i),o=s.sub(e).mul(i),a=Ko(n,o),u=Xo(n,o),l=Xo(a.x,Xo(a.y,a.z)),d=Ko(u.x,Ko(u.y,u.z));return Bi(l,d)}));this.fragmentNode=_i((()=>{const e=wa(Ii(zu.mul(Oi(Eu,1)))),s=wa(ju.sub(e)).normalize(),i=Bi(r({orig:e,dir:s})).toVar();i.x.greaterThan(i.y).discard(),i.assign(Bi(Xo(i.x,0),i.y));const n=Ii(e.add(i.x.mul(s))).toVar(),o=Ii(s.abs().reciprocal()).toVar(),a=Ci(Ko(o.x,Ko(o.y,o.z))).toVar("delta");a.divAssign(wl("steps","float"));const u=Oi(wl("base","color"),0).toVar();return ic({type:"float",start:i.x,end:i.y,update:"+= delta"},(()=>{const e=sn("float","d").assign(t.sample(n.add(.5)).r);null!==this.testNode?this.testNode({map:t,mapValue:e,probe:n,finalColor:u}).append():(u.a.assign(1),nc()),n.addAssign(s.mul(a))})),u.a.equal(0).discard(),Oi(u)}))(),super.setup(e)}}class Ag{constructor(e,t){this.nodes=e,this.info=t,this._context=self,this._animationLoop=null,this._requestId=null}start(){const e=(t,r)=>{this._requestId=this._context.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,r)};e()}stop(){this._context.cancelAnimationFrame(this._requestId),this._requestId=null}setAnimationLoop(e){this._animationLoop=e}setContext(e){this._context=e}dispose(){this.stop()}}class Rg{constructor(){this.weakMap=new WeakMap}get(e){let t=this.weakMap;for(let r=0;r{this.dispose()},this.material.addEventListener("dispose",this.onMaterialDispose)}updateClipping(e){this.clippingContext=e}get clippingNeedsUpdate(){return null!==this.clippingContext&&this.clippingContext.cacheKey!==this.clippingContextCacheKey&&(this.clippingContextCacheKey=this.clippingContext.cacheKey,!0)}get hardwareClippingPlanes(){return!0===this.material.hardwareClipping?this.clippingContext.unionClippingCount: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)}getIndirect(){return this._geometries.getIndirect(this)}getChainArray(){return[this.object,this.material,this.context,this.lightsNode]}setGeometry(e){this.geometry=e,this.attributes=null}getAttributes(){if(null!==this.attributes)return this.attributes;const e=this.getNodeBuilderState().nodeAttributes,t=this.geometry,r=[],s=new Set;for(const i of e){const e=i.node&&i.node.attribute?i.node.attribute:t.getAttribute(i.name);if(void 0===e)continue;r.push(e);const n=e.isInterleavedBufferAttribute?e.data:e;s.add(n)}return this.attributes=r,this.vertexBuffers=Array.from(s.values()),r}getVertexBuffers(){return null===this.vertexBuffers&&this.getAttributes(),this.vertexBuffers}getDrawParameters(){const{object:e,material:t,geometry:r,group:s,drawRange:i}=this,n=this.drawParams||(this.drawParams={vertexCount:0,firstVertex:0,instanceCount:0,firstInstance:0}),o=this.getIndex(),a=null!==o,u=r.isInstancedBufferGeometry?r.instanceCount:e.count>1?e.count:1;if(0===u)return null;if(n.instanceCount=u,!0===e.isBatchedMesh)return n;let l=1;!0!==t.wireframe||e.isPoints||e.isLineSegments||e.isLine||e.isLineLoop||(l=2);let d=i.start*l,c=(i.start+i.count)*l;null!==s&&(d=Math.max(d,s.start*l),c=Math.min(c,(s.start+s.count)*l));const h=r.attributes.position;let p=1/0;a?p=o.count:null!=h&&(p=h.count),d=Math.max(d,0),c=Math.min(c,p);const g=c-d;return g<0||g===1/0?null:(n.vertexCount=g,n.firstVertex=d,n)}getGeometryCacheKey(){const{geometry:e}=this;let t="";for(const r of Object.keys(e.attributes).sort()){const s=e.attributes[r];t+=r+",",s.data&&(t+=s.data.stride+","),s.offset&&(t+=s.offset+","),s.itemSize&&(t+=s.itemSize+","),s.normalized&&(t+="n,")}return e.index&&(t+="index,"),t}getMaterialCacheKey(){const{object:e,material:t}=this;let r=t.customProgramCacheKey();for(const e of function(e){const t=Object.keys(e);let r=Object.getPrototypeOf(e);for(;r;){const e=Object.getOwnPropertyDescriptors(r);for(const r in e)if(void 0!==e[r]){const s=e[r];s&&"function"==typeof s.get&&t.push(r)}r=Object.getPrototypeOf(r)}return t}(t)){if(/^(is[A-Z]|_)|^(visible|version|uuid|name|opacity|userData)$/.test(e))continue;const s=t[e];let i;if(null!==s){const e=typeof s;"number"===e?i=0!==s?"1":"0":"object"===e?(i="{",s.isTexture&&(i+=s.mapping),i+="}"):i=String(s)}else i=String(s);r+=i+","}return r+=this.clippingContextCacheKey+",",e.geometry&&(r+=this.getGeometryCacheKey()),e.skeleton&&(r+=e.skeleton.bones.length+","),e.morphTargetInfluences&&(r+=e.morphTargetInfluences.length+","),e.isBatchedMesh&&(r+=e._matricesTexture.uuid+",",null!==e._colorsTexture&&(r+=e._colorsTexture.uuid+",")),e.count>1&&(r+=e.uuid+","),r+=e.receiveShadow+",",us(r)}get needsGeometryUpdate(){return this.geometry.id!==this.object.geometry.id}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 wg=[];class Mg{constructor(e,t,r,s,i,n){this.renderer=e,this.nodes=t,this.geometries=r,this.pipelines=s,this.bindings=i,this.info=n,this.chainMaps={}}get(e,t,r,s,i,n,o,a){const u=this.getChainMap(a);wg[0]=e,wg[1]=t,wg[2]=n,wg[3]=i;let l=u.get(wg);return void 0===l?(l=this.createRenderObject(this.nodes,this.geometries,this.renderer,e,t,r,s,i,n,o,a),u.set(wg,l)):(l.updateClipping(o),l.needsGeometryUpdate&&l.setGeometry(e.geometry),(l.version!==t.version||l.needsUpdate)&&(l.initialCacheKey!==l.getCacheKey()?(l.dispose(),l=this.get(e,t,r,s,i,n,o,a)):l.version=t.version)),l}getChainMap(e="default"){return this.chainMaps[e]||(this.chainMaps[e]=new Rg)}dispose(){this.chainMaps={}}createRenderObject(e,t,r,s,i,n,o,a,u,l,d){const c=this.getChainMap(d),h=new Eg(e,t,r,s,i,n,o,a,u,l);return h.onDispose=()=>{this.pipelines.delete(h),this.bindings.delete(h),this.nodes.delete(h),c.delete(h.getChainArray())},h}}class Bg{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 Ug=1,Fg=2,Pg=3,Ig=4,Lg=16;class Dg extends Bg{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 r=this.get(e);if(void 0===r.version)t===Ug?this.backend.createAttribute(e):t===Fg?this.backend.createIndexAttribute(e):t===Pg?this.backend.createStorageAttribute(e):t===Ig&&this.backend.createIndirectStorageAttribute(e),r.version=this._getBufferAttribute(e).version;else{const t=this._getBufferAttribute(e);(r.version=0;--t)if(e[t]>=65535)return!0;return!1}(t)?ae:ue)(t,1);return i.version=Vg(e),i}class Gg extends Bg{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 r=()=>{this.info.memory.geometries--;const s=t.index,i=e.getAttributes();null!==s&&this.attributes.delete(s);for(const e of i)this.attributes.delete(e);const n=this.wireframes.get(t);void 0!==n&&this.attributes.delete(n),t.removeEventListener("dispose",r)};t.addEventListener("dispose",r)}updateAttributes(e){const t=e.getAttributes();for(const e of t)e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute?this.updateAttribute(e,Pg):this.updateAttribute(e,Ug);const r=this.getIndex(e);null!==r&&this.updateAttribute(r,Fg);const s=e.geometry.indirect;null!==s&&this.updateAttribute(s,Ig)}updateAttribute(e,t){const r=this.info.render.calls;e.isInterleavedBufferAttribute?void 0===this.attributeCall.get(e)?(this.attributes.update(e,t),this.attributeCall.set(e,r)):this.attributeCall.get(e.data)!==r&&(this.attributes.update(e,t),this.attributeCall.set(e.data,r),this.attributeCall.set(e,r)):this.attributeCall.get(e)!==r&&(this.attributes.update(e,t),this.attributeCall.set(e,r))}getIndirect(e){return e.geometry.indirect}getIndex(e){const{geometry:t,material:r}=e;let s=t.index;if(!0===r.wireframe){const e=this.wireframes;let r=e.get(t);void 0===r?(r=Og(t),e.set(t,r)):r.version!==Vg(t)&&(this.attributes.delete(r),r=Og(t),e.set(t,r)),s=r}return s}}class kg{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,r){this.render.drawCalls++,e.isMesh||e.isSprite?this.render.triangles+=r*(t/3):e.isPoints?this.render.points+=r*t:e.isLineSegments?this.render.lines+=r*(t/2):e.isLine?this.render.lines+=r*(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 zg{constructor(e){this.cacheKey=e,this.usedTimes=0}}class $g extends zg{constructor(e,t,r){super(e),this.vertexProgram=t,this.fragmentProgram=r}}class Hg extends zg{constructor(e,t){super(e),this.computeProgram=t,this.isComputePipeline=!0}}let Wg=0;class jg{constructor(e,t,r=null,s=null){this.id=Wg++,this.code=e,this.stage=t,this.transforms=r,this.attributes=s,this.usedTimes=0}}class qg extends Bg{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:r}=this,s=this.get(e);if(this._needsComputeUpdate(e)){const i=s.pipeline;i&&(i.usedTimes--,i.computeProgram.usedTimes--);const n=this.nodes.getForCompute(e);let o=this.programs.compute.get(n.computeShader);void 0===o&&(i&&0===i.computeProgram.usedTimes&&this._releaseProgram(i.computeProgram),o=new jg(n.computeShader,"compute",n.transforms,n.nodeAttributes),this.programs.compute.set(n.computeShader,o),r.createProgram(o));const a=this._getComputeCacheKey(e,o);let u=this.caches.get(a);void 0===u&&(i&&0===i.usedTimes&&this._releasePipeline(i),u=this._getComputePipeline(e,o,a,t)),u.usedTimes++,o.usedTimes++,s.version=e.version,s.pipeline=u}return s.pipeline}getForRender(e,t=null){const{backend:r}=this,s=this.get(e);if(this._needsRenderUpdate(e)){const i=s.pipeline;i&&(i.usedTimes--,i.vertexProgram.usedTimes--,i.fragmentProgram.usedTimes--);const n=e.getNodeBuilderState();let o=this.programs.vertex.get(n.vertexShader);void 0===o&&(i&&0===i.vertexProgram.usedTimes&&this._releaseProgram(i.vertexProgram),o=new jg(n.vertexShader,"vertex"),this.programs.vertex.set(n.vertexShader,o),r.createProgram(o));let a=this.programs.fragment.get(n.fragmentShader);void 0===a&&(i&&0===i.fragmentProgram.usedTimes&&this._releaseProgram(i.fragmentProgram),a=new jg(n.fragmentShader,"fragment"),this.programs.fragment.set(n.fragmentShader,a),r.createProgram(a));const u=this._getRenderCacheKey(e,o,a);let l=this.caches.get(u);void 0===l?(i&&0===i.usedTimes&&this._releasePipeline(i),l=this._getRenderPipeline(e,o,a,u,t)):e.pipeline=l,l.usedTimes++,o.usedTimes++,a.usedTimes++,s.pipeline=l}return s.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,r,s){r=r||this._getComputeCacheKey(e,t);let i=this.caches.get(r);return void 0===i&&(i=new Hg(r,t),this.caches.set(r,i),this.backend.createComputePipeline(i,s)),i}_getRenderPipeline(e,t,r,s,i){s=s||this._getRenderCacheKey(e,t,r);let n=this.caches.get(s);return void 0===n&&(n=new $g(s,t,r),this.caches.set(s,n),e.pipeline=n,this.backend.createRenderPipeline(e,i)),n}_getComputeCacheKey(e,t){return e.id+","+t.id}_getRenderCacheKey(e,t,r){return t.id+","+r.id+","+this.backend.getRenderCacheKey(e)}_releasePipeline(e){this.caches.delete(e.cacheKey)}_releaseProgram(e){const t=e.code,r=e.stage;this.programs[r].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 Kg extends Bg{constructor(e,t,r,s,i,n){super(),this.backend=e,this.textures=r,this.pipelines=i,this.attributes=s,this.nodes=t,this.info=n,this.pipelines.bindings=this}getForRender(e){const t=e.getBindings();for(const e of t){const r=this.get(e);void 0===r.bindGroup&&(this._init(e),this.backend.createBindings(e,t,0),r.bindGroup=e)}return t}getForCompute(e){const t=this.nodes.getForCompute(e).bindings;for(const e of t){const r=this.get(e);void 0===r.bindGroup&&(this._init(e),this.backend.createBindings(e,t,0),r.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,r=e.isIndirectStorageBufferAttribute?Ig:Pg;this.attributes.update(e,r)}}_update(e,t){const{backend:r}=this;let s=!1,i=!0,n=0,o=0;for(const t of e.bindings){if(t.isNodeUniformsGroup){if(!this.nodes.updateGroup(t))continue}if(t.isUniformBuffer){t.update()&&r.updateBinding(t)}else if(t.isSampler)t.update();else if(t.isSampledTexture){const e=this.textures.get(t.texture);t.needsBindingsUpdate(e.generation)&&(s=!0);const a=t.update(),u=t.texture;a&&this.textures.updateTexture(u);const l=r.get(u);if(void 0!==l.externalTexture||e.isDefaultTexture?i=!1:(n=10*n+u.id,o+=u.version),!0===r.isWebGPUBackend&&void 0===l.texture&&void 0===l.externalTexture&&(console.error("Bindings._update: binding should be available:",t,a,u,t.textureNode.value,s),this.textures.updateTexture(u),s=!0),!0===u.isStorageTexture){const e=this.get(u);!0===t.store?e.needsMipmap=!0:this.textures.needsMipmaps(u)&&!0===e.needsMipmap&&(this.backend.generateMipmaps(u),e.needsMipmap=!1)}}}!0===s&&this.backend.updateBindings(e,t,i?n:0,o)}}function Xg(e,t){return e.groupOrder!==t.groupOrder?e.groupOrder-t.groupOrder:e.renderOrder!==t.renderOrder?e.renderOrder-t.renderOrder:e.material.id!==t.material.id?e.material.id-t.material.id:e.z!==t.z?e.z-t.z:e.id-t.id}function Yg(e,t){return e.groupOrder!==t.groupOrder?e.groupOrder-t.groupOrder:e.renderOrder!==t.renderOrder?e.renderOrder-t.renderOrder:e.z!==t.z?t.z-e.z:e.id-t.id}function Qg(e){return(e.transmission>0||e.transmissionNode)&&e.side===le&&!1===e.forceSinglePass}class Zg{constructor(e,t,r){this.renderItems=[],this.renderItemsIndex=0,this.opaque=[],this.transparentDoublePass=[],this.transparent=[],this.bundles=[],this.lightsNode=e.getNode(t,r),this.lightsArray=[],this.scene=t,this.camera=r,this.occlusionQueryCount=0}begin(){return this.renderItemsIndex=0,this.opaque.length=0,this.transparentDoublePass.length=0,this.transparent.length=0,this.bundles.length=0,this.lightsArray.length=0,this.occlusionQueryCount=0,this}getNextRenderItem(e,t,r,s,i,n,o){let a=this.renderItems[this.renderItemsIndex];return void 0===a?(a={id:e.id,object:e,geometry:t,material:r,groupOrder:s,renderOrder:e.renderOrder,z:i,group:n,clippingContext:o},this.renderItems[this.renderItemsIndex]=a):(a.id=e.id,a.object=e,a.geometry=t,a.material=r,a.groupOrder=s,a.renderOrder=e.renderOrder,a.z=i,a.group=n,a.clippingContext=o),this.renderItemsIndex++,a}push(e,t,r,s,i,n,o){const a=this.getNextRenderItem(e,t,r,s,i,n,o);!0===e.occlusionTest&&this.occlusionQueryCount++,!0===r.transparent||r.transmission>0?(Qg(r)&&this.transparentDoublePass.push(a),this.transparent.push(a)):this.opaque.push(a)}unshift(e,t,r,s,i,n,o){const a=this.getNextRenderItem(e,t,r,s,i,n,o);!0===r.transparent||r.transmission>0?(Qg(r)&&this.transparentDoublePass.unshift(a),this.transparent.unshift(a)):this.opaque.unshift(a)}pushBundle(e){this.bundles.push(e)}pushLight(e){this.lightsArray.push(e)}sort(e,t){this.opaque.length>1&&this.opaque.sort(e||Xg),this.transparentDoublePass.length>1&&this.transparentDoublePass.sort(t||Yg),this.transparent.length>1&&this.transparent.sort(t||Yg)}finish(){this.lightsNode.setLights(this.lightsArray);for(let e=this.renderItemsIndex,t=this.renderItems.length;e>t,u=o.height>>t;let l=e.depthTexture||i[t];const d=!0===e.depthBuffer||!0===e.stencilBuffer;let c=!1;void 0===l&&d&&(l=new B,l.format=e.stencilBuffer?de:ce,l.type=e.stencilBuffer?he:f,l.image.width=a,l.image.height=u,i[t]=l),r.width===o.width&&o.height===r.height||(c=!0,l&&(l.needsUpdate=!0,l.image.width=a,l.image.height=u)),r.width=o.width,r.height=o.height,r.textures=n,r.depthTexture=l||null,r.depth=e.depthBuffer,r.stencil=e.stencilBuffer,r.renderTarget=e,r.sampleCount!==s&&(c=!0,l&&(l.needsUpdate=!0),r.sampleCount=s);const h={sampleCount:s};for(let e=0;e{e.removeEventListener("dispose",t);for(let e=0;e0){const s=e.image;if(void 0===s)console.warn("THREE.Renderer: Texture marked for update but image is undefined.");else if(!1===s.complete)console.warn("THREE.Renderer: Texture marked for update but image is incomplete.");else{if(e.images){const r=[];for(const t of e.images)r.push(t);t.images=r}else t.image=s;void 0!==r.isDefaultTexture&&!0!==r.isDefaultTexture||(i.createTexture(e,t),r.isDefaultTexture=!1,r.generation=e.version),!0===e.source.dataReady&&i.updateTexture(e,t),t.needsMipmaps&&0===e.mipmaps.length&&i.generateMipmaps(e)}}else i.createDefaultTexture(e),r.isDefaultTexture=!0,r.generation=e.version}if(!0!==r.initialized){r.initialized=!0,r.generation=e.version,this.info.memory.textures++;const t=()=>{e.removeEventListener("dispose",t),this._destroyTexture(e),this.info.memory.textures--};e.addEventListener("dispose",t)}r.version=e.version}getSize(e,t=im){let r=e.images?e.images[0]:e.image;return r?(void 0!==r.image&&(r=r.image),t.width=r.width||1,t.height=r.height||1,t.depth=e.isCubeTexture?6:r.depth||1):t.width=t.height=t.depth=1,t}getMipLevels(e,t,r){let s;return s=e.isCompressedTexture?e.mipmaps?e.mipmaps.length:1:Math.floor(Math.log2(Math.max(t,r)))+1,s}needsMipmaps(e){return this.isEnvironmentTexture(e)||!0===e.isCompressedTexture||e.generateMipmaps}isEnvironmentTexture(e){const t=e.mapping;return t===j||t===q||t===T||t===_}_destroyTexture(e){this.backend.destroySampler(e),this.backend.destroyTexture(e),this.delete(e)}}class om extends e{constructor(e,t,r,s=1){super(e,t,r),this.a=s}set(e,t,r,s=1){return this.a=s,super.set(e,t,r)}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)}}class am extends rn{static get type(){return"ParameterNode"}constructor(e,t=null){super(e,t),this.isParameterNode=!0}getHash(){return this.uuid}generate(){return this.name}}class um extends Ms{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 r=new mi(t);return this._currentCond=Ta(e,r),this.add(this._currentCond)}ElseIf(e,t){const r=new mi(t),s=Ta(e,r);return this._currentCond.elseNode=s,this._currentCond=s,this}Else(e){return this._currentCond.elseNode=new mi(e),this}build(e,...t){const r=Ni();vi(this);for(const t of this.nodes)t.build(e,"void");return vi(r),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 lm=xi(um);class dm extends Ms{static get type(){return"OutputStructNode"}constructor(...e){super(),this.members=e,this.isOutputStructNode=!0}setup(e){super.setup(e);const t=this.members,r=[];for(let s=0;s{const t=e.toUint().mul(747796405).add(2891336453),r=t.shiftRight(t.shiftRight(28).add(4)).bitXor(t).mul(277803737);return r.shiftRight(22).bitXor(r).toFloat().mul(1/2**32)})),fm=(e,t)=>sa(kn(4,e.mul(Gn(1,e))),t),ym=_i((([e])=>e.fract().sub(.5).abs())).setLayout({name:"tri",type:"float",inputs:[{name:"x",type:"float"}]}),bm=_i((([e])=>Ii(ym(e.z.add(ym(e.y.mul(1)))),ym(e.z.add(ym(e.x.mul(1)))),ym(e.y.add(ym(e.x.mul(1))))))).setLayout({name:"tri3",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),xm=_i((([e,t,r])=>{const s=Ii(e).toVar(),i=Ci(1.4).toVar(),n=Ci(0).toVar(),o=Ii(s).toVar();return ic({start:Ci(0),end:Ci(3),type:"float",condition:"<="},(()=>{const e=Ii(bm(o.mul(2))).toVar();s.addAssign(e.add(r.mul(Ci(.1).mul(t)))),o.mulAssign(1.8),i.mulAssign(1.5),s.mulAssign(1.2);const a=Ci(ym(s.z.add(ym(s.x.add(ym(s.y)))))).toVar();n.addAssign(a.div(i)),o.addAssign(.14)})),n})).setLayout({name:"triNoise3D",type:"float",inputs:[{name:"position",type:"vec3"},{name:"speed",type:"float"},{name:"time",type:"float"}]});class Tm extends Ms{static get type(){return"FunctionOverloadingNode"}constructor(e=[],...t){super(),this.functionNodes=e,this.parametersNodes=t,this._candidateFnCall=null,this.global=!0}getNodeType(){return this.functionNodes[0].shaderNode.layout.type}setup(e){const t=this.parametersNodes;let r=this._candidateFnCall;if(null===r){let s=null,i=-1;for(const r of this.functionNodes){const n=r.shaderNode.layout;if(null===n)throw new Error("FunctionOverloadingNode: FunctionNode must be a layout.");const o=n.inputs;if(t.length===o.length){let n=0;for(let r=0;ri&&(s=r,i=n)}}this._candidateFnCall=r=s(...t)}return r}}const _m=xi(Tm),vm=e=>(...t)=>_m(e,...t),Nm=tn(0).setGroup(Zi).onRenderUpdate((e=>e.time)),Sm=tn(0).setGroup(Zi).onRenderUpdate((e=>e.deltaTime)),Am=tn(0,"uint").setGroup(Zi).onRenderUpdate((e=>e.frameId)),Rm=_i((([e,t,r=Bi(.5)])=>mg(e.sub(r),t).add(r))),Cm=_i((([e,t,r=Bi(.5)])=>{const s=e.sub(r),i=s.dot(s),n=i.mul(i).mul(t);return e.add(s.mul(n))})),Em=_i((({position:e=null,horizontal:t=!0,vertical:r=!1})=>{let s;null!==e?(s=Du.toVar(),s[3][0]=e.x,s[3][1]=e.y,s[3][2]=e.z):s=Du;const i=Au.mul(s);return pi(t)&&(i[0][0]=Du[0].length(),i[0][1]=0,i[0][2]=0),pi(r)&&(i[1][0]=0,i[1][1]=Du[1].length(),i[1][2]=0),i[2][0]=0,i[2][1]=0,i[2][2]=1,Nu.mul(i).mul(qu)})),wm=_i((([e=null])=>{const t=$c();return $c(Ic(e)).sub(t).lessThan(0).select(xc,e)}));class Mm extends Ms{static get type(){return"SpriteSheetUVNode"}constructor(e,t=pu(),r=Ci(0)){super("vec2"),this.countNode=e,this.uvNode=t,this.frameNode=r}setup(){const{frameNode:e,uvNode:t,countNode:r}=this,{width:s,height:i}=r,n=e.mod(s.mul(i)).floor(),o=n.mod(s),a=i.sub(n.add(1).div(s).ceil()),u=r.reciprocal(),l=Bi(o,a);return t.add(l).mul(u)}}const Bm=xi(Mm);class Um extends Ms{static get type(){return"TriplanarTexturesNode"}constructor(e,t=null,r=null,s=Ci(1),i=qu,n=sl){super("vec4"),this.textureXNode=e,this.textureYNode=t,this.textureZNode=r,this.scaleNode=s,this.positionNode=i,this.normalNode=n}setup(){const{textureXNode:e,textureYNode:t,textureZNode:r,scaleNode:s,positionNode:i,normalNode:n}=this;let o=n.abs().normalize();o=o.div(o.dot(Ii(1)));const a=i.yz.mul(s),u=i.zx.mul(s),l=i.xy.mul(s),d=e.value,c=null!==t?t.value:d,h=null!==r?r.value:d,p=xu(d,a).mul(o.x),g=xu(c,u).mul(o.y),m=xu(h,l).mul(o.z);return On(p,g,m)}}const Fm=xi(Um),Pm=new me,Im=new r,Lm=new r,Dm=new r,Vm=new n,Om=new r(0,0,-1),Gm=new s,km=new r,zm=new r,$m=new s,Hm=new t,Wm=new ge,jm=xc.flipX();Wm.depthTexture=new B(1,1);let qm=!1;class Km extends bu{static get type(){return"ReflectorNode"}constructor(e={}){super(e.defaultTexture||Wm.texture,jm),this._reflectorBaseNode=e.reflector||new Xm(this,e),this._depthNode=null,this.setUpdateMatrix(!1)}get reflector(){return this._reflectorBaseNode}get target(){return this._reflectorBaseNode.target}getDepthNode(){if(null===this._depthNode){if(!0!==this._reflectorBaseNode.depth)throw new Error("THREE.ReflectorNode: Depth node can only be requested when the reflector is created with { depth: true }. ");this._depthNode=fi(new Km({defaultTexture:Wm.depthTexture,reflector:this._reflectorBaseNode}))}return this._depthNode}setup(e){return e.object.isQuadMesh||this._reflectorBaseNode.build(e),super.setup(e)}clone(){const e=new this.constructor(this.reflectorNode);return e._reflectorBaseNode=this._reflectorBaseNode,e}}class Xm extends Ms{static get type(){return"ReflectorBaseNode"}constructor(e,t={}){super();const{target:r=new fe,resolution:s=1,generateMipmaps:i=!1,bounces:n=!0,depth:o=!1}=t;this.textureNode=e,this.target=r,this.resolution=s,this.generateMipmaps=i,this.bounces=n,this.depth=o,this.updateBeforeType=n?vs.RENDER:vs.FRAME,this.virtualCameras=new WeakMap,this.renderTargets=new WeakMap}_updateResolution(e,t){const r=this.resolution;t.getDrawingBufferSize(Hm),e.setSize(Math.round(Hm.width*r),Math.round(Hm.height*r))}setup(e){return this._updateResolution(Wm,e.renderer),super.setup(e)}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 ge(0,0,{type:ye}),!0===this.generateMipmaps&&(t.texture.minFilter=be,t.texture.generateMipmaps=!0),!0===this.depth&&(t.depthTexture=new B),this.renderTargets.set(e,t)),t}updateBefore(e){if(!1===this.bounces&&qm)return;qm=!0;const{scene:t,camera:r,renderer:s,material:i}=e,{target:n}=this,o=this.getVirtualCamera(r),a=this.getRenderTarget(o);if(s.getDrawingBufferSize(Hm),this._updateResolution(a,s),Lm.setFromMatrixPosition(n.matrixWorld),Dm.setFromMatrixPosition(r.matrixWorld),Vm.extractRotation(n.matrixWorld),Im.set(0,0,1),Im.applyMatrix4(Vm),km.subVectors(Lm,Dm),km.dot(Im)>0)return;km.reflect(Im).negate(),km.add(Lm),Vm.extractRotation(r.matrixWorld),Om.set(0,0,-1),Om.applyMatrix4(Vm),Om.add(Dm),zm.subVectors(Lm,Om),zm.reflect(Im).negate(),zm.add(Lm),o.coordinateSystem=r.coordinateSystem,o.position.copy(km),o.up.set(0,1,0),o.up.applyMatrix4(Vm),o.up.reflect(Im),o.lookAt(zm),o.near=r.near,o.far=r.far,o.updateMatrixWorld(),o.projectionMatrix.copy(r.projectionMatrix),Pm.setFromNormalAndCoplanarPoint(Im,Lm),Pm.applyMatrix4(o.matrixWorldInverse),Gm.set(Pm.normal.x,Pm.normal.y,Pm.normal.z,Pm.constant);const u=o.projectionMatrix;$m.x=(Math.sign(Gm.x)+u.elements[8])/u.elements[0],$m.y=(Math.sign(Gm.y)+u.elements[9])/u.elements[5],$m.z=-1,$m.w=(1+u.elements[10])/u.elements[14],Gm.multiplyScalar(1/Gm.dot($m));u.elements[2]=Gm.x,u.elements[6]=Gm.y,u.elements[10]=s.coordinateSystem===v?Gm.z-0:Gm.z+1-0,u.elements[14]=Gm.w,this.textureNode.value=a.texture,!0===this.depth&&(this.textureNode.getDepthNode().value=a.depthTexture),i.visible=!1;const l=s.getRenderTarget(),d=s.getMRT();s.setMRT(null),s.setRenderTarget(a),s.render(t,o),s.setMRT(d),s.setRenderTarget(l),i.visible=!0,qm=!1}}const Ym=new xe(-1,1,1,-1,0,1);class Qm extends Te{constructor(e=!1){super();const t=!1===e?[0,-1,0,1,2,1]:[0,2,0,0,2,0];this.setAttribute("position",new _e([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new _e(t,2))}}const Zm=new Qm;class Jm extends k{constructor(e=null){super(Zm,e),this.camera=Ym,this.isQuadMesh=!0}renderAsync(e){return e.renderAsync(this,Ym)}render(e){e.render(this,Ym)}}const ef=new t;class tf extends bu{static get type(){return"RTTNode"}constructor(e,t=null,r=null,s={type:ye}){const i=new ge(t,r,s);super(i.texture,pu()),this.node=e,this.width=t,this.height=r,this.pixelRatio=1,this.renderTarget=i,this.textureNeedsUpdate=!0,this.autoUpdate=!0,this._rttNode=null,this._quadMesh=new Jm(new Yc),this.updateBeforeType=vs.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 r=e*this.pixelRatio,s=t*this.pixelRatio;this.renderTarget.setSize(r,s),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(ef);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 bu(this.value,this.uvNode,this.levelNode);return e.sampler=this.sampler,e.referenceNode=this,e}}const rf=(e,...t)=>fi(new tf(fi(e),...t)),sf=_i((([e,t,r],s)=>{let i;s.renderer.coordinateSystem===v?(e=Bi(e.x,e.y.oneMinus()).mul(2).sub(1),i=Oi(Ii(e,t),1)):i=Oi(Ii(e.x,e.y.oneMinus(),t).mul(2).sub(1),1);const n=Oi(r.mul(i));return n.xyz.div(n.w)})),nf=_i((([e,t])=>{const r=t.mul(Oi(e,1)),s=r.xy.div(r.w).mul(.5).add(.5).toVar();return Bi(s.x,s.y.oneMinus())})),of=_i((([e,t,r])=>{const s=mu(Tu(t)),i=Ui(e.mul(s)).toVar(),n=Tu(t,i).toVar(),o=Tu(t,i.sub(Ui(2,0))).toVar(),a=Tu(t,i.sub(Ui(1,0))).toVar(),u=Tu(t,i.add(Ui(1,0))).toVar(),l=Tu(t,i.add(Ui(2,0))).toVar(),d=Tu(t,i.add(Ui(0,2))).toVar(),c=Tu(t,i.add(Ui(0,1))).toVar(),h=Tu(t,i.sub(Ui(0,1))).toVar(),p=Tu(t,i.sub(Ui(0,2))).toVar(),g=Po(Gn(Ci(2).mul(a).sub(o),n)).toVar(),m=Po(Gn(Ci(2).mul(u).sub(l),n)).toVar(),f=Po(Gn(Ci(2).mul(c).sub(d),n)).toVar(),y=Po(Gn(Ci(2).mul(h).sub(p),n)).toVar(),b=sf(e,n,r).toVar(),x=g.lessThan(m).select(b.sub(sf(e.sub(Bi(Ci(1).div(s.x),0)),a,r)),b.negate().add(sf(e.add(Bi(Ci(1).div(s.x),0)),u,r))),T=f.lessThan(y).select(b.sub(sf(e.add(Bi(0,Ci(1).div(s.y))),c,r)),b.negate().add(sf(e.sub(Bi(0,Ci(1).div(s.y))),h,r)));return Ro(ra(x,T))}));class af extends R{constructor(e,t,r=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new r(e*t)),super(e,t),this.isStorageInstancedBufferAttribute=!0}}class uf extends ve{constructor(e,t,r=Float32Array){!1===ArrayBuffer.isView(e)&&(e=new r(e*t)),super(e,t),this.isStorageBufferAttribute=!0}}class lf extends Bs{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.isPBO&&e.setupPBO(this.node),super.setup(e)}generate(e,t){let r;const s=e.context.assign;if(r=!1===e.isAvailable("storageBuffer")?!0!==this.node.isPBO||!0===s||!this.node.value.isInstancedBufferAttribute&&"compute"===e.shaderStage?this.node.build(e):e.generatePBO(this):super.generate(e),!0!==s){const s=this.getNodeType(e);r=e.format(r,s,t)}return r}}const df=xi(lf);class cf extends xl{static get type(){return"StorageBufferNode"}constructor(e,t=null,r=0){null===t&&(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute)&&(t=gs(e.itemSize),r=e.count),super(e,t,r),this.isStorageBufferNode=!0,this.access=Ss.READ_WRITE,this.isAtomic=!1,this.isPBO=!1,this.bufferCount=r,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 this.value.isIndirectStorageBufferAttribute?"indirectStorageBuffer":"storageBuffer"}element(e){return df(this,e)}setPBO(e){return this.isPBO=e,this}getPBO(){return this.isPBO}setAccess(e){return this.access=e,this}toReadOnly(){return this.setAccess(Ss.READ_ONLY)}setAtomic(e){return this.isAtomic=e,this}toAtomic(){return this.setAtomic(!0)}getAttributeData(){return null===this._attribute&&(this._attribute=qa(this.value),this._varying=wa(this._attribute)),{attribute:this._attribute,varying:this._varying}}getNodeType(e){if(e.isAvailable("storageBuffer")||e.isAvailable("indirectStorageBuffer"))return super.getNodeType(e);const{attribute:t}=this.getAttributeData();return t.getNodeType(e)}generate(e){if(e.isAvailable("storageBuffer")||e.isAvailable("indirectStorageBuffer"))return super.generate(e);const{attribute:t,varying:r}=this.getAttributeData(),s=r.build(e);return e.registerTransform(s,t),s}}const hf=(e,t,r)=>fi(new cf(e,t,r));class pf extends cu{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 r;return r=!0===e.hasGeometryAttribute(t)?super.generate(e):e.generateConst(this.nodeType,new s(1,1,1,1)),r}serialize(e){super.serialize(e),e.index=this.index}deserialize(e){super.deserialize(e),this.index=e.index}}class gf extends Ms{static get type(){return"PointUVNode"}constructor(){super("vec2"),this.isPointUVNode=!0}generate(){return"vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )"}}const mf=Ti(gf),ff=new Se,yf=new n;class bf extends Ms{static get type(){return"SceneNode"}constructor(e=bf.BACKGROUND_BLURRINESS,t=null){super(),this.scope=e,this.scene=t}setup(e){const t=this.scope,r=null!==this.scene?this.scene:e.scene;let s;return t===bf.BACKGROUND_BLURRINESS?s=Rl("backgroundBlurriness","float",r):t===bf.BACKGROUND_INTENSITY?s=Rl("backgroundIntensity","float",r):t===bf.BACKGROUND_ROTATION?s=tn("mat4").label("backgroundRotation").setGroup(Zi).onRenderUpdate((()=>{const e=r.background;return null!==e&&e.isTexture&&e.mapping!==Ne?(ff.copy(r.backgroundRotation),ff.x*=-1,ff.y*=-1,ff.z*=-1,yf.makeRotationFromEuler(ff)):yf.identity(),yf})):console.error("THREE.SceneNode: Unknown scope:",t),s}}bf.BACKGROUND_BLURRINESS="backgroundBlurriness",bf.BACKGROUND_INTENSITY="backgroundIntensity",bf.BACKGROUND_ROTATION="backgroundRotation";const xf=Ti(bf,bf.BACKGROUND_BLURRINESS),Tf=Ti(bf,bf.BACKGROUND_INTENSITY),_f=Ti(bf,bf.BACKGROUND_ROTATION);class vf extends bu{static get type(){return"StorageTextureNode"}constructor(e,t,r=null){super(e,t),this.storeNode=r,this.isStorageTextureNode=!0,this.access=Ss.WRITE_ONLY}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 r;return r=null!==this.storeNode?this.generateStore(e):super.generate(e,t),r}toReadWrite(){return this.setAccess(Ss.READ_WRITE)}toReadOnly(){return this.setAccess(Ss.READ_ONLY)}toWriteOnly(){return this.setAccess(Ss.WRITE_ONLY)}generateStore(e){const t=e.getNodeProperties(this),{uvNode:r,storeNode:s}=t,i=super.generate(e,"property"),n=r.build(e,"uvec2"),o=s.build(e,"vec4"),a=e.generateTextureStore(e,i,n,o);e.addLineFlowCode(a,this)}}const Nf=xi(vf);class Sf extends Al{static get type(){return"UserDataNode"}constructor(e,t,r=null){super(e,t,r),this.userData=r}updateReference(e){return this.reference=null!==this.userData?this.userData:e.object.userData,this.reference}}const Af=new WeakMap;class Rf extends Fs{static get type(){return"VelocityNode"}constructor(){super("vec2"),this.projectionMatrix=null,this.updateType=vs.OBJECT,this.updateAfterType=vs.OBJECT,this.previousModelWorldMatrix=tn(new n),this.previousProjectionMatrix=tn(new n).setGroup(Zi),this.previousCameraViewMatrix=tn(new n)}setProjectionMatrix(e){this.projectionMatrix=e}update({frameId:e,camera:t,object:r}){const s=Ef(r);this.previousModelWorldMatrix.value.copy(s);const i=Cf(t);i.frameId!==e&&(i.frameId=e,void 0===i.previousProjectionMatrix?(i.previousProjectionMatrix=new n,i.previousCameraViewMatrix=new n,i.currentProjectionMatrix=new n,i.currentCameraViewMatrix=new n,i.previousProjectionMatrix.copy(this.projectionMatrix||t.projectionMatrix),i.previousCameraViewMatrix.copy(t.matrixWorldInverse)):(i.previousProjectionMatrix.copy(i.currentProjectionMatrix),i.previousCameraViewMatrix.copy(i.currentCameraViewMatrix)),i.currentProjectionMatrix.copy(this.projectionMatrix||t.projectionMatrix),i.currentCameraViewMatrix.copy(t.matrixWorldInverse),this.previousProjectionMatrix.value.copy(i.previousProjectionMatrix),this.previousCameraViewMatrix.value.copy(i.previousCameraViewMatrix))}updateAfter({object:e}){Ef(e).copy(e.matrixWorld)}setup(){const e=null===this.projectionMatrix?Nu:tn(this.projectionMatrix),t=this.previousCameraViewMatrix.mul(this.previousModelWorldMatrix),r=e.mul($u).mul(qu),s=this.previousProjectionMatrix.mul(t).mul(Ku),i=r.xy.div(r.w),n=s.xy.div(s.w);return Gn(i,n)}}function Cf(e){let t=Af.get(e);return void 0===t&&(t={},Af.set(e,t)),t}function Ef(e,t=0){const r=Cf(e);let s=r[t];return void 0===s&&(r[t]=s=new n),s}const wf=Ti(Rf),Mf=_i((([e,t])=>Ko(1,e.oneMinus().div(t)).oneMinus())).setLayout({name:"blendBurn",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Bf=_i((([e,t])=>Ko(e.div(t.oneMinus()),1))).setLayout({name:"blendDodge",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Uf=_i((([e,t])=>e.oneMinus().mul(t.oneMinus()).oneMinus())).setLayout({name:"blendScreen",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Ff=_i((([e,t])=>da(e.mul(2).mul(t),e.oneMinus().mul(2).mul(t.oneMinus()).oneMinus(),Qo(.5,e)))).setLayout({name:"blendOverlay",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Pf=_i((([e,t])=>{const r=t.a.add(e.a.mul(t.a.oneMinus()));return Oi(t.rgb.mul(t.a).add(e.rgb.mul(e.a).mul(t.a.oneMinus())).div(r),r)})).setLayout({name:"blendColor",type:"vec4",inputs:[{name:"base",type:"vec4"},{name:"blend",type:"vec4"}]}),If=_i((([e])=>Of(e.rgb))),Lf=_i((([e,t=Ci(1)])=>t.mix(Of(e.rgb),e.rgb))),Df=_i((([e,t=Ci(1)])=>{const r=On(e.r,e.g,e.b).div(3),s=e.r.max(e.g.max(e.b)),i=s.sub(r).mul(t).mul(-3);return da(e.rgb,s,i)})),Vf=_i((([e,t=Ci(1)])=>{const r=Ii(.57735,.57735,.57735),s=t.cos();return Ii(e.rgb.mul(s).add(r.cross(e.rgb).mul(t.sin()).add(r.mul(ta(r,e.rgb).mul(s.oneMinus())))))})),Of=(e,t=Ii(u.getLuminanceCoefficients(new r)))=>ta(e,t),Gf=_i((([e,t=Ii(1),s=Ii(0),i=Ii(1),n=Ci(1),o=Ii(u.getLuminanceCoefficients(new r,Ae))])=>{const a=e.rgb.dot(Ii(o)),l=Xo(e.rgb.mul(t).add(s),0).toVar(),d=l.pow(i).toVar();return Si(l.r.greaterThan(0),(()=>{l.r.assign(d.r)})),Si(l.g.greaterThan(0),(()=>{l.g.assign(d.g)})),Si(l.b.greaterThan(0),(()=>{l.b.assign(d.b)})),l.assign(a.add(l.sub(a).mul(n))),Oi(l.rgb,e.a)}));class kf extends Fs{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 zf=xi(kf),$f=new t;class Hf extends bu{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 Wf extends Hf{static get type(){return"PassMultipleTextureNode"}constructor(e,t,r=!1){super(e,null),this.textureName=t,this.previousTexture=r}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 jf extends Fs{static get type(){return"PassNode"}constructor(e,t,r,s={}){super("vec4"),this.scope=e,this.scene=t,this.camera=r,this.options=s,this._pixelRatio=1,this._width=1,this._height=1;const i=new B;i.isRenderTargetTexture=!0,i.name="depth";const n=new ge(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:ye,...s});n.texture.name="output",n.depthTexture=i,this.renderTarget=n,this._textures={output:n.texture,depth:i},this._textureNodes={},this._linearDepthNodes={},this._viewZNodes={},this._previousTextures={},this._previousTextureNodes={},this._cameraNear=tn(0),this._cameraFar=tn(0),this._mrt=null,this.isPassNode=!0,this.updateBeforeType=vs.FRAME}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.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(),this._previousTextures[e]=t),t}toggleTexture(e){const t=this._previousTextures[e];if(void 0!==t){const r=this._textures[e],s=this.renderTarget.textures.indexOf(r);this.renderTarget.textures[s]=t,this._textures[e]=t,this._previousTextures[e]=r,this._textureNodes[e].updateTexture(),this._previousTextureNodes[e].updateTexture()}}getTextureNode(e="output"){let t=this._textureNodes[e];return void 0===t&&(t=fi(new Wf(this,e)),t.updateTexture(),this._textureNodes[e]=t),t}getPreviousTextureNode(e="output"){let t=this._previousTextureNodes[e];return void 0===t&&(void 0===this._textureNodes[e]&&this.getTextureNode(e),t=fi(new Wf(this,e,!0)),t.updateTexture(),this._previousTextureNodes[e]=t),t}getViewZNode(e="depth"){let t=this._viewZNodes[e];if(void 0===t){const r=this._cameraNear,s=this._cameraFar;this._viewZNodes[e]=t=Oc(this.getTextureNode(e),r,s)}return t}getLinearDepthNode(e="depth"){let t=this._linearDepthNodes[e];if(void 0===t){const r=this._cameraNear,s=this._cameraFar,i=this.getViewZNode(e);this._linearDepthNodes[e]=t=Dc(i,r,s)}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.scope===jf.COLOR?this.getTextureNode():this.getLinearDepthNode()}updateBefore(e){const{renderer:t}=e,{scene:r,camera:s}=this;this._pixelRatio=t.getPixelRatio();const i=t.getSize($f);this.setSize(i.width,i.height);const n=t.getRenderTarget(),o=t.getMRT();this._cameraNear.value=s.near,this._cameraFar.value=s.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(this.renderTarget),t.setMRT(this._mrt),t.render(r,s),t.setRenderTarget(n),t.setMRT(o)}setSize(e,t){this._width=e,this._height=t;const r=this._width*this._pixelRatio,s=this._height*this._pixelRatio;this.renderTarget.setSize(r,s)}setPixelRatio(e){this._pixelRatio=e,this.setSize(this._width,this._height)}dispose(){this.renderTarget.dispose()}}jf.COLOR="color",jf.DEPTH="depth";class qf extends jf{static get type(){return"ToonOutlinePassNode"}constructor(e,t,r,s,i){super(jf.COLOR,e,t),this.colorNode=r,this.thicknessNode=s,this.alphaNode=i,this._materialCache=new WeakMap}updateBefore(e){const{renderer:t}=e,r=t.getRenderObjectFunction();t.setRenderObjectFunction(((e,r,s,i,n,o,a,u)=>{if((n.isMeshToonMaterial||n.isMeshToonNodeMaterial)&&!1===n.wireframe){const l=this._getOutlineMaterial(n);t.renderObject(e,r,s,i,l,o,a,u)}t.renderObject(e,r,s,i,n,o,a,u)})),super.updateBefore(e),t.setRenderObjectFunction(r)}_createMaterial(){const e=new Yc;e.isMeshToonOutlineMaterial=!0,e.name="Toon_Outline",e.side=x;const t=sl.negate(),r=Nu.mul($u),s=Ci(1),i=r.mul(Oi(qu,1)),n=r.mul(Oi(qu.add(t),1)),o=Ro(i.sub(n));return e.vertexNode=i.add(o.mul(this.thicknessNode).mul(i.w).mul(s)),e.colorNode=Oi(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 Kf=_i((([e,t])=>e.mul(t).clamp())).setLayout({name:"linearToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),Xf=_i((([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"}]}),Yf=_i((([e,t])=>{const r=(e=(e=e.mul(t)).sub(.004).max(0)).mul(e.mul(6.2).add(.5)),s=e.mul(e.mul(6.2).add(1.7)).add(.06);return r.div(s).pow(2.2)})).setLayout({name:"cineonToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),Qf=_i((([e])=>{const t=e.mul(e.add(.0245786)).sub(90537e-9),r=e.mul(e.add(.432951).mul(.983729)).add(.238081);return t.div(r)})),Zf=_i((([e,t])=>{const r=Hi(.59719,.35458,.04823,.076,.90834,.01566,.0284,.13383,.83777),s=Hi(1.60475,-.53108,-.07367,-.10208,1.10813,-.00605,-.00327,-.07276,1.07602);return e=e.mul(t).div(.6),e=r.mul(e),e=Qf(e),(e=s.mul(e)).clamp()})).setLayout({name:"acesFilmicToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),Jf=Hi(Ii(1.6605,-.1246,-.0182),Ii(-.5876,1.1329,-.1006),Ii(-.0728,-.0083,1.1187)),ey=Hi(Ii(.6274,.0691,.0164),Ii(.3293,.9195,.088),Ii(.0433,.0113,.8956)),ty=_i((([e])=>{const t=Ii(e).toVar(),r=Ii(t.mul(t)).toVar(),s=Ii(r.mul(r)).toVar();return Ci(15.5).mul(s.mul(r)).sub(kn(40.14,s.mul(t))).add(kn(31.96,s).sub(kn(6.868,r.mul(t))).add(kn(.4298,r).add(kn(.1191,t).sub(.00232))))})),ry=_i((([e,t])=>{const r=Ii(e).toVar(),s=Hi(Ii(.856627153315983,.137318972929847,.11189821299995),Ii(.0951212405381588,.761241990602591,.0767994186031903),Ii(.0482516061458583,.101439036467562,.811302368396859)),i=Hi(Ii(1.1271005818144368,-.1413297634984383,-.14132976349843826),Ii(-.11060664309660323,1.157823702216272,-.11060664309660294),Ii(-.016493938717834573,-.016493938717834257,1.2519364065950405)),n=Ci(-12.47393),o=Ci(4.026069);return r.mulAssign(t),r.assign(ey.mul(r)),r.assign(s.mul(r)),r.assign(Xo(r,1e-10)),r.assign(_o(r)),r.assign(r.sub(n).div(o.sub(n))),r.assign(ca(r,0,1)),r.assign(ty(r)),r.assign(i.mul(r)),r.assign(sa(Xo(Ii(0),r),Ii(2.2))),r.assign(Jf.mul(r)),r.assign(ca(r,0,1)),r})).setLayout({name:"agxToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),sy=_i((([e,t])=>{const r=Ci(.76),s=Ci(.15);e=e.mul(t);const i=Ko(e.r,Ko(e.g,e.b)),n=Ta(i.lessThan(.08),i.sub(kn(6.25,i.mul(i))),.04);e.subAssign(n);const o=Xo(e.r,Xo(e.g,e.b));Si(o.lessThan(r),(()=>e));const a=Gn(1,r),u=Gn(1,a.mul(a).div(o.add(a.sub(r))));e.mulAssign(u.div(o));const l=Gn(1,zn(1,s.mul(o.sub(u)).add(1)));return da(e,Ii(u),l)})).setLayout({name:"neutralToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]});class iy extends Ms{static get type(){return"CodeNode"}constructor(e="",t=[],r=""){super("code"),this.isCodeNode=!0,this.code=e,this.includes=t,this.language=r}isGlobal(){return!0}setIncludes(e){return this.includes=e,this}getIncludes(){return this.includes}generate(e){const t=this.getIncludes(e);for(const r of t)r.build(e);const r=e.getCodeFromNode(this,this.getNodeType(e));return r.code=this.code,r.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 ny=xi(iy);class oy extends iy{static get type(){return"FunctionNode"}constructor(e="",t=[],r=""){super(e,t,r)}getNodeType(e){return this.getNodeFunction(e).type}getInputs(e){return this.getNodeFunction(e).inputs}getNodeFunction(e){const t=e.getDataFromNode(this);let r=t.nodeFunction;return void 0===r&&(r=e.parser.parseFunction(this.code),t.nodeFunction=r),r}generate(e,t){super.generate(e);const r=this.getNodeFunction(e),s=r.name,i=r.type,n=e.getCodeFromNode(this,i);""!==s&&(n.name=s);const o=e.getPropertyName(n),a=this.getNodeFunction(e).getCode(o);return n.code=a+"\n","property"===t?o:e.format(`${o}()`,i,t)}}const ay=(e,t=[],r="")=>{for(let e=0;es.call(...e);return i.functionNode=s,i};class uy extends Ms{static get type(){return"ScriptableValueNode"}constructor(e=null){super(),this._value=e,this._cache=null,this.inputType=null,this.outputType=null,this.events=new o,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:Ci()}serialize(e){super.serialize(e),null!==this.value?"ArrayBuffer"===this.inputType?e.value=bs(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?xs(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 ly=xi(uy);class dy extends Map{get(e,t=null,...r){if(this.has(e))return super.get(e);if(null!==t){const s=t(...r);return this.set(e,s),s}}}class cy{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 hy=new dy;class py extends Ms{static get type(){return"ScriptableNode"}constructor(e=null,t={}){super(),this.codeNode=e,this.parameters=t,this._local=new dy,this._output=ly(),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 r=this._outputs;return void 0===r[e]?r[e]=ly(t):r[e].value=t,this}getOutput(e){return this._outputs[e]}getParameter(e){return this.parameters[e]}setParameter(e,t){const r=this.parameters;return t&&t.isScriptableNode?(this.deleteParameter(e),r[e]=t,r[e].getDefaultOutput().events.addEventListener("refresh",this.onRefresh)):t&&t.isScriptableValueNode?(this.deleteParameter(e),r[e]=t,r[e].events.addEventListener("refresh",this.onRefresh)):void 0===r[e]?(r[e]=ly(t),r[e].events.addEventListener("refresh",this.onRefresh)):r[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 r=this.getObject()[e];if("function"==typeof r)return r(...t)}async callAsync(e,...t){const r=this.getObject()[e];if("function"==typeof r)return"AsyncFunction"===r.constructor.name?await r(...t):r(...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 cy(this),t=hy.get("THREE"),r=hy.get("TSL"),s=this.getMethod(this.codeNode),i=[e,this._local,hy,()=>this.refresh(),(e,t)=>this.setOutput(e,t),t,r];this._object=s(...i);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:Ci()}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+" };",r="var "+e+"; var output = {};\n"+this.codeNode.code+t;return this._method=new Function(...["parameters","local","global","refresh","setOutput","THREE","TSL"],r),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=[us(this.source),this.getDefaultOutputNode().getCacheKey(e)];for(const r in this.parameters)t.push(this.parameters[r].getCacheKey(e));return ls(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 gy=xi(py);class my extends Ms{static get type(){return"FogNode"}constructor(e,t){super("float"),this.isFogNode=!0,this.colorNode=e,this.factorNode=t}getViewZNode(e){let t;const r=e.context.getViewZ;return void 0!==r&&(t=r(this)),(t||Qu.z).negate()}setup(){return this.factorNode}}const fy=xi(my);class yy extends my{static get type(){return"FogRangeNode"}constructor(e,t,r){super(e,null),this.isFogRangeNode=!0,this.nearNode=t,this.farNode=r}setup(e){const t=this.getViewZNode(e);return ga(this.nearNode,this.farNode,t)}}const by=xi(yy);class xy extends my{static get type(){return"FogExp2Node"}constructor(e,t){super(e,null),this.isFogExp2Node=!0,this.densityNode=t}setup(e){const t=this.getViewZNode(e),r=this.densityNode;return r.mul(r,t,t).negate().exp().oneMinus()}}const Ty=xi(xy);let _y=null,vy=null;class Ny extends Ms{static get type(){return"RangeNode"}constructor(e=Ci(),t=Ci()){super(),this.minNode=e,this.maxNode=t}getVectorLength(e){const t=e.getTypeLength(fs(this.minNode.value)),r=e.getTypeLength(fs(this.maxNode.value));return t>r?t:r}getNodeType(e){return e.object.count>1?e.getTypeFromLength(this.getVectorLength(e)):"float"}setup(e){const t=e.object;let r=null;if(t.count>1){const i=this.minNode.value,n=this.maxNode.value,o=e.getTypeLength(fs(i)),u=e.getTypeLength(fs(n));_y=_y||new s,vy=vy||new s,_y.setScalar(0),vy.setScalar(0),1===o?_y.setScalar(i):i.isColor?_y.set(i.r,i.g,i.b,1):_y.set(i.x,i.y,i.z||0,i.w||0),1===u?vy.setScalar(n):n.isColor?vy.set(n.r,n.g,n.b,1):vy.set(n.x,n.y,n.z||0,n.w||0);const l=4,d=l*t.count,c=new Float32Array(d);for(let e=0;efi(new Ay(e,t)),Cy=Ry("numWorkgroups","uvec3"),Ey=Ry("workgroupId","uvec3"),wy=Ry("localId","uvec3"),My=Ry("subgroupSize","uint");const By=xi(class extends Ms{constructor(e){super(),this.scope=e}generate(e){const{scope:t}=this,{renderer:r}=e;!0===r.backend.isWebGLBackend?e.addFlowCode(`\t// ${t}Barrier \n`):e.addLineFlowCode(`${t}Barrier()`,this)}});class Uy extends Bs{constructor(e,t){super(e,t),this.isWorkgroupInfoElementNode=!0}generate(e,t){let r;const s=e.context.assign;if(r=super.generate(e),!0!==s){const s=this.getNodeType(e);r=e.format(r,s,t)}return r}}class Fy extends Ms{constructor(e,t,r=0){super(t),this.bufferType=t,this.bufferCount=r,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 fi(new Uy(this,e))}generate(e){return e.getScopedArray(this.name||`${this.scope}Array_${this.id}`,this.scope.toLowerCase(),this.bufferType,this.bufferCount)}}class Py extends Fs{static get type(){return"AtomicFunctionNode"}constructor(e,t,r,s=null){super("uint"),this.method=e,this.pointerNode=t,this.valueNode=r,this.storeNode=s}getInputType(e){return this.pointerNode.getNodeType(e)}getNodeType(e){return this.getInputType(e)}generate(e){const t=this.method,r=this.getNodeType(e),s=this.getInputType(e),i=this.pointerNode,n=this.valueNode,o=[];o.push(`&${i.build(e,s)}`),o.push(n.build(e,s));const a=`${e.getMethod(t,r)}( ${o.join(", ")} )`;if(null!==this.storeNode){const t=this.storeNode.build(e,s);e.addLineFlowCode(`${t} = ${a}`,this)}else e.addLineFlowCode(a,this)}}Py.ATOMIC_LOAD="atomicLoad",Py.ATOMIC_STORE="atomicStore",Py.ATOMIC_ADD="atomicAdd",Py.ATOMIC_SUB="atomicSub",Py.ATOMIC_MAX="atomicMax",Py.ATOMIC_MIN="atomicMin",Py.ATOMIC_AND="atomicAnd",Py.ATOMIC_OR="atomicOr",Py.ATOMIC_XOR="atomicXor";const Iy=xi(Py),Ly=(e,t,r,s)=>{const i=Iy(e,t,r,s);return i.append(),i};let Dy;function Vy(e){Dy=Dy||new WeakMap;let t=Dy.get(e);return void 0===t&&Dy.set(e,t={}),t}function Oy(e){const t=Vy(e);return t.shadowMatrix||(t.shadowMatrix=tn("mat4").setGroup(Zi).onRenderUpdate((()=>(!0!==e.castShadow&&e.shadow.updateMatrices(e),e.shadow.matrix))))}function Gy(e){const t=Vy(e);if(void 0===t.projectionUV){const r=Oy(e).mul(Xu);t.projectionUV=r.xyz.div(r.w)}return t.projectionUV}function ky(e){const t=Vy(e);return t.position||(t.position=tn(new r).setGroup(Zi).onRenderUpdate(((t,r)=>r.value.setFromMatrixPosition(e.matrixWorld))))}function zy(e){const t=Vy(e);return t.targetPosition||(t.targetPosition=tn(new r).setGroup(Zi).onRenderUpdate(((t,r)=>r.value.setFromMatrixPosition(e.target.matrixWorld))))}function $y(e){const t=Vy(e);return t.viewPosition||(t.viewPosition=tn(new r).setGroup(Zi).onRenderUpdate((({camera:t},s)=>{s.value=s.value||new r,s.value.setFromMatrixPosition(e.matrixWorld),s.value.applyMatrix4(t.matrixWorldInverse)})))}const Hy=e=>Au.transformDirection(ky(e).sub(zy(e))),Wy=(e,t)=>{for(const r of t)if(r.isAnalyticLightNode&&r.light.id===e)return r;return null},jy=new WeakMap;class qy extends Ms{static get type(){return"LightsNode"}constructor(){super("vec3"),this.totalDiffuseNode=Ii().toVar("totalDiffuse"),this.totalSpecularNode=Ii().toVar("totalSpecular"),this.outgoingLightNode=Ii().toVar("outgoingLight"),this._lights=[],this._lightNodes=null,this._lightNodesHash=null,this.global=!0}customCacheKey(){const e=[];for(let t=0;te.sort(((e,t)=>e.id-t.id)))(this._lights),i=e.renderer.library;for(const e of s)if(e.isNode)t.push(fi(e));else{let s=null;if(null!==r&&(s=Wy(e.id,r)),null===s){const r=i.getLightNodeClass(e.constructor);if(null===r){console.warn(`LightsNode.setupNodeLights: Light node not found for ${e.constructor.name}`);continue}let s=null;jy.has(e)?s=jy.get(e):(s=fi(new r(e)),jy.set(e,s)),t.push(s)}}this._lightNodes=t}setupLights(e,t){for(const r of t)r.build(e)}setup(e){null===this._lightNodes&&this.setupLightsNode(e);const t=e.context,r=t.lightingModel;let s=this.outgoingLightNode;if(r){const{_lightNodes:i,totalDiffuseNode:n,totalSpecularNode:o}=this;t.outgoingLight=s;const a=e.addStack();e.getDataFromNode(this).nodes=a.nodes,r.start(t,a,e),this.setupLights(e,i),r.indirect(t,a,e);const{backdrop:u,backdropAlpha:l}=t,{directDiffuse:d,directSpecular:c,indirectDiffuse:h,indirectSpecular:p}=t.reflectedLight;let g=d.add(h);null!==u&&(g=Ii(null!==l?l.mix(g,u):u),t.material.transparent=!0),n.assign(g),o.assign(c.add(p)),s.assign(n.add(o)),r.finish(t,a,e),s=s.bypass(e.removeStack())}return s}setLights(e){return this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this}getLights(){return this._lights}get hasLights(){return this._lights.length>0}}const Ky=(e=[])=>fi(new qy).setLights(e);class Xy extends Ms{static get type(){return"ShadowBaseNode"}constructor(e){super(),this.light=e,this.updateBeforeType=vs.RENDER,this.isShadowBaseNode=!0}setupShadowPosition({material:e}){Yy.assign(e.shadowPositionNode||Xu)}dispose(){this.updateBeforeType=vs.NONE}}const Yy=Ii().toVar("shadowWorldPosition"),Qy=new WeakMap,Zy=_i((([e,t,r])=>{let s=Xu.sub(e).length();return s=s.sub(t).div(r.sub(t)),s=s.saturate(),s})),Jy=e=>{let t=Qy.get(e);if(void 0===t){const r=e.isPointLight?(e=>{const t=e.shadow.camera,r=Rl("near","float",t).setGroup(Zi),s=Rl("far","float",t).setGroup(Zi),i=Uu(e);return Zy(i,r,s)})(e):null;t=new Yc,t.colorNode=Oi(0,0,0,1),t.depthNode=r,t.isShadowNodeMaterial=!0,t.name="ShadowMaterial",Qy.set(e,t)}return t},eb=_i((({depthTexture:e,shadowCoord:t})=>xu(e,t.xy).compare(t.z))),tb=_i((({depthTexture:e,shadowCoord:t,shadow:r})=>{const s=(t,r)=>xu(e,t).compare(r),i=Rl("mapSize","vec2",r).setGroup(Zi),n=Rl("radius","float",r).setGroup(Zi),o=Bi(1).div(i),a=o.x.negate().mul(n),u=o.y.negate().mul(n),l=o.x.mul(n),d=o.y.mul(n),c=a.div(2),h=u.div(2),p=l.div(2),g=d.div(2);return On(s(t.xy.add(Bi(a,u)),t.z),s(t.xy.add(Bi(0,u)),t.z),s(t.xy.add(Bi(l,u)),t.z),s(t.xy.add(Bi(c,h)),t.z),s(t.xy.add(Bi(0,h)),t.z),s(t.xy.add(Bi(p,h)),t.z),s(t.xy.add(Bi(a,0)),t.z),s(t.xy.add(Bi(c,0)),t.z),s(t.xy,t.z),s(t.xy.add(Bi(p,0)),t.z),s(t.xy.add(Bi(l,0)),t.z),s(t.xy.add(Bi(c,g)),t.z),s(t.xy.add(Bi(0,g)),t.z),s(t.xy.add(Bi(p,g)),t.z),s(t.xy.add(Bi(a,d)),t.z),s(t.xy.add(Bi(0,d)),t.z),s(t.xy.add(Bi(l,d)),t.z)).mul(1/17)})),rb=_i((({depthTexture:e,shadowCoord:t,shadow:r})=>{const s=(t,r)=>xu(e,t).compare(r),i=Rl("mapSize","vec2",r).setGroup(Zi),n=Bi(1).div(i),o=n.x,a=n.y,u=t.xy,l=Co(u.mul(i).add(.5));return u.subAssign(l.mul(n)),On(s(u,t.z),s(u.add(Bi(o,0)),t.z),s(u.add(Bi(0,a)),t.z),s(u.add(n),t.z),da(s(u.add(Bi(o.negate(),0)),t.z),s(u.add(Bi(o.mul(2),0)),t.z),l.x),da(s(u.add(Bi(o.negate(),a)),t.z),s(u.add(Bi(o.mul(2),a)),t.z),l.x),da(s(u.add(Bi(0,a.negate())),t.z),s(u.add(Bi(0,a.mul(2))),t.z),l.y),da(s(u.add(Bi(o,a.negate())),t.z),s(u.add(Bi(o,a.mul(2))),t.z),l.y),da(da(s(u.add(Bi(o.negate(),a.negate())),t.z),s(u.add(Bi(o.mul(2),a.negate())),t.z),l.x),da(s(u.add(Bi(o.negate(),a.mul(2))),t.z),s(u.add(Bi(o.mul(2),a.mul(2))),t.z),l.x),l.y)).mul(1/9)})),sb=_i((({depthTexture:e,shadowCoord:t})=>{const r=Ci(1).toVar(),s=xu(e).sample(t.xy).rg,i=Qo(t.z,s.x);return Si(i.notEqual(Ci(1)),(()=>{const e=t.z.sub(s.x),n=Xo(0,s.y.mul(s.y));let o=n.div(n.add(e.mul(e)));o=ca(Gn(o,.3).div(.95-.3)),r.assign(ca(Xo(i,o)))})),r})),ib=_i((({samples:e,radius:t,size:r,shadowPass:s})=>{const i=Ci(0).toVar(),n=Ci(0).toVar(),o=e.lessThanEqual(Ci(1)).select(Ci(0),Ci(2).div(e.sub(1))),a=e.lessThanEqual(Ci(1)).select(Ci(0),Ci(-1));ic({start:Ei(0),end:Ei(e),type:"int",condition:"<"},(({i:e})=>{const u=a.add(Ci(e).mul(o)),l=s.sample(On(_c.xy,Bi(0,u).mul(t)).div(r)).x;i.addAssign(l),n.addAssign(l.mul(l))})),i.divAssign(e),n.divAssign(e);const u=vo(n.sub(i.mul(i)));return Bi(i,u)})),nb=_i((({samples:e,radius:t,size:r,shadowPass:s})=>{const i=Ci(0).toVar(),n=Ci(0).toVar(),o=e.lessThanEqual(Ci(1)).select(Ci(0),Ci(2).div(e.sub(1))),a=e.lessThanEqual(Ci(1)).select(Ci(0),Ci(-1));ic({start:Ei(0),end:Ei(e),type:"int",condition:"<"},(({i:e})=>{const u=a.add(Ci(e).mul(o)),l=s.sample(On(_c.xy,Bi(u,0).mul(t)).div(r));i.addAssign(l.x),n.addAssign(On(l.y.mul(l.y),l.x.mul(l.x)))})),i.divAssign(e),n.divAssign(e);const u=vo(n.sub(i.mul(i)));return Bi(i,u)})),ob=[eb,tb,rb,sb],ab=new Jm;class ub extends Xy{static get type(){return"ShadowNode"}constructor(e,t=null){super(e),this.shadow=t||e.shadow,this.shadowMap=null,this.vsmShadowMapVertical=null,this.vsmShadowMapHorizontal=null,this.vsmMaterialVertical=null,this.vsmMaterialHorizontal=null,this._node=null,this.isShadowNode=!0}setupShadowFilter(e,{filterFn:t,depthTexture:r,shadowCoord:s,shadow:i}){const n=s.x.greaterThanEqual(0).and(s.x.lessThanEqual(1)).and(s.y.greaterThanEqual(0)).and(s.y.lessThanEqual(1)).and(s.z.lessThanEqual(1)),o=t({depthTexture:r,shadowCoord:s,shadow:i});return n.select(o,Ci(1))}setupShadowCoord(e,t){const{shadow:r}=this,{renderer:s}=e,i=Rl("bias","float",r).setGroup(Zi);let n,o=t;if(r.camera.isOrthographicCamera||!0!==s.logarithmicDepthBuffer)o=o.xyz.div(o.w),n=o.z,s.coordinateSystem===v&&(n=n.mul(2).sub(1));else{const e=o.w;o=o.xy.div(e);const t=Rl("near","float",r.camera).setGroup(Zi),s=Rl("far","float",r.camera).setGroup(Zi);n=Gc(e.negate(),t,s)}return o=Ii(o.x,o.y.oneMinus(),n.add(i)),o}getShadowFilterFn(e){return ob[e]}setupShadow(e){const{renderer:t}=e,{light:r,shadow:s}=this,i=t.shadowMap.type,n=new B(s.mapSize.width,s.mapSize.height);n.compareFunction=Re;const o=e.createRenderTarget(s.mapSize.width,s.mapSize.height);if(o.depthTexture=n,s.camera.updateProjectionMatrix(),i===Ce){n.compareFunction=null,this.vsmShadowMapVertical=e.createRenderTarget(s.mapSize.width,s.mapSize.height,{format:Ee,type:ye}),this.vsmShadowMapHorizontal=e.createRenderTarget(s.mapSize.width,s.mapSize.height,{format:Ee,type:ye});const t=xu(n),r=xu(this.vsmShadowMapVertical.texture),i=Rl("blurSamples","float",s).setGroup(Zi),o=Rl("radius","float",s).setGroup(Zi),a=Rl("mapSize","vec2",s).setGroup(Zi);let u=this.vsmMaterialVertical||(this.vsmMaterialVertical=new Yc);u.fragmentNode=ib({samples:i,radius:o,size:a,shadowPass:t}).context(e.getSharedContext()),u.name="VSMVertical",u=this.vsmMaterialHorizontal||(this.vsmMaterialHorizontal=new Yc),u.fragmentNode=nb({samples:i,radius:o,size:a,shadowPass:r}).context(e.getSharedContext()),u.name="VSMHorizontal"}const a=Rl("intensity","float",s).setGroup(Zi),u=Rl("normalBias","float",s).setGroup(Zi),l=Oy(r).mul(Yy.add(ul.mul(u))),d=this.setupShadowCoord(e,l),c=s.filterNode||this.getShadowFilterFn(t.shadowMap.type)||null;if(null===c)throw new Error("THREE.WebGPURenderer: Shadow map type not supported yet.");const h=i===Ce?this.vsmShadowMapHorizontal.texture:n,p=this.setupShadowFilter(e,{filterFn:c,shadowTexture:o.texture,depthTexture:h,shadowCoord:d,shadow:s}),g=xu(o.texture,d),m=da(1,p.rgb.mix(g,1),a.mul(g.a)).toVar();return this.shadowMap=o,this.shadow.map=o,m}setup(e){if(!1!==e.renderer.shadowMap.enabled)return _i((()=>{let t=this._node;return this.setupShadowPosition(e),null===t&&(this._node=t=this.setupShadow(e)),e.material.shadowNode&&console.warn('THREE.NodeMaterial: ".shadowNode" is deprecated. Use ".castShadowNode" instead.'),e.material.receivedShadowNode&&(t=e.material.receivedShadowNode(t)),t}))()}renderShadow(e){const{shadow:t,shadowMap:r,light:s}=this,{renderer:i,scene:n}=e;t.updateMatrices(s),r.setSize(t.mapSize.width,t.mapSize.height),i.render(n,t.camera)}updateShadow(e){const{shadowMap:t,light:r,shadow:s}=this,{renderer:i,scene:n,camera:o}=e,a=i.shadowMap.type,u=t.depthTexture.version;this._depthVersionCached=u;const l=n.overrideMaterial;n.overrideMaterial=Jy(r),s.camera.layers.mask=o.layers.mask;const d=i.getRenderTarget(),c=i.getRenderObjectFunction(),h=i.getMRT();i.setMRT(null),i.setRenderObjectFunction(((e,t,r,n,u,l,...d)=>{(!0===e.castShadow||e.receiveShadow&&a===Ce)&&(e.onBeforeShadow(i,e,o,s.camera,n,t.overrideMaterial,l),i.renderObject(e,t,r,n,u,l,...d),e.onAfterShadow(i,e,o,s.camera,n,t.overrideMaterial,l))})),i.setRenderTarget(t),this.renderShadow(e),i.setRenderObjectFunction(c),!0!==r.isPointLight&&a===Ce&&this.vsmPass(i),i.setRenderTarget(d),i.setMRT(h),n.overrideMaterial=l}vsmPass(e){const{shadow:t}=this;this.vsmShadowMapVertical.setSize(t.mapSize.width,t.mapSize.height),this.vsmShadowMapHorizontal.setSize(t.mapSize.width,t.mapSize.height),e.setRenderTarget(this.vsmShadowMapVertical),ab.material=this.vsmMaterialVertical,ab.render(e),e.setRenderTarget(this.vsmShadowMapHorizontal),ab.material=this.vsmMaterialHorizontal,ab.render(e)}dispose(){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),super.dispose()}updateBefore(e){const{shadow:t}=this;(t.needsUpdate||t.autoUpdate)&&(this.updateShadow(e),this.shadowMap.depthTexture.version===this._depthVersionCached&&(t.needsUpdate=!1))}}const lb=(e,t)=>fi(new ub(e,t));class db extends cc{static get type(){return"AnalyticLightNode"}constructor(t=null){super(),this.light=t,this.color=new e,this.colorNode=t&&t.colorNode||tn(this.color).setGroup(Zi),this.baseColorNode=null,this.shadowNode=null,this.shadowColorNode=null,this.isAnalyticLightNode=!0,this.updateType=vs.FRAME}customCacheKey(){return ds(this.light.id,this.light.castShadow?1:0)}getHash(){return this.light.uuid}setupShadowNode(){return lb(this.light)}setupShadow(e){const{renderer:t}=e;if(!1===t.shadowMap.enabled)return;let r=this.shadowColorNode;if(null===r){const t=this.light.shadow.shadowNode;let s;s=void 0!==t?fi(t):this.setupShadowNode(e),this.shadowNode=s,this.shadowColorNode=r=this.colorNode.mul(s),this.baseColorNode=this.colorNode}this.colorNode=r}setup(e){this.colorNode=this.baseColorNode||this.colorNode,this.light.castShadow?e.object.receiveShadow&&this.setupShadow(e):null!==this.shadowNode&&(this.shadowNode.dispose(),this.shadowNode=null,this.shadowColorNode=null)}update(){const{light:e}=this;this.color.copy(e.color).multiplyScalar(e.intensity)}}const cb=_i((e=>{const{lightDistance:t,cutoffDistance:r,decayExponent:s}=e,i=t.pow(s).max(.01).reciprocal();return r.greaterThan(0).select(i.mul(t.div(r).pow4().oneMinus().clamp().pow2()),i)})),hb=new e,pb=_i((([e,t])=>{const r=e.toVar(),s=Po(r),i=zn(1,Xo(s.x,Xo(s.y,s.z)));s.mulAssign(i),r.mulAssign(i.mul(t.mul(2).oneMinus()));const n=Bi(r.xy).toVar(),o=t.mul(1.5).oneMinus();return Si(s.z.greaterThanEqual(o),(()=>{Si(r.z.greaterThan(0),(()=>{n.x.assign(Gn(4,r.x))}))})).ElseIf(s.x.greaterThanEqual(o),(()=>{const e=Io(r.x);n.x.assign(r.z.mul(e).add(e.mul(2)))})).ElseIf(s.y.greaterThanEqual(o),(()=>{const e=Io(r.y);n.x.assign(r.x.add(e.mul(2)).add(2)),n.y.assign(r.z.mul(e).sub(2))})),Bi(.125,.25).mul(n).add(Bi(.375,.75)).flipY()})).setLayout({name:"cubeToUV",type:"vec2",inputs:[{name:"pos",type:"vec3"},{name:"texelSizeY",type:"float"}]}),gb=_i((({depthTexture:e,bd3D:t,dp:r,texelSize:s})=>xu(e,pb(t,s.y)).compare(r))),mb=_i((({depthTexture:e,bd3D:t,dp:r,texelSize:s,shadow:i})=>{const n=Rl("radius","float",i).setGroup(Zi),o=Bi(-1,1).mul(n).mul(s.y);return xu(e,pb(t.add(o.xyy),s.y)).compare(r).add(xu(e,pb(t.add(o.yyy),s.y)).compare(r)).add(xu(e,pb(t.add(o.xyx),s.y)).compare(r)).add(xu(e,pb(t.add(o.yyx),s.y)).compare(r)).add(xu(e,pb(t,s.y)).compare(r)).add(xu(e,pb(t.add(o.xxy),s.y)).compare(r)).add(xu(e,pb(t.add(o.yxy),s.y)).compare(r)).add(xu(e,pb(t.add(o.xxx),s.y)).compare(r)).add(xu(e,pb(t.add(o.yxx),s.y)).compare(r)).mul(1/9)})),fb=_i((({filterFn:e,depthTexture:t,shadowCoord:r,shadow:s})=>{const i=r.xyz.toVar(),n=i.length(),o=tn("float").setGroup(Zi).onRenderUpdate((()=>s.camera.near)),a=tn("float").setGroup(Zi).onRenderUpdate((()=>s.camera.far)),u=Rl("bias","float",s).setGroup(Zi),l=tn(s.mapSize).setGroup(Zi),d=Ci(1).toVar();return Si(n.sub(a).lessThanEqual(0).and(n.sub(o).greaterThanEqual(0)),(()=>{const r=n.sub(o).div(a.sub(o)).toVar();r.addAssign(u);const c=i.normalize(),h=Bi(1).div(l.mul(Bi(4,2)));d.assign(e({depthTexture:t,bd3D:c,dp:r,texelSize:h,shadow:s}))})),d})),yb=new s,bb=new t,xb=new t;class Tb extends ub{static get type(){return"PointShadowNode"}constructor(e,t=null){super(e,t)}getShadowFilterFn(e){return e===we?gb:mb}setupShadowCoord(e,t){return t}setupShadowFilter(e,{filterFn:t,shadowTexture:r,depthTexture:s,shadowCoord:i,shadow:n}){return fb({filterFn:t,shadowTexture:r,depthTexture:s,shadowCoord:i,shadow:n})}renderShadow(e){const{shadow:t,shadowMap:r,light:s}=this,{renderer:i,scene:n}=e,o=t.getFrameExtents();xb.copy(t.mapSize),xb.multiply(o),r.setSize(xb.width,xb.height),bb.copy(t.mapSize);const a=i.autoClear,u=i.getClearColor(hb),l=i.getClearAlpha();i.autoClear=!1,i.setClearColor(t.clearColor,t.clearAlpha),i.clear();const d=t.getViewportCount();for(let e=0;e{const n=i.context.lightingModel,o=t.sub(Qu),a=o.normalize(),u=o.length(),l=cb({lightDistance:u,cutoffDistance:r,decayExponent:s}),d=e.mul(l),c=i.context.reflectedLight;n.direct({lightDirection:a,lightColor:d,reflectedLight:c},i.stack,i)}));class vb extends db{static get type(){return"PointLightNode"}constructor(e=null){super(e),this.cutoffDistanceNode=tn(0).setGroup(Zi),this.decayExponentNode=tn(2).setGroup(Zi)}update(e){const{light:t}=this;super.update(e),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}setupShadowNode(){return((e,t)=>fi(new Tb(e,t)))(this.light)}setup(e){super.setup(e),_b({color:this.colorNode,lightViewPosition:$y(this.light),cutoffDistance:this.cutoffDistanceNode,decayExponent:this.decayExponentNode}).append()}}const Nb=_i((([e=t()])=>{const t=e.mul(2),r=t.x.floor(),s=t.y.floor();return r.add(s).mod(2).sign()})),Sb=_i((([e,t,r])=>{const s=Ci(r).toVar(),i=Ci(t).toVar(),n=Mi(e).toVar();return Ta(n,i,s)})).setLayout({name:"mx_select",type:"float",inputs:[{name:"b",type:"bool"},{name:"t",type:"float"},{name:"f",type:"float"}]}),Ab=_i((([e,t])=>{const r=Mi(t).toVar(),s=Ci(e).toVar();return Ta(r,s.negate(),s)})).setLayout({name:"mx_negate_if",type:"float",inputs:[{name:"val",type:"float"},{name:"b",type:"bool"}]}),Rb=_i((([e])=>{const t=Ci(e).toVar();return Ei(So(t))})).setLayout({name:"mx_floor",type:"int",inputs:[{name:"x",type:"float"}]}),Cb=_i((([e,t])=>{const r=Ci(e).toVar();return t.assign(Rb(r)),r.sub(Ci(t))})),Eb=vm([_i((([e,t,r,s,i,n])=>{const o=Ci(n).toVar(),a=Ci(i).toVar(),u=Ci(s).toVar(),l=Ci(r).toVar(),d=Ci(t).toVar(),c=Ci(e).toVar(),h=Ci(Gn(1,a)).toVar();return Gn(1,o).mul(c.mul(h).add(d.mul(a))).add(o.mul(l.mul(h).add(u.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"}]}),_i((([e,t,r,s,i,n])=>{const o=Ci(n).toVar(),a=Ci(i).toVar(),u=Ii(s).toVar(),l=Ii(r).toVar(),d=Ii(t).toVar(),c=Ii(e).toVar(),h=Ci(Gn(1,a)).toVar();return Gn(1,o).mul(c.mul(h).add(d.mul(a))).add(o.mul(l.mul(h).add(u.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"}]})]),wb=vm([_i((([e,t,r,s,i,n,o,a,u,l,d])=>{const c=Ci(d).toVar(),h=Ci(l).toVar(),p=Ci(u).toVar(),g=Ci(a).toVar(),m=Ci(o).toVar(),f=Ci(n).toVar(),y=Ci(i).toVar(),b=Ci(s).toVar(),x=Ci(r).toVar(),T=Ci(t).toVar(),_=Ci(e).toVar(),v=Ci(Gn(1,p)).toVar(),N=Ci(Gn(1,h)).toVar();return Ci(Gn(1,c)).toVar().mul(N.mul(_.mul(v).add(T.mul(p))).add(h.mul(x.mul(v).add(b.mul(p))))).add(c.mul(N.mul(y.mul(v).add(f.mul(p))).add(h.mul(m.mul(v).add(g.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"}]}),_i((([e,t,r,s,i,n,o,a,u,l,d])=>{const c=Ci(d).toVar(),h=Ci(l).toVar(),p=Ci(u).toVar(),g=Ii(a).toVar(),m=Ii(o).toVar(),f=Ii(n).toVar(),y=Ii(i).toVar(),b=Ii(s).toVar(),x=Ii(r).toVar(),T=Ii(t).toVar(),_=Ii(e).toVar(),v=Ci(Gn(1,p)).toVar(),N=Ci(Gn(1,h)).toVar();return Ci(Gn(1,c)).toVar().mul(N.mul(_.mul(v).add(T.mul(p))).add(h.mul(x.mul(v).add(b.mul(p))))).add(c.mul(N.mul(y.mul(v).add(f.mul(p))).add(h.mul(m.mul(v).add(g.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"}]})]),Mb=_i((([e,t,r])=>{const s=Ci(r).toVar(),i=Ci(t).toVar(),n=wi(e).toVar(),o=wi(n.bitAnd(wi(7))).toVar(),a=Ci(Sb(o.lessThan(wi(4)),i,s)).toVar(),u=Ci(kn(2,Sb(o.lessThan(wi(4)),s,i))).toVar();return Ab(a,Mi(o.bitAnd(wi(1)))).add(Ab(u,Mi(o.bitAnd(wi(2)))))})).setLayout({name:"mx_gradient_float_0",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"}]}),Bb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ci(t).toVar(),a=wi(e).toVar(),u=wi(a.bitAnd(wi(15))).toVar(),l=Ci(Sb(u.lessThan(wi(8)),o,n)).toVar(),d=Ci(Sb(u.lessThan(wi(4)),n,Sb(u.equal(wi(12)).or(u.equal(wi(14))),o,i))).toVar();return Ab(l,Mi(u.bitAnd(wi(1)))).add(Ab(d,Mi(u.bitAnd(wi(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"}]}),Ub=vm([Mb,Bb]),Fb=_i((([e,t,r])=>{const s=Ci(r).toVar(),i=Ci(t).toVar(),n=Di(e).toVar();return Ii(Ub(n.x,i,s),Ub(n.y,i,s),Ub(n.z,i,s))})).setLayout({name:"mx_gradient_vec3_0",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"}]}),Pb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ci(t).toVar(),a=Di(e).toVar();return Ii(Ub(a.x,o,n,i),Ub(a.y,o,n,i),Ub(a.z,o,n,i))})).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"}]}),Ib=vm([Fb,Pb]),Lb=_i((([e])=>{const t=Ci(e).toVar();return kn(.6616,t)})).setLayout({name:"mx_gradient_scale2d_0",type:"float",inputs:[{name:"v",type:"float"}]}),Db=_i((([e])=>{const t=Ci(e).toVar();return kn(.982,t)})).setLayout({name:"mx_gradient_scale3d_0",type:"float",inputs:[{name:"v",type:"float"}]}),Vb=vm([Lb,_i((([e])=>{const t=Ii(e).toVar();return kn(.6616,t)})).setLayout({name:"mx_gradient_scale2d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),Ob=vm([Db,_i((([e])=>{const t=Ii(e).toVar();return kn(.982,t)})).setLayout({name:"mx_gradient_scale3d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),Gb=_i((([e,t])=>{const r=Ei(t).toVar(),s=wi(e).toVar();return s.shiftLeft(r).bitOr(s.shiftRight(Ei(32).sub(r)))})).setLayout({name:"mx_rotl32",type:"uint",inputs:[{name:"x",type:"uint"},{name:"k",type:"int"}]}),kb=_i((([e,t,r])=>{e.subAssign(r),e.bitXorAssign(Gb(r,Ei(4))),r.addAssign(t),t.subAssign(e),t.bitXorAssign(Gb(e,Ei(6))),e.addAssign(r),r.subAssign(t),r.bitXorAssign(Gb(t,Ei(8))),t.addAssign(e),e.subAssign(r),e.bitXorAssign(Gb(r,Ei(16))),r.addAssign(t),t.subAssign(e),t.bitXorAssign(Gb(e,Ei(19))),e.addAssign(r),r.subAssign(t),r.bitXorAssign(Gb(t,Ei(4))),t.addAssign(e)})),zb=_i((([e,t,r])=>{const s=wi(r).toVar(),i=wi(t).toVar(),n=wi(e).toVar();return s.bitXorAssign(i),s.subAssign(Gb(i,Ei(14))),n.bitXorAssign(s),n.subAssign(Gb(s,Ei(11))),i.bitXorAssign(n),i.subAssign(Gb(n,Ei(25))),s.bitXorAssign(i),s.subAssign(Gb(i,Ei(16))),n.bitXorAssign(s),n.subAssign(Gb(s,Ei(4))),i.bitXorAssign(n),i.subAssign(Gb(n,Ei(14))),s.bitXorAssign(i),s.subAssign(Gb(i,Ei(24))),s})).setLayout({name:"mx_bjfinal",type:"uint",inputs:[{name:"a",type:"uint"},{name:"b",type:"uint"},{name:"c",type:"uint"}]}),$b=_i((([e])=>{const t=wi(e).toVar();return Ci(t).div(Ci(wi(Ei(4294967295))))})).setLayout({name:"mx_bits_to_01",type:"float",inputs:[{name:"bits",type:"uint"}]}),Hb=_i((([e])=>{const t=Ci(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"}]}),Wb=vm([_i((([e])=>{const t=Ei(e).toVar(),r=wi(wi(1)).toVar(),s=wi(wi(Ei(3735928559)).add(r.shiftLeft(wi(2))).add(wi(13))).toVar();return zb(s.add(wi(t)),s,s)})).setLayout({name:"mx_hash_int_0",type:"uint",inputs:[{name:"x",type:"int"}]}),_i((([e,t])=>{const r=Ei(t).toVar(),s=Ei(e).toVar(),i=wi(wi(2)).toVar(),n=wi().toVar(),o=wi().toVar(),a=wi().toVar();return n.assign(o.assign(a.assign(wi(Ei(3735928559)).add(i.shiftLeft(wi(2))).add(wi(13))))),n.addAssign(wi(s)),o.addAssign(wi(r)),zb(n,o,a)})).setLayout({name:"mx_hash_int_1",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ei(t).toVar(),n=Ei(e).toVar(),o=wi(wi(3)).toVar(),a=wi().toVar(),u=wi().toVar(),l=wi().toVar();return a.assign(u.assign(l.assign(wi(Ei(3735928559)).add(o.shiftLeft(wi(2))).add(wi(13))))),a.addAssign(wi(n)),u.addAssign(wi(i)),l.addAssign(wi(s)),zb(a,u,l)})).setLayout({name:"mx_hash_int_2",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]}),_i((([e,t,r,s])=>{const i=Ei(s).toVar(),n=Ei(r).toVar(),o=Ei(t).toVar(),a=Ei(e).toVar(),u=wi(wi(4)).toVar(),l=wi().toVar(),d=wi().toVar(),c=wi().toVar();return l.assign(d.assign(c.assign(wi(Ei(3735928559)).add(u.shiftLeft(wi(2))).add(wi(13))))),l.addAssign(wi(a)),d.addAssign(wi(o)),c.addAssign(wi(n)),kb(l,d,c),l.addAssign(wi(i)),zb(l,d,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"}]}),_i((([e,t,r,s,i])=>{const n=Ei(i).toVar(),o=Ei(s).toVar(),a=Ei(r).toVar(),u=Ei(t).toVar(),l=Ei(e).toVar(),d=wi(wi(5)).toVar(),c=wi().toVar(),h=wi().toVar(),p=wi().toVar();return c.assign(h.assign(p.assign(wi(Ei(3735928559)).add(d.shiftLeft(wi(2))).add(wi(13))))),c.addAssign(wi(l)),h.addAssign(wi(u)),p.addAssign(wi(a)),kb(c,h,p),c.addAssign(wi(o)),h.addAssign(wi(n)),zb(c,h,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"}]})]),jb=vm([_i((([e,t])=>{const r=Ei(t).toVar(),s=Ei(e).toVar(),i=wi(Wb(s,r)).toVar(),n=Di().toVar();return n.x.assign(i.bitAnd(Ei(255))),n.y.assign(i.shiftRight(Ei(8)).bitAnd(Ei(255))),n.z.assign(i.shiftRight(Ei(16)).bitAnd(Ei(255))),n})).setLayout({name:"mx_hash_vec3_0",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ei(t).toVar(),n=Ei(e).toVar(),o=wi(Wb(n,i,s)).toVar(),a=Di().toVar();return a.x.assign(o.bitAnd(Ei(255))),a.y.assign(o.shiftRight(Ei(8)).bitAnd(Ei(255))),a.z.assign(o.shiftRight(Ei(16)).bitAnd(Ei(255))),a})).setLayout({name:"mx_hash_vec3_1",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]})]),qb=vm([_i((([e])=>{const t=Bi(e).toVar(),r=Ei().toVar(),s=Ei().toVar(),i=Ci(Cb(t.x,r)).toVar(),n=Ci(Cb(t.y,s)).toVar(),o=Ci(Hb(i)).toVar(),a=Ci(Hb(n)).toVar(),u=Ci(Eb(Ub(Wb(r,s),i,n),Ub(Wb(r.add(Ei(1)),s),i.sub(1),n),Ub(Wb(r,s.add(Ei(1))),i,n.sub(1)),Ub(Wb(r.add(Ei(1)),s.add(Ei(1))),i.sub(1),n.sub(1)),o,a)).toVar();return Vb(u)})).setLayout({name:"mx_perlin_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"}]}),_i((([e])=>{const t=Ii(e).toVar(),r=Ei().toVar(),s=Ei().toVar(),i=Ei().toVar(),n=Ci(Cb(t.x,r)).toVar(),o=Ci(Cb(t.y,s)).toVar(),a=Ci(Cb(t.z,i)).toVar(),u=Ci(Hb(n)).toVar(),l=Ci(Hb(o)).toVar(),d=Ci(Hb(a)).toVar(),c=Ci(wb(Ub(Wb(r,s,i),n,o,a),Ub(Wb(r.add(Ei(1)),s,i),n.sub(1),o,a),Ub(Wb(r,s.add(Ei(1)),i),n,o.sub(1),a),Ub(Wb(r.add(Ei(1)),s.add(Ei(1)),i),n.sub(1),o.sub(1),a),Ub(Wb(r,s,i.add(Ei(1))),n,o,a.sub(1)),Ub(Wb(r.add(Ei(1)),s,i.add(Ei(1))),n.sub(1),o,a.sub(1)),Ub(Wb(r,s.add(Ei(1)),i.add(Ei(1))),n,o.sub(1),a.sub(1)),Ub(Wb(r.add(Ei(1)),s.add(Ei(1)),i.add(Ei(1))),n.sub(1),o.sub(1),a.sub(1)),u,l,d)).toVar();return Ob(c)})).setLayout({name:"mx_perlin_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"}]})]),Kb=vm([_i((([e])=>{const t=Bi(e).toVar(),r=Ei().toVar(),s=Ei().toVar(),i=Ci(Cb(t.x,r)).toVar(),n=Ci(Cb(t.y,s)).toVar(),o=Ci(Hb(i)).toVar(),a=Ci(Hb(n)).toVar(),u=Ii(Eb(Ib(jb(r,s),i,n),Ib(jb(r.add(Ei(1)),s),i.sub(1),n),Ib(jb(r,s.add(Ei(1))),i,n.sub(1)),Ib(jb(r.add(Ei(1)),s.add(Ei(1))),i.sub(1),n.sub(1)),o,a)).toVar();return Vb(u)})).setLayout({name:"mx_perlin_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),_i((([e])=>{const t=Ii(e).toVar(),r=Ei().toVar(),s=Ei().toVar(),i=Ei().toVar(),n=Ci(Cb(t.x,r)).toVar(),o=Ci(Cb(t.y,s)).toVar(),a=Ci(Cb(t.z,i)).toVar(),u=Ci(Hb(n)).toVar(),l=Ci(Hb(o)).toVar(),d=Ci(Hb(a)).toVar(),c=Ii(wb(Ib(jb(r,s,i),n,o,a),Ib(jb(r.add(Ei(1)),s,i),n.sub(1),o,a),Ib(jb(r,s.add(Ei(1)),i),n,o.sub(1),a),Ib(jb(r.add(Ei(1)),s.add(Ei(1)),i),n.sub(1),o.sub(1),a),Ib(jb(r,s,i.add(Ei(1))),n,o,a.sub(1)),Ib(jb(r.add(Ei(1)),s,i.add(Ei(1))),n.sub(1),o,a.sub(1)),Ib(jb(r,s.add(Ei(1)),i.add(Ei(1))),n,o.sub(1),a.sub(1)),Ib(jb(r.add(Ei(1)),s.add(Ei(1)),i.add(Ei(1))),n.sub(1),o.sub(1),a.sub(1)),u,l,d)).toVar();return Ob(c)})).setLayout({name:"mx_perlin_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"}]})]),Xb=vm([_i((([e])=>{const t=Ci(e).toVar(),r=Ei(Rb(t)).toVar();return $b(Wb(r))})).setLayout({name:"mx_cell_noise_float_0",type:"float",inputs:[{name:"p",type:"float"}]}),_i((([e])=>{const t=Bi(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar();return $b(Wb(r,s))})).setLayout({name:"mx_cell_noise_float_1",type:"float",inputs:[{name:"p",type:"vec2"}]}),_i((([e])=>{const t=Ii(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar(),i=Ei(Rb(t.z)).toVar();return $b(Wb(r,s,i))})).setLayout({name:"mx_cell_noise_float_2",type:"float",inputs:[{name:"p",type:"vec3"}]}),_i((([e])=>{const t=Oi(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar(),i=Ei(Rb(t.z)).toVar(),n=Ei(Rb(t.w)).toVar();return $b(Wb(r,s,i,n))})).setLayout({name:"mx_cell_noise_float_3",type:"float",inputs:[{name:"p",type:"vec4"}]})]),Yb=vm([_i((([e])=>{const t=Ci(e).toVar(),r=Ei(Rb(t)).toVar();return Ii($b(Wb(r,Ei(0))),$b(Wb(r,Ei(1))),$b(Wb(r,Ei(2))))})).setLayout({name:"mx_cell_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"float"}]}),_i((([e])=>{const t=Bi(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar();return Ii($b(Wb(r,s,Ei(0))),$b(Wb(r,s,Ei(1))),$b(Wb(r,s,Ei(2))))})).setLayout({name:"mx_cell_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),_i((([e])=>{const t=Ii(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar(),i=Ei(Rb(t.z)).toVar();return Ii($b(Wb(r,s,i,Ei(0))),$b(Wb(r,s,i,Ei(1))),$b(Wb(r,s,i,Ei(2))))})).setLayout({name:"mx_cell_noise_vec3_2",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),_i((([e])=>{const t=Oi(e).toVar(),r=Ei(Rb(t.x)).toVar(),s=Ei(Rb(t.y)).toVar(),i=Ei(Rb(t.z)).toVar(),n=Ei(Rb(t.w)).toVar();return Ii($b(Wb(r,s,i,n,Ei(0))),$b(Wb(r,s,i,n,Ei(1))),$b(Wb(r,s,i,n,Ei(2))))})).setLayout({name:"mx_cell_noise_vec3_3",type:"vec3",inputs:[{name:"p",type:"vec4"}]})]),Qb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ei(t).toVar(),a=Ii(e).toVar(),u=Ci(0).toVar(),l=Ci(1).toVar();return ic(o,(()=>{u.addAssign(l.mul(qb(a))),l.mulAssign(i),a.mulAssign(n)})),u})).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"}]}),Zb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ei(t).toVar(),a=Ii(e).toVar(),u=Ii(0).toVar(),l=Ci(1).toVar();return ic(o,(()=>{u.addAssign(l.mul(Kb(a))),l.mulAssign(i),a.mulAssign(n)})),u})).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"}]}),Jb=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ei(t).toVar(),a=Ii(e).toVar();return Bi(Qb(a,o,n,i),Qb(a.add(Ii(Ei(19),Ei(193),Ei(17))),o,n,i))})).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"}]}),ex=_i((([e,t,r,s])=>{const i=Ci(s).toVar(),n=Ci(r).toVar(),o=Ei(t).toVar(),a=Ii(e).toVar(),u=Ii(Zb(a,o,n,i)).toVar(),l=Ci(Qb(a.add(Ii(Ei(19),Ei(193),Ei(17))),o,n,i)).toVar();return Oi(u,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"}]}),tx=vm([_i((([e,t,r,s,i,n,o])=>{const a=Ei(o).toVar(),u=Ci(n).toVar(),l=Ei(i).toVar(),d=Ei(s).toVar(),c=Ei(r).toVar(),h=Ei(t).toVar(),p=Bi(e).toVar(),g=Ii(Yb(Bi(h.add(d),c.add(l)))).toVar(),m=Bi(g.x,g.y).toVar();m.subAssign(.5),m.mulAssign(u),m.addAssign(.5);const f=Bi(Bi(Ci(h),Ci(c)).add(m)).toVar(),y=Bi(f.sub(p)).toVar();return Si(a.equal(Ei(2)),(()=>Po(y.x).add(Po(y.y)))),Si(a.equal(Ei(3)),(()=>Xo(Po(y.x),Po(y.y)))),ta(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"}]}),_i((([e,t,r,s,i,n,o,a,u])=>{const l=Ei(u).toVar(),d=Ci(a).toVar(),c=Ei(o).toVar(),h=Ei(n).toVar(),p=Ei(i).toVar(),g=Ei(s).toVar(),m=Ei(r).toVar(),f=Ei(t).toVar(),y=Ii(e).toVar(),b=Ii(Yb(Ii(f.add(p),m.add(h),g.add(c)))).toVar();b.subAssign(.5),b.mulAssign(d),b.addAssign(.5);const x=Ii(Ii(Ci(f),Ci(m),Ci(g)).add(b)).toVar(),T=Ii(x.sub(y)).toVar();return Si(l.equal(Ei(2)),(()=>Po(T.x).add(Po(T.y)).add(Po(T.z)))),Si(l.equal(Ei(3)),(()=>Xo(Xo(Po(T.x),Po(T.y)),Po(T.z)))),ta(T,T)})).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"}]})]),rx=_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Bi(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Bi(Cb(n.x,o),Cb(n.y,a)).toVar(),l=Ci(1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{const r=Ci(tx(u,e,t,o,a,i,s)).toVar();l.assign(Ko(l,r))}))})),Si(s.equal(Ei(0)),(()=>{l.assign(vo(l))})),l})).setLayout({name:"mx_worley_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),sx=_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Bi(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Bi(Cb(n.x,o),Cb(n.y,a)).toVar(),l=Bi(1e6,1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{const r=Ci(tx(u,e,t,o,a,i,s)).toVar();Si(r.lessThan(l.x),(()=>{l.y.assign(l.x),l.x.assign(r)})).ElseIf(r.lessThan(l.y),(()=>{l.y.assign(r)}))}))})),Si(s.equal(Ei(0)),(()=>{l.assign(vo(l))})),l})).setLayout({name:"mx_worley_noise_vec2_0",type:"vec2",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),ix=_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Bi(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Bi(Cb(n.x,o),Cb(n.y,a)).toVar(),l=Ii(1e6,1e6,1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{const r=Ci(tx(u,e,t,o,a,i,s)).toVar();Si(r.lessThan(l.x),(()=>{l.z.assign(l.y),l.y.assign(l.x),l.x.assign(r)})).ElseIf(r.lessThan(l.y),(()=>{l.z.assign(l.y),l.y.assign(r)})).ElseIf(r.lessThan(l.z),(()=>{l.z.assign(r)}))}))})),Si(s.equal(Ei(0)),(()=>{l.assign(vo(l))})),l})).setLayout({name:"mx_worley_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),nx=vm([rx,_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Ii(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Ei().toVar(),l=Ii(Cb(n.x,o),Cb(n.y,a),Cb(n.z,u)).toVar(),d=Ci(1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{ic({start:-1,end:Ei(1),name:"z",condition:"<="},(({z:r})=>{const n=Ci(tx(l,e,t,r,o,a,u,i,s)).toVar();d.assign(Ko(d,n))}))}))})),Si(s.equal(Ei(0)),(()=>{d.assign(vo(d))})),d})).setLayout({name:"mx_worley_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),ox=vm([sx,_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Ii(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Ei().toVar(),l=Ii(Cb(n.x,o),Cb(n.y,a),Cb(n.z,u)).toVar(),d=Bi(1e6,1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{ic({start:-1,end:Ei(1),name:"z",condition:"<="},(({z:r})=>{const n=Ci(tx(l,e,t,r,o,a,u,i,s)).toVar();Si(n.lessThan(d.x),(()=>{d.y.assign(d.x),d.x.assign(n)})).ElseIf(n.lessThan(d.y),(()=>{d.y.assign(n)}))}))}))})),Si(s.equal(Ei(0)),(()=>{d.assign(vo(d))})),d})).setLayout({name:"mx_worley_noise_vec2_1",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),ax=vm([ix,_i((([e,t,r])=>{const s=Ei(r).toVar(),i=Ci(t).toVar(),n=Ii(e).toVar(),o=Ei().toVar(),a=Ei().toVar(),u=Ei().toVar(),l=Ii(Cb(n.x,o),Cb(n.y,a),Cb(n.z,u)).toVar(),d=Ii(1e6,1e6,1e6).toVar();return ic({start:-1,end:Ei(1),name:"x",condition:"<="},(({x:e})=>{ic({start:-1,end:Ei(1),name:"y",condition:"<="},(({y:t})=>{ic({start:-1,end:Ei(1),name:"z",condition:"<="},(({z:r})=>{const n=Ci(tx(l,e,t,r,o,a,u,i,s)).toVar();Si(n.lessThan(d.x),(()=>{d.z.assign(d.y),d.y.assign(d.x),d.x.assign(n)})).ElseIf(n.lessThan(d.y),(()=>{d.z.assign(d.y),d.y.assign(n)})).ElseIf(n.lessThan(d.z),(()=>{d.z.assign(n)}))}))}))})),Si(s.equal(Ei(0)),(()=>{d.assign(vo(d))})),d})).setLayout({name:"mx_worley_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),ux=_i((([e])=>{const t=e.y,r=e.z,s=Ii().toVar();return Si(t.lessThan(1e-4),(()=>{s.assign(Ii(r,r,r))})).Else((()=>{let i=e.x;i=i.sub(So(i)).mul(6).toVar();const n=Ei($o(i)),o=i.sub(Ci(n)),a=r.mul(t.oneMinus()),u=r.mul(t.mul(o).oneMinus()),l=r.mul(t.mul(o.oneMinus()).oneMinus());Si(n.equal(Ei(0)),(()=>{s.assign(Ii(r,l,a))})).ElseIf(n.equal(Ei(1)),(()=>{s.assign(Ii(u,r,a))})).ElseIf(n.equal(Ei(2)),(()=>{s.assign(Ii(a,r,l))})).ElseIf(n.equal(Ei(3)),(()=>{s.assign(Ii(a,u,r))})).ElseIf(n.equal(Ei(4)),(()=>{s.assign(Ii(l,a,r))})).Else((()=>{s.assign(Ii(r,a,u))}))})),s})).setLayout({name:"mx_hsvtorgb",type:"vec3",inputs:[{name:"hsv",type:"vec3"}]}),lx=_i((([e])=>{const t=Ii(e).toVar(),r=Ci(t.x).toVar(),s=Ci(t.y).toVar(),i=Ci(t.z).toVar(),n=Ci(Ko(r,Ko(s,i))).toVar(),o=Ci(Xo(r,Xo(s,i))).toVar(),a=Ci(o.sub(n)).toVar(),u=Ci().toVar(),l=Ci().toVar(),d=Ci().toVar();return d.assign(o),Si(o.greaterThan(0),(()=>{l.assign(a.div(o))})).Else((()=>{l.assign(0)})),Si(l.lessThanEqual(0),(()=>{u.assign(0)})).Else((()=>{Si(r.greaterThanEqual(o),(()=>{u.assign(s.sub(i).div(a))})).ElseIf(s.greaterThanEqual(o),(()=>{u.assign(On(2,i.sub(r).div(a)))})).Else((()=>{u.assign(On(4,r.sub(s).div(a)))})),u.mulAssign(1/6),Si(u.lessThan(0),(()=>{u.addAssign(1)}))})),Ii(u,l,d)})).setLayout({name:"mx_rgbtohsv",type:"vec3",inputs:[{name:"c",type:"vec3"}]}),dx=_i((([e])=>{const t=Ii(e).toVar(),r=Vi(qn(t,Ii(.04045))).toVar(),s=Ii(t.div(12.92)).toVar(),i=Ii(sa(Xo(t.add(Ii(.055)),Ii(0)).div(1.055),Ii(2.4))).toVar();return da(s,i,r)})).setLayout({name:"mx_srgb_texture_to_lin_rec709",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),cx=(e,t)=>{e=Ci(e),t=Ci(t);const r=Bi(t.dFdx(),t.dFdy()).length().mul(.7071067811865476);return ga(e.sub(r),e.add(r),t)},hx=(e,t,r,s)=>da(e,t,r[s].clamp()),px=(e,t,r,s,i)=>da(e,t,cx(r,s[i])),gx=_i((([e,t,r])=>{const s=Ro(e).toVar("nDir"),i=Gn(Ci(.5).mul(t.sub(r)),Xu).div(s).toVar("rbmax"),n=Gn(Ci(-.5).mul(t.sub(r)),Xu).div(s).toVar("rbmin"),o=Ii().toVar("rbminmax");o.x=s.x.greaterThan(Ci(0)).select(i.x,n.x),o.y=s.y.greaterThan(Ci(0)).select(i.y,n.y),o.z=s.z.greaterThan(Ci(0)).select(i.z,n.z);const a=Ko(Ko(o.x,o.y),o.z).toVar("correction");return Xu.add(s.mul(a)).toVar("boxIntersection").sub(r)})),mx=_i((([e,t])=>{const r=e.x,s=e.y,i=e.z;let n=t.element(0).mul(.886227);return n=n.add(t.element(1).mul(1.023328).mul(s)),n=n.add(t.element(2).mul(1.023328).mul(i)),n=n.add(t.element(3).mul(1.023328).mul(r)),n=n.add(t.element(4).mul(.858086).mul(r).mul(s)),n=n.add(t.element(5).mul(.858086).mul(s).mul(i)),n=n.add(t.element(6).mul(i.mul(i).mul(.743125).sub(.247708))),n=n.add(t.element(7).mul(.858086).mul(r).mul(i)),n=n.add(t.element(8).mul(.429043).mul(kn(r,r).sub(kn(s,s)))),n}));var fx=Object.freeze({__proto__:null,BRDF_GGX:kh,BRDF_Lambert:Rh,BasicShadowFilter:eb,Break:nc,Continue:()=>au("continue").append(),DFGApprox:zh,D_GGX:Vh,Discard:uu,EPSILON:uo,F_Schlick:Ah,Fn:_i,INFINITY:lo,If:Si,Loop:ic,NodeAccess:Ss,NodeShaderStage:_s,NodeType:Ns,NodeUpdateType:vs,PCFShadowFilter:tb,PCFSoftShadowFilter:rb,PI:co,PI2:ho,Return:()=>au("return").append(),Schlick_to_F0:Hh,ScriptableNodeResources:hy,ShaderNode:mi,TBNViewMatrix:$l,VSMShadowFilter:sb,V_GGX_SmithCorrelated:Lh,abs:Po,acesFilmicToneMapping:Zf,acos:Uo,add:On,addMethodChaining:$s,addNodeElement:function(e){console.warn("THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add",e)},agxToneMapping:ry,all:po,alphaT:yn,and:Yn,anisotropy:bn,anisotropyB:Tn,anisotropyT:xn,any:go,append:Ai,arrayBuffer:e=>fi(new Gs(e,"ArrayBuffer")),asin:Bo,assign:In,atan:Fo,atan2:qo,atomicAdd:(e,t,r=null)=>Ly(Py.ATOMIC_ADD,e,t,r),atomicAnd:(e,t,r=null)=>Ly(Py.ATOMIC_AND,e,t,r),atomicFunc:Ly,atomicMax:(e,t,r=null)=>Ly(Py.ATOMIC_MAX,e,t,r),atomicMin:(e,t,r=null)=>Ly(Py.ATOMIC_MIN,e,t,r),atomicOr:(e,t,r=null)=>Ly(Py.ATOMIC_OR,e,t,r),atomicStore:(e,t,r=null)=>Ly(Py.ATOMIC_STORE,e,t,r),atomicSub:(e,t,r=null)=>Ly(Py.ATOMIC_SUB,e,t,r),atomicXor:(e,t,r=null)=>Ly(Py.ATOMIC_XOR,e,t,r),attenuationColor:Un,attenuationDistance:Bn,attribute:hu,attributeArray:(e,t="float")=>{const r=ms(t),s=new uf(e,r);return hf(s,t,e)},backgroundBlurriness:xf,backgroundIntensity:Tf,backgroundRotation:_f,batch:Jd,billboarding:Em,bitAnd:eo,bitNot:to,bitOr:ro,bitXor:so,bitangentGeometry:Dl,bitangentLocal:Vl,bitangentView:Ol,bitangentWorld:Gl,bitcast:Wo,blendBurn:Mf,blendColor:Pf,blendDodge:Bf,blendOverlay:Ff,blendScreen:Uf,blur:zp,bool:Mi,buffer:Tl,bufferAttribute:qa,bumpMap:Zl,burn:(...e)=>(console.warn('THREE.TSL: "burn" has been renamed. Use "blendBurn" instead.'),Mf(e)),bvec2:Pi,bvec3:Vi,bvec4:zi,bypass:ru,cache:eu,call:Dn,cameraFar:vu,cameraNear:_u,cameraNormalMatrix:Cu,cameraPosition:Eu,cameraProjectionMatrix:Nu,cameraProjectionMatrixInverse:Su,cameraViewMatrix:Au,cameraWorldMatrix:Ru,cbrt:ua,cdl:Gf,ceil:Ao,checker:Nb,cineonToneMapping:Yf,clamp:ca,clearcoat:dn,clearcoatRoughness:cn,code:ny,color:Ri,colorSpaceToWorking:Va,colorToDirection:e=>fi(e).mul(2).sub(1),compute:Za,cond:_a,context:Na,convert:qi,convertColorSpace:(e,t,r)=>fi(new Pa(fi(e),t,r)),convertToTexture:(e,...t)=>e.isTextureNode?e:e.isPassNode?e.getTextureNode():rf(e,...t),cos:wo,cross:ra,cubeTexture:bl,dFdx:Oo,dFdy:Go,dashSize:An,defaultBuildStages:Rs,defaultShaderStages:As,defined:pi,degrees:yo,deltaTime:Sm,densityFog:Ty,depth:zc,depthPass:(e,t)=>fi(new jf(jf.DEPTH,e,t)),difference:ea,diffuseColor:on,directPointLight:_b,directionToColor:uh,dispersion:Fn,distance:Jo,div:zn,dodge:(...e)=>(console.warn('THREE.TSL: "dodge" has been renamed. Use "blendDodge" instead.'),Bf(e)),dot:ta,drawIndex:qd,dynamicBufferAttribute:Ka,element:ji,emissive:an,equal:Hn,equals:mo,equirectUV:hh,exp:bo,exp2:xo,expression:au,faceDirection:tl,faceForward:ma,float:Ci,floor:So,fog:fy,fract:Co,frameGroup:Qi,frameId:Am,frontFacing:el,fwidth:Ho,gain:(e,t)=>e.lessThan(.5)?fm(e.mul(2),t).div(2):Gn(1,fm(kn(Gn(1,e),2),t).div(2)),gapSize:Rn,getConstNodeType:gi,getCurrentStack:Ni,getDirection:Vp,getDistanceAttenuation:cb,getGeometryRoughness:Ph,getNormalFromDepth:of,getParallaxCorrectNormal:gx,getRoughness:Ih,getScreenPosition:nf,getShIrradianceAt:mx,getTextureIndex:hm,getViewPosition:sf,glsl:(e,t)=>ny(e,t,"glsl"),glslFn:(e,t)=>ay(e,t,"glsl"),grayscale:If,greaterThan:qn,greaterThanEqual:Xn,hash:mm,highPrecisionModelNormalViewMatrix:Wu,highPrecisionModelViewMatrix:Hu,hue:Vf,instance:Xd,instanceIndex:$d,instancedArray:(e,t="float")=>{const r=ms(t),s=new af(e,r);return hf(s,t,e)},instancedBufferAttribute:Xa,instancedDynamicBufferAttribute:Ya,instancedMesh:Qd,int:Ei,inverseSqrt:No,invocationLocalIndex:jd,invocationSubgroupIndex:Wd,ior:En,iridescence:gn,iridescenceIOR:mn,iridescenceThickness:fn,ivec2:Ui,ivec3:Li,ivec4:Gi,js:(e,t)=>ny(e,t,"js"),label:Sa,length:Lo,lengthSq:la,lessThan:jn,lessThanEqual:Kn,lightPosition:ky,lightProjectionUV:Gy,lightShadowMatrix:Oy,lightTargetDirection:Hy,lightTargetPosition:zy,lightViewPosition:$y,lightingContext:gc,lights:Ky,linearDepth:$c,linearToneMapping:Kf,localId:wy,log:To,log2:_o,logarithmicDepthToViewZ:(e,t,r)=>{const s=e.mul(To(r.div(t)));return Ci(Math.E).pow(s).mul(t).negate()},loop:(...e)=>(console.warn("TSL.LoopNode: loop() has been renamed to Loop()."),ic(...e)),luminance:Of,mat2:$i,mat3:Hi,mat4:Wi,matcapUV:lg,materialAOMap:Dd,materialAlphaTest:td,materialAnisotropy:Td,materialAnisotropyVector:Vd,materialAttenuationColor:Ed,materialAttenuationDistance:Cd,materialClearcoat:gd,materialClearcoatNormal:fd,materialClearcoatRoughness:md,materialColor:rd,materialDispersion:Id,materialEmissive:id,materialIOR:Rd,materialIridescence:_d,materialIridescenceIOR:vd,materialIridescenceThickness:Nd,materialLightMap:Ld,materialLineDashOffset:Fd,materialLineDashSize:Md,materialLineGapSize:Bd,materialLineScale:wd,materialLineWidth:Ud,materialMetalness:hd,materialNormal:pd,materialOpacity:nd,materialPointWidth:Pd,materialReference:wl,materialReflectivity:dd,materialRefractionRatio:hl,materialRotation:yd,materialRoughness:cd,materialSheen:bd,materialSheenRoughness:xd,materialShininess:sd,materialSpecular:od,materialSpecularColor:ud,materialSpecularIntensity:ad,materialSpecularStrength:ld,materialThickness:Ad,materialTransmission:Sd,max:Xo,maxMipLevel:yu,metalness:ln,min:Ko,mix:da,mixElement:ya,mod:Yo,modInt:$n,modelDirection:Lu,modelNormalMatrix:ku,modelPosition:Vu,modelScale:Ou,modelViewMatrix:$u,modelViewPosition:Gu,modelViewProjection:Gd,modelWorldMatrix:Du,modelWorldMatrixInverse:zu,morphReference:dc,mrt:gm,mul:kn,mx_aastep:cx,mx_cell_noise_float:(e=pu())=>Xb(e.convert("vec2|vec3")),mx_contrast:(e,t=1,r=.5)=>Ci(e).sub(r).mul(t).add(r),mx_fractal_noise_float:(e=pu(),t=3,r=2,s=.5,i=1)=>Qb(e,Ei(t),r,s).mul(i),mx_fractal_noise_vec2:(e=pu(),t=3,r=2,s=.5,i=1)=>Jb(e,Ei(t),r,s).mul(i),mx_fractal_noise_vec3:(e=pu(),t=3,r=2,s=.5,i=1)=>Zb(e,Ei(t),r,s).mul(i),mx_fractal_noise_vec4:(e=pu(),t=3,r=2,s=.5,i=1)=>ex(e,Ei(t),r,s).mul(i),mx_hsvtorgb:ux,mx_noise_float:(e=pu(),t=1,r=0)=>qb(e.convert("vec2|vec3")).mul(t).add(r),mx_noise_vec3:(e=pu(),t=1,r=0)=>Kb(e.convert("vec2|vec3")).mul(t).add(r),mx_noise_vec4:(e=pu(),t=1,r=0)=>{e=e.convert("vec2|vec3");return Oi(Kb(e),qb(e.add(Bi(19,73)))).mul(t).add(r)},mx_ramplr:(e,t,r=pu())=>hx(e,t,r,"x"),mx_ramptb:(e,t,r=pu())=>hx(e,t,r,"y"),mx_rgbtohsv:lx,mx_safepower:(e,t=1)=>(e=Ci(e)).abs().pow(t).mul(e.sign()),mx_splitlr:(e,t,r,s=pu())=>px(e,t,r,s,"x"),mx_splittb:(e,t,r,s=pu())=>px(e,t,r,s,"y"),mx_srgb_texture_to_lin_rec709:dx,mx_transform_uv:(e=1,t=0,r=pu())=>r.mul(e).add(t),mx_worley_noise_float:(e=pu(),t=1)=>nx(e.convert("vec2|vec3"),t,Ei(1)),mx_worley_noise_vec2:(e=pu(),t=1)=>ox(e.convert("vec2|vec3"),t,Ei(1)),mx_worley_noise_vec3:(e=pu(),t=1)=>ax(e.convert("vec2|vec3"),t,Ei(1)),negate:Do,neutralToneMapping:sy,nodeArray:bi,nodeImmutable:Ti,nodeObject:fi,nodeObjects:yi,nodeProxy:xi,normalFlat:il,normalGeometry:rl,normalLocal:sl,normalMap:Kl,normalView:nl,normalWorld:ol,normalize:Ro,not:Zn,notEqual:Wn,numWorkgroups:Cy,objectDirection:Mu,objectGroup:Ji,objectPosition:Uu,objectScale:Fu,objectViewPosition:Pu,objectWorldMatrix:Bu,oneMinus:Vo,or:Qn,orthographicDepthToViewZ:(e,t,r)=>t.sub(r).mul(e).sub(t),oscSawtooth:(e=Nm)=>e.fract(),oscSine:(e=Nm)=>e.add(.75).mul(2*Math.PI).sin().mul(.5).add(.5),oscSquare:(e=Nm)=>e.fract().round(),oscTriangle:(e=Nm)=>e.add(.5).fract().mul(2).sub(1).abs(),output:Sn,outputStruct:cm,overlay:(...e)=>(console.warn('THREE.TSL: "overlay" has been renamed. Use "blendOverlay" instead.'),Ff(e)),overloadingFn:vm,parabola:fm,parallaxDirection:Hl,parallaxUV:(e,t)=>e.sub(Hl.mul(t)),parameter:(e,t)=>fi(new am(e,t)),pass:(e,t,r)=>fi(new jf(jf.COLOR,e,t,r)),passTexture:(e,t)=>fi(new Hf(e,t)),pcurve:(e,t,r)=>sa(zn(sa(e,t),On(sa(e,t),sa(Gn(1,e),r))),1/t),perspectiveDepthToViewZ:Oc,pmremTexture:qp,pointUV:mf,pointWidth:Cn,positionGeometry:ju,positionLocal:qu,positionPrevious:Ku,positionView:Qu,positionViewDirection:Zu,positionWorld:Xu,positionWorldDirection:Yu,posterize:zf,pow:sa,pow2:ia,pow3:na,pow4:oa,property:sn,radians:fo,rand:fa,range:Sy,rangeFog:by,reciprocal:zo,reference:Rl,referenceBuffer:Cl,reflect:Zo,reflectVector:ml,reflectView:pl,reflector:e=>fi(new Km(e)),refract:pa,refractVector:fl,refractView:gl,reinhardToneMapping:Xf,remainder:oo,remap:iu,remapClamp:nu,renderGroup:Zi,renderOutput:du,rendererReference:za,rotate:mg,rotateUV:Rm,roughness:un,round:ko,rtt:rf,sRGBTransferEOTF:Ma,sRGBTransferOETF:Ba,sampler:e=>(!0===e.isNode?e:xu(e)).convert("sampler"),saturate:ha,saturation:Lf,screen:(...e)=>(console.warn('THREE.TSL: "screen" has been renamed. Use "blendScreen" instead.'),Uf(e)),screenCoordinate:_c,screenSize:Tc,screenUV:xc,scriptable:gy,scriptableValue:ly,select:Ta,setCurrentStack:vi,shaderStages:Cs,shadow:lb,sharedUniformGroup:Yi,sheen:hn,sheenRoughness:pn,shiftLeft:io,shiftRight:no,shininess:Nn,sign:Io,sin:Eo,sinc:(e,t)=>Eo(co.mul(t.mul(e).sub(1))).div(co.mul(t.mul(e).sub(1))),skinning:e=>fi(new tc(e)),skinningReference:rc,smoothstep:ga,smoothstepElement:ba,specularColor:_n,specularF90:vn,spherizeUV:Cm,split:(e,t)=>fi(new Ls(fi(e),t)),spritesheetUV:Bm,sqrt:vo,stack:lm,step:Qo,storage:hf,storageBarrier:()=>By("storage").append(),storageObject:(e,t,r)=>(console.warn('THREE.TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.'),hf(e,t,r).setPBO(!0)),storageTexture:Nf,string:(e="")=>fi(new Gs(e,"string")),sub:Gn,subgroupIndex:Hd,subgroupSize:My,tan:Mo,tangentGeometry:Ml,tangentLocal:Bl,tangentView:Ul,tangentWorld:Fl,temp:Ca,texture:xu,texture3D:Ng,textureBarrier:()=>By("texture").append(),textureBicubic:up,textureCubeUV:Op,textureLoad:Tu,textureSize:mu,textureStore:(e,t,r)=>{const s=Nf(e,t,r);return null!==r&&s.append(),s},thickness:Mn,time:Nm,timerDelta:(e=1)=>(console.warn('TSL: timerDelta() is deprecated. Use "deltaTime" instead.'),Sm.mul(e)),timerGlobal:(e=1)=>(console.warn('TSL: timerGlobal() is deprecated. Use "time" instead.'),Nm.mul(e)),timerLocal:(e=1)=>(console.warn('TSL: timerLocal() is deprecated. Use "time" instead.'),Nm.mul(e)),toOutputColorSpace:Ia,toWorkingColorSpace:La,toneMapping:Ha,toneMappingExposure:Wa,toonOutlinePass:(t,r,s=new e(0,0,0),i=.003,n=1)=>fi(new qf(t,r,fi(s),fi(i),fi(n))),transformDirection:aa,transformNormal:dl,transformNormalToView:cl,transformedBentNormalView:Wl,transformedBitangentView:kl,transformedBitangentWorld:zl,transformedClearcoatNormalView:ll,transformedNormalView:al,transformedNormalWorld:ul,transformedTangentView:Pl,transformedTangentWorld:Il,transmission:wn,transpose:jo,triNoise3D:xm,triplanarTexture:(...e)=>Fm(...e),triplanarTextures:Fm,trunc:$o,tslFn:(...e)=>(console.warn("TSL.ShaderNode: tslFn() has been renamed to Fn()."),_i(...e)),uint:wi,uniform:tn,uniformArray:Nl,uniformGroup:Xi,uniforms:(e,t)=>(console.warn("TSL.UniformArrayNode: uniforms() has been renamed to uniformArray()."),fi(new vl(e,t))),userData:(e,t,r)=>fi(new Sf(e,t,r)),uv:pu,uvec2:Fi,uvec3:Di,uvec4:ki,varying:wa,varyingProperty:nn,vec2:Bi,vec3:Ii,vec4:Oi,vectorComponents:Es,velocity:wf,vertexColor:(...e)=>fi(new pf(...e)),vertexIndex:zd,vibrance:Df,viewZToLogarithmicDepth:Gc,viewZToOrthographicDepth:Dc,viewZToPerspectiveDepth:Vc,viewport:vc,viewportBottomLeft:Ec,viewportCoordinate:Sc,viewportDepthTexture:Ic,viewportLinearDepth:Hc,viewportMipTexture:Uc,viewportResolution:Rc,viewportSafeUV:wm,viewportSharedTexture:nh,viewportSize:Nc,viewportTexture:Bc,viewportTopLeft:Cc,viewportUV:Ac,wgsl:(e,t)=>ny(e,t,"wgsl"),wgslFn:(e,t)=>ay(e,t,"wgsl"),workgroupArray:(e,t)=>fi(new Fy("Workgroup",e,t)),workgroupBarrier:()=>By("workgroup").append(),workgroupId:Ey,workingToColorSpace:Da,xor:Jn});const yx=new om;class bx extends Bg{constructor(e,t){super(),this.renderer=e,this.nodes=t}update(e,t,r){const s=this.renderer,i=this.nodes.getBackgroundNode(e)||e.background;let n=!1;if(null===i)s._clearColor.getRGB(yx,Ae),yx.a=s._clearColor.a;else if(!0===i.isColor)i.getRGB(yx,Ae),yx.a=1,n=!0;else if(!0===i.isNode){const r=this.get(e),n=i;yx.copy(s._clearColor);let o=r.backgroundMesh;if(void 0===o){const e=Na(Oi(n).mul(Tf),{getUV:()=>_f.mul(ol),getTextureLevel:()=>xf});let t=Gd();t=t.setZ(t.w);const s=new Yc;s.name="Background.material",s.side=x,s.depthTest=!1,s.depthWrite=!1,s.fog=!1,s.lights=!1,s.vertexNode=t,s.colorNode=e,r.backgroundMeshNode=e,r.backgroundMesh=o=new k(new Me(1,32,32),s),o.frustumCulled=!1,o.name="Background.mesh",o.onBeforeRender=function(e,t,r){this.matrixWorld.copyPosition(r.matrixWorld)}}const a=n.getCacheKey();r.backgroundCacheKey!==a&&(r.backgroundMeshNode.node=Oi(n).mul(Tf),r.backgroundMeshNode.needsUpdate=!0,o.material.needsUpdate=!0,r.backgroundCacheKey=a),t.unshift(o,o.geometry,o.material,0,0,null,null)}else console.error("THREE.Renderer: Unsupported background configuration.",i);if(!0===s.autoClear||!0===n){const e=r.clearColorValue;e.r=yx.r,e.g=yx.g,e.b=yx.b,e.a=yx.a,!0!==s.backend.isWebGLBackend&&!0!==s.alpha||(e.r*=e.a,e.g*=e.a,e.b*=e.a),r.depthClearValue=s._clearDepth,r.stencilClearValue=s._clearStencil,r.clearColor=!0===s.autoClearColor,r.clearDepth=!0===s.autoClearDepth,r.clearStencil=!0===s.autoClearStencil}else r.clearColor=!1,r.clearDepth=!1,r.clearStencil=!1}}let xx=0;class Tx{constructor(e="",t=[],r=0,s=[]){this.name=e,this.bindings=t,this.index=r,this.bindingsReference=s,this.id=xx++}}class _x{constructor(e,t,r,s,i,n,o,a,u,l=[]){this.vertexShader=e,this.fragmentShader=t,this.computeShader=r,this.transforms=l,this.nodeAttributes=s,this.bindings=i,this.updateNodes=n,this.updateBeforeNodes=o,this.updateAfterNodes=a,this.monitor=u,this.usedTimes=0}createBindings(){const e=[];for(const t of this.bindings){if(!0!==t.bindings[0].groupNode.shared){const r=new Tx(t.name,[],t.index,t);e.push(r);for(const e of t.bindings)r.bindings.push(e.clone())}else e.push(t)}return e}}class vx{constructor(e,t,r=null){this.isNodeAttribute=!0,this.name=e,this.type=t,this.node=r}}class Nx{constructor(e,t,r){this.isNodeUniform=!0,this.name=e,this.type=t,this.node=r.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 Sx{constructor(e,t){this.isNodeVar=!0,this.name=e,this.type=t}}class Ax extends Sx{constructor(e,t){super(e,t),this.needsInterpolation=!1,this.isNodeVarying=!0}}class Rx{constructor(e,t,r=""){this.name=e,this.type=t,this.code=r,Object.defineProperty(this,"isNodeCode",{value:!0})}}let Cx=0;class Ex{constructor(e=null){this.id=Cx++,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 wx extends Ms{static get type(){return"StructTypeNode"}constructor(e,t){super(),this.name=e,this.types=t,this.isStructTypeNode=!0}getMemberTypes(){return this.types}}class Mx{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 Bx extends Mx{constructor(e,t=0){super(e,t),this.isNumberUniform=!0,this.boundary=4,this.itemSize=1}}class Ux extends Mx{constructor(e,r=new t){super(e,r),this.isVector2Uniform=!0,this.boundary=8,this.itemSize=2}}class Fx extends Mx{constructor(e,t=new r){super(e,t),this.isVector3Uniform=!0,this.boundary=16,this.itemSize=3}}class Px extends Mx{constructor(e,t=new s){super(e,t),this.isVector4Uniform=!0,this.boundary=16,this.itemSize=4}}class Ix extends Mx{constructor(t,r=new e){super(t,r),this.isColorUniform=!0,this.boundary=16,this.itemSize=3}}class Lx extends Mx{constructor(e,t=new i){super(e,t),this.isMatrix3Uniform=!0,this.boundary=48,this.itemSize=12}}class Dx extends Mx{constructor(e,t=new n){super(e,t),this.isMatrix4Uniform=!0,this.boundary=64,this.itemSize=16}}class Vx extends Bx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class Ox extends Ux{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class Gx extends Fx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class kx extends Px{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class zx extends Ix{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class $x extends Lx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class Hx extends Dx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}const Wx=[.125,.215,.35,.446,.526,.582],jx=20,qx=new xe(-1,1,1,-1,0,1),Kx=new Ue(90,1),Xx=new e;let Yx=null,Qx=0,Zx=0;const Jx=(1+Math.sqrt(5))/2,eT=1/Jx,tT=[new r(-Jx,eT,0),new r(Jx,eT,0),new r(-eT,0,Jx),new r(eT,0,Jx),new r(0,Jx,-eT),new r(0,Jx,eT),new r(-1,1,-1),new r(1,1,-1),new r(-1,1,1),new r(1,1,1)],rT=[3,1,5,0,4,2],sT=Vp(pu(),hu("faceIndex")).normalize(),iT=Ii(sT.x,sT.y,sT.z);class nT{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}get _hasInitialized(){return this._renderer.hasInitialized()}fromScene(e,t=0,r=.1,s=100,i=null){if(this._setSize(256),!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromScene() called before the backend is initialized. Try using .fromSceneAsync() instead.");const n=i||this._allocateTargets();return this.fromSceneAsync(e,t,r,s,n),n}Yx=this._renderer.getRenderTarget(),Qx=this._renderer.getActiveCubeFace(),Zx=this._renderer.getActiveMipmapLevel();const n=i||this._allocateTargets();return n.depthBuffer=!0,this._sceneToCubeUV(e,r,s,n),t>0&&this._blur(n,0,0,t),this._applyPMREM(n),this._cleanup(n),n}async fromSceneAsync(e,t=0,r=.1,s=100,i=null){return!1===this._hasInitialized&&await this._renderer.init(),this.fromScene(e,t,r,s,i)}fromEquirectangular(e,t=null){if(!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromEquirectangular() called before the backend is initialized. Try using .fromEquirectangularAsync() instead."),this._setSizeFromTexture(e);const r=t||this._allocateTargets();return this.fromEquirectangularAsync(e,r),r}return this._fromTexture(e,t)}async fromEquirectangularAsync(e,t=null){return!1===this._hasInitialized&&await this._renderer.init(),this._fromTexture(e,t)}fromCubemap(e,t=null){if(!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromCubemap() called before the backend is initialized. Try using .fromCubemapAsync() instead."),this._setSizeFromTexture(e);const r=t||this._allocateTargets();return this.fromCubemapAsync(e,t),r}return this._fromTexture(e,t)}async fromCubemapAsync(e,t=null){return!1===this._hasInitialized&&await this._renderer.init(),this._fromTexture(e,t)}async compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=lT(),await this._compileMaterial(this._cubemapMaterial))}async compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=dT(),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())}_setSizeFromTexture(e){e.mapping===T||e.mapping===_?this._setSize(0===e.image.length?16:e.image[0].width||e.image[0].image.width):this._setSize(e.image.width/4)}_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?u=Wx[a-e+4-1]:0===a&&(u=0),s.push(u);const l=1/(o-2),d=-l,c=1+l,h=[d,d,c,d,c,c,d,d,c,c,d,c],p=6,g=6,m=3,f=2,y=1,b=new Float32Array(m*g*p),x=new Float32Array(f*g*p),T=new Float32Array(y*g*p);for(let e=0;e2?0:-1,s=[t,r,0,t+2/3,r,0,t+2/3,r+1,0,t,r,0,t+2/3,r+1,0,t,r+1,0],i=rT[e];b.set(s,m*g*i),x.set(h,f*g*i);const n=[i,i,i,i,i,i];T.set(n,y*g*i)}const _=new Te;_.setAttribute("position",new ve(b,m)),_.setAttribute("uv",new ve(x,f)),_.setAttribute("faceIndex",new ve(T,y)),t.push(_),i.push(new k(_,null)),n>4&&n--}return{lodPlanes:t,sizeLods:r,sigmas:s,lodMeshes:i}}(i)),this._blurMaterial=function(e,t,s){const i=Nl(new Array(jx).fill(0)),n=tn(new r(0,1,0)),o=tn(0),a=Ci(jx),u=tn(0),l=tn(1),d=xu(null),c=tn(0),h=Ci(1/t),p=Ci(1/s),g=Ci(e),m={n:a,latitudinal:u,weights:i,poleAxis:n,outputDirection:iT,dTheta:o,samples:l,envMap:d,mipInt:c,CUBEUV_TEXEL_WIDTH:h,CUBEUV_TEXEL_HEIGHT:p,CUBEUV_MAX_MIP:g},f=uT("blur");return f.uniforms=m,f.fragmentNode=zp({...m,latitudinal:u.equal(1)}),f}(i,e,t)}return i}async _compileMaterial(e){const t=new k(this._lodPlanes[0],e);await this._renderer.compile(t,qx)}_sceneToCubeUV(e,t,r,s){const i=Kx;i.near=t,i.far=r;const n=[1,1,1,1,-1,1],o=[1,-1,1,-1,1,-1],a=this._renderer,u=a.autoClear;a.getClearColor(Xx),a.autoClear=!1;let l=this._backgroundBox;if(null===l){const e=new Q({name:"PMREM.Background",side:x,depthWrite:!1,depthTest:!1});l=new k(new G,e)}let d=!1;const c=e.background;c?c.isColor&&(l.material.color.copy(c),e.background=null,d=!0):(l.material.color.copy(Xx),d=!0),a.setRenderTarget(s),a.clear(),d&&a.render(l,i);for(let t=0;t<6;t++){const r=t%3;0===r?(i.up.set(0,n[t],0),i.lookAt(o[t],0,0)):1===r?(i.up.set(0,0,n[t]),i.lookAt(0,o[t],0)):(i.up.set(0,n[t],0),i.lookAt(0,0,o[t]));const u=this._cubeSize;aT(s,r*u,t>2?u:0,u,u),a.render(e,i)}a.autoClear=u,e.background=c}_textureToCubeUV(e,t){const r=this._renderer,s=e.mapping===T||e.mapping===_;s?null===this._cubemapMaterial&&(this._cubemapMaterial=lT(e)):null===this._equirectMaterial&&(this._equirectMaterial=dT(e));const i=s?this._cubemapMaterial:this._equirectMaterial;i.fragmentNode.value=e;const n=this._lodMeshes[0];n.material=i;const o=this._cubeSize;aT(t,0,0,3*o,2*o),r.setRenderTarget(t),r.render(n,qx)}_applyPMREM(e){const t=this._renderer,r=t.autoClear;t.autoClear=!1;const s=this._lodPlanes.length;for(let t=1;tjx&&console.warn(`sigmaRadians, ${i}, is too large and will clip, as it requested ${g} samples when the maximum is set to 20`);const m=[];let f=0;for(let e=0;ey-4?s-y+4:0),4*(this._cubeSize-b),3*b,2*b),a.setRenderTarget(t),a.render(l,qx)}}function oT(e,t,r){const s=new ge(e,t,r);return s.texture.mapping=Be,s.texture.name="PMREM.cubeUv",s.texture.isPMREMTexture=!0,s.scissorTest=!0,s}function aT(e,t,r,s,i){e.viewport.set(t,r,s,i),e.scissor.set(t,r,s,i)}function uT(e){const t=new Yc;return t.depthTest=!1,t.depthWrite=!1,t.blending=D,t.name=`PMREM_${e}`,t}function lT(e){const t=uT("cubemap");return t.fragmentNode=bl(e,iT),t}function dT(e){const t=uT("equirect");return t.fragmentNode=xu(e,hh(iT),0),t}const cT=new WeakMap,hT=new Map([[Int8Array,"int"],[Int16Array,"int"],[Int32Array,"int"],[Uint8Array,"uint"],[Uint16Array,"uint"],[Uint32Array,"uint"],[Float32Array,"float"]]),pT=e=>/e/g.test(e)?String(e).replace(/\+/g,""):(e=Number(e))+(e%1?"":".0");class gT{constructor(e,t,r){this.object=e,this.material=e&&e.material||null,this.geometry=e&&e.geometry||null,this.renderer=t,this.parser=r,this.scene=null,this.camera=null,this.nodes=[],this.sequentialNodes=[],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=lm(),this.stacks=[],this.tab="\t",this.currentFunctionNode=null,this.context={material:this.material},this.cache=new Ex,this.globalCache=this.cache,this.flowsData=new WeakMap,this.shaderStage=null,this.buildStage=null,this.useComparisonMethod=!1}getBindGroupsCache(){let e=cT.get(this.renderer);return void 0===e&&(e=new Rg,cT.set(this.renderer,e)),e}createRenderTarget(e,t,r){return new ge(e,t,r)}createCubeRenderTarget(e,t){return new ph(e,t)}createPMREMGenerator(){return new nT(this.renderer)}includes(e){return this.nodes.includes(e)}_getBindGroup(e,t){const r=this.getBindGroupsCache(),s=[];let i,n=!0;for(const e of t)s.push(e),n=n&&!0!==e.groupNode.shared;return n?(i=r.get(s),void 0===i&&(i=new Tx(e,s,this.bindingsIndexes[e].group,s),r.set(s,i))):i=new Tx(e,s,this.bindingsIndexes[e].group,s),i}getBindGroupArray(e,t){const r=this.bindings[t];let s=r[e];return void 0===s&&(void 0===this.bindingsIndexes[e]&&(this.bindingsIndexes[e]={binding:0,group:Object.keys(this.bindingsIndexes).length}),r[e]=s=[]),s}getBindings(){let e=this.bindGroups;if(null===e){const t={},r=this.bindings;for(const e of Cs)for(const s in r[e]){const i=r[e][s];(t[s]||(t[s]=[])).push(...i)}e=[];for(const r in t){const s=t[r],i=this._getBindGroup(r,s);e.push(i)}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(n)}u`:"0u";if("bool"===i)return n?"true":"false";if("color"===i)return`${this.getType("vec3")}( ${pT(n.r)}, ${pT(n.g)}, ${pT(n.b)} )`;const o=this.getTypeLength(i),a=this.getComponentType(i),u=e=>this.generateConst(a,e);if(2===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)} )`;if(3===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)}, ${u(n.z)} )`;if(4===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)}, ${u(n.z)}, ${u(n.w)} )`;if(o>4&&n&&(n.isMatrix3||n.isMatrix4))return`${this.getType(i)}( ${n.elements.map(u).join(", ")} )`;if(o>4)return`${this.getType(i)}()`;throw new Error(`NodeBuilder: Type '${i}' 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 r=this.attributes;for(const t of r)if(t.name===e)return t;const s=new vx(e,t);return r.push(s),s}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===y)return"int";if(t===f)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 r=gs(e);return("float"===t?"":t[0])+r}getTypeFromArray(e){return hT.get(e.constructor)}getTypeFromAttribute(e){let t=e;e.isInterleavedBufferAttribute&&(t=e.data);const r=t.array,s=e.itemSize,i=e.normalized;let n;return e instanceof Le||!0===i||(n=this.getTypeFromArray(r)),this.getTypeFromLength(s,n)}getTypeLength(e){const t=this.getVectorType(e),r=/vec([2-4])/.exec(t);return null!==r?Number(r[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=lm(this.stack),this.stacks.push(Ni()||this.stack),vi(this.stack),this.stack}removeStack(){const e=this.stack;return this.stack=e.parent,vi(this.stacks.pop()),e}getDataFromNode(e,t=this.shaderStage,r=null){let s=(r=null===r?e.isGlobal(this)?this.globalCache:this.cache:r).getData(e);return void 0===s&&(s={},r.setData(e,s)),void 0===s[t]&&(s[t]={}),s[t]}getNodeProperties(e,t="any"){const r=this.getDataFromNode(e,t);return r.properties||(r.properties={outputNode:null})}getBufferAttributeFromNode(e,t){const r=this.getDataFromNode(e);let s=r.bufferAttribute;if(void 0===s){const i=this.uniforms.index++;s=new vx("nodeAttribute"+i,t,e),this.bufferAttributes.push(s),r.bufferAttribute=s}return s}getStructTypeFromNode(e,t,r=this.shaderStage){const s=this.getDataFromNode(e,r);let i=s.structType;if(void 0===i){const e=this.structs.index++;i=new wx("StructType"+e,t),this.structs[r].push(i),s.structType=i}return i}getUniformFromNode(e,t,r=this.shaderStage,s=null){const i=this.getDataFromNode(e,r,this.globalCache);let n=i.uniform;if(void 0===n){const o=this.uniforms.index++;n=new Nx(s||"nodeUniform"+o,t,e),this.uniforms[r].push(n),i.uniform=n}return n}getVarFromNode(e,t=null,r=e.getNodeType(this),s=this.shaderStage){const i=this.getDataFromNode(e,s);let n=i.variable;if(void 0===n){const e=this.vars[s]||(this.vars[s]=[]);null===t&&(t="nodeVar"+e.length),n=new Sx(t,r),e.push(n),i.variable=n}return n}getVaryingFromNode(e,t=null,r=e.getNodeType(this)){const s=this.getDataFromNode(e,"any");let i=s.varying;if(void 0===i){const e=this.varyings,n=e.length;null===t&&(t="nodeVarying"+n),i=new Ax(t,r),e.push(i),s.varying=i}return i}getCodeFromNode(e,t,r=this.shaderStage){const s=this.getDataFromNode(e);let i=s.code;if(void 0===i){const e=this.codes[r]||(this.codes[r]=[]),n=e.length;i=new Rx("nodeCode"+n,t),e.push(i),s.code=i}return i}addFlowCodeHierarchy(e,t){const{flowCodes:r,flowCodeBlock:s}=this.getDataFromNode(e);let i=!0,n=t;for(;n;){if(!0===s.get(n)){i=!1;break}n=this.getDataFromNode(n).parentNodeBlock}if(i)for(const e of r)this.addLineFlowCode(e)}addLineFlowCodeBlock(e,t,r){const s=this.getDataFromNode(e),i=s.flowCodes||(s.flowCodes=[]),n=s.flowCodeBlock||(s.flowCodeBlock=new WeakMap);i.push(t),n.set(r,!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),r=this.flowChildNode(e,t);return this.flowsData.set(e,r),r}buildFunctionNode(e){const t=new oy,r=this.currentFunctionNode;return this.currentFunctionNode=t,t.code=this.buildFunctionCode(e),this.currentFunctionNode=r,t}flowShaderNode(e){const t=e.layout,r={[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)r[e.name]=new am(e.type,e.name);e.layout=null;const s=e.call(r),i=this.flowStagesNode(s,t.type);return e.layout=t,i}flowStagesNode(e,t=null){const r=this.flow,s=this.vars,i=this.cache,n=this.buildStage,o=this.stack,a={code:""};this.flow=a,this.vars={},this.cache=new Ex,this.stack=lm();for(const r of Rs)this.setBuildStage(r),a.result=e.build(this,t);return a.vars=this.getVars(this.shaderStage),this.flow=r,this.vars=s,this.cache=i,this.stack=o,this.setBuildStage(n),a}getFunctionOperator(){return null}flowChildNode(e,t=null){const r=this.flow,s={code:""};return this.flow=s,s.result=e.build(this,t),this.flow=r,s}flowNodeFromShaderStage(e,t,r=null,s=null){const i=this.shaderStage;this.setShaderStage(e);const n=this.flowChildNode(t,r);return null!==s&&(n.code+=`${this.tab+s} = ${n.result};\n`),this.flowCode[e]=this.flowCode[e]+n.code,this.setShaderStage(i),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 r=this.vars[e];if(void 0!==r)for(const e of r)t+=`${this.getVar(e.type,e.name)}; `;return t}getUniforms(){console.warn("Abstract function.")}getCodes(e){const t=this.codes[e];let r="";if(void 0!==t)for(const e of t)r+=e.code+"\n";return r}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:r}=this;if(null!==t){let e=r.library.fromMaterial(t);null===e&&(console.error(`NodeMaterial: Material "${t.type}" is not compatible.`),e=new Yc),e.build(this)}else this.addFlow("compute",e);for(const e of Rs){this.setBuildStage(e),this.context.vertex&&this.context.vertex.isNode&&this.flowNodeFromShaderStage("vertex",this.context.vertex);for(const t of Cs){this.setShaderStage(t);const r=this.flowNodes[t];for(const t of r)"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 Vx(e);if("vec2"===t||"ivec2"===t||"uvec2"===t)return new Ox(e);if("vec3"===t||"ivec3"===t||"uvec3"===t)return new Gx(e);if("vec4"===t||"ivec4"===t||"uvec4"===t)return new kx(e);if("color"===t)return new zx(e);if("mat3"===t)return new $x(e);if("mat4"===t)return new Hx(e);throw new Error(`Uniform "${t}" not declared.`)}format(e,t,r){if((t=this.getVectorType(t))===(r=this.getVectorType(r))||null===r||this.isReference(r))return e;const s=this.getTypeLength(t),i=this.getTypeLength(r);return 16===s&&9===i?`${this.getType(r)}(${e}[0].xyz, ${e}[1].xyz, ${e}[2].xyz)`:9===s&&4===i?`${this.getType(r)}(${e}[0].xy, ${e}[1].xy)`:s>4||i>4||0===i?e:s===i?`${this.getType(r)}( ${e} )`:s>i?this.format(`${e}.${"xyz".slice(0,i)}`,this.getTypeFromLength(i,this.getComponentType(t)),r):4===i&&s>1?`${this.getType(r)}( ${this.format(e,t,"vec3")}, 1.0 )`:2===s?`${this.getType(r)}( ${this.format(e,t,"vec2")}, 0.0 )`:(1===s&&i>1&&t!==this.getComponentType(r)&&(e=`${this.getType(this.getComponentType(r))}( ${e} )`),`${this.getType(r)}( ${e} )`)}getSignature(){return`// Three.js r${De} - Node System\n`}createNodeMaterial(e="NodeMaterial"){throw new Error(`THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${e}() instead.`)}}class mT{constructor(){this.time=0,this.deltaTime=0,this.frameId=0,this.renderId=0,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 r=e.get(t);return void 0===r&&(r={renderMap:new WeakMap,frameMap:new WeakMap},e.set(t,r)),r}updateBeforeNode(e){const t=e.getUpdateBeforeType(),r=e.updateReference(this);if(t===vs.FRAME){const{frameMap:t}=this._getMaps(this.updateBeforeMap,r);t.get(r)!==this.frameId&&!1!==e.updateBefore(this)&&t.set(r,this.frameId)}else if(t===vs.RENDER){const{renderMap:t}=this._getMaps(this.updateBeforeMap,r);t.get(r)!==this.renderId&&!1!==e.updateBefore(this)&&t.set(r,this.renderId)}else t===vs.OBJECT&&e.updateBefore(this)}updateAfterNode(e){const t=e.getUpdateAfterType(),r=e.updateReference(this);if(t===vs.FRAME){const{frameMap:t}=this._getMaps(this.updateAfterMap,r);t.get(r)!==this.frameId&&!1!==e.updateAfter(this)&&t.set(r,this.frameId)}else if(t===vs.RENDER){const{renderMap:t}=this._getMaps(this.updateAfterMap,r);t.get(r)!==this.renderId&&!1!==e.updateAfter(this)&&t.set(r,this.renderId)}else t===vs.OBJECT&&e.updateAfter(this)}updateNode(e){const t=e.getUpdateType(),r=e.updateReference(this);if(t===vs.FRAME){const{frameMap:t}=this._getMaps(this.updateMap,r);t.get(r)!==this.frameId&&!1!==e.update(this)&&t.set(r,this.frameId)}else if(t===vs.RENDER){const{renderMap:t}=this._getMaps(this.updateMap,r);t.get(r)!==this.renderId&&!1!==e.update(this)&&t.set(r,this.renderId)}else t===vs.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 fT{constructor(e,t,r=null,s="",i=!1){this.type=e,this.name=t,this.count=r,this.qualifier=s,this.isConst=i}}fT.isNodeFunctionInput=!0;class yT extends db{static get type(){return"DirectionalLightNode"}constructor(e=null){super(e)}setup(e){super.setup(e);const t=e.context.lightingModel,r=this.colorNode,s=Hy(this.light),i=e.context.reflectedLight;t.direct({lightDirection:s,lightColor:r,reflectedLight:i},e.stack,e)}}const bT=new n,xT=new n;let TT=null;class _T extends db{static get type(){return"RectAreaLightNode"}constructor(e=null){super(e),this.halfHeight=tn(new r).setGroup(Zi),this.halfWidth=tn(new r).setGroup(Zi),this.updateType=vs.RENDER}update(e){super.update(e);const{light:t}=this,r=e.camera.matrixWorldInverse;xT.identity(),bT.copy(t.matrixWorld),bT.premultiply(r),xT.extractRotation(bT),this.halfWidth.value.set(.5*t.width,0,0),this.halfHeight.value.set(0,.5*t.height,0),this.halfWidth.value.applyMatrix4(xT),this.halfHeight.value.applyMatrix4(xT)}setup(e){let t,r;super.setup(e),e.isAvailable("float32Filterable")?(t=xu(TT.LTC_FLOAT_1),r=xu(TT.LTC_FLOAT_2)):(t=xu(TT.LTC_HALF_1),r=xu(TT.LTC_HALF_2));const{colorNode:s,light:i}=this,n=e.context.lightingModel,o=$y(i),a=e.context.reflectedLight;n.directRectArea({lightColor:s,lightPosition:o,halfWidth:this.halfWidth,halfHeight:this.halfHeight,reflectedLight:a,ltc_1:t,ltc_2:r},e.stack,e)}static setLTC(e){TT=e}}class vT extends db{static get type(){return"SpotLightNode"}constructor(e=null){super(e),this.coneCosNode=tn(0).setGroup(Zi),this.penumbraCosNode=tn(0).setGroup(Zi),this.cutoffDistanceNode=tn(0).setGroup(Zi),this.decayExponentNode=tn(0).setGroup(Zi)}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:r}=this;return ga(t,r,e)}setup(e){super.setup(e);const t=e.context.lightingModel,{colorNode:r,cutoffDistanceNode:s,decayExponentNode:i,light:n}=this,o=$y(n).sub(Qu),a=o.normalize(),u=a.dot(Hy(n)),l=this.getSpotAttenuation(u),d=o.length(),c=cb({lightDistance:d,cutoffDistance:s,decayExponent:i});let h=r.mul(l).mul(c);if(n.map){const e=Gy(n),t=xu(n.map,e.xy).onRenderUpdate((()=>n.map));h=e.mul(2).sub(1).abs().lessThan(1).all().select(h.mul(t),h)}const p=e.context.reflectedLight;t.direct({lightDirection:a,lightColor:h,reflectedLight:p},e.stack,e)}}class NT extends vT{static get type(){return"IESSpotLightNode"}getSpotAttenuation(e){const t=this.light.iesMap;let r=null;if(t&&!0===t.isTexture){const s=e.acos().mul(1/Math.PI);r=xu(t,Bi(s,0),0).r}else r=super.getSpotAttenuation(e);return r}}class ST extends db{static get type(){return"AmbientLightNode"}constructor(e=null){super(e)}setup({context:e}){e.irradiance.addAssign(this.colorNode)}}class AT extends db{static get type(){return"HemisphereLightNode"}constructor(t=null){super(t),this.lightPositionNode=ky(t),this.lightDirectionNode=this.lightPositionNode.normalize(),this.groundColorNode=tn(new e).setGroup(Zi)}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:r,lightDirectionNode:s}=this,i=nl.dot(s).mul(.5).add(.5),n=da(r,t,i);e.context.irradiance.addAssign(n)}}class RT extends db{static get type(){return"LightProbeNode"}constructor(e=null){super(e);const t=[];for(let e=0;e<9;e++)t.push(new r);this.lightProbe=Nl(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=mx(ol,this.lightProbe);e.context.irradiance.addAssign(t)}}class CT{parseFunction(){console.warn("Abstract function.")}}class ET{constructor(e,t,r="",s=""){this.type=e,this.inputs=t,this.name=r,this.precision=s}getCode(){console.warn("Abstract function.")}}ET.isNodeFunction=!0;const wT=/^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i,MT=/[a-z_0-9]+/gi,BT="#pragma main";class UT extends ET{constructor(e){const{type:t,inputs:r,name:s,precision:i,inputsCode:n,blockCode:o,headerCode:a}=(e=>{const t=(e=e.trim()).indexOf(BT),r=-1!==t?e.slice(t+12):e,s=r.match(wT);if(null!==s&&5===s.length){const i=s[4],n=[];let o=null;for(;null!==(o=MT.exec(i));)n.push(o);const a=[];let u=0;for(;u0||e.backgroundBlurriness>0&&0===t.backgroundBlurriness;if(t.background!==r||s){let s=null;if(!0===r.isCubeTexture||r.mapping===j||r.mapping===q||r.mapping===Be)if(e.backgroundBlurriness>0||r.mapping===Be)s=qp(r);else{let e;e=!0===r.isCubeTexture?bl(r):xu(r),s=bh(e)}else!0===r.isTexture?s=xu(r,xc.flipY()).setUpdateMatrix(!0):!0!==r.isColor&&console.error("WebGPUNodes: Unsupported background configuration.",r);t.backgroundNode=s,t.background=r,t.backgroundBlurriness=e.backgroundBlurriness}}else t.backgroundNode&&(delete t.backgroundNode,delete t.background)}updateFog(e){const t=this.get(e),r=e.fog;if(r){if(t.fog!==r){let e=null;if(r.isFogExp2){const t=Rl("color","color",r).setGroup(Zi),s=Rl("density","float",r).setGroup(Zi);e=Ty(t,s)}else if(r.isFog){const t=Rl("color","color",r).setGroup(Zi),s=Rl("near","float",r).setGroup(Zi),i=Rl("far","float",r).setGroup(Zi);e=by(t,s,i)}else console.error("WebGPUNodes: Unsupported fog configuration.",r);t.fogNode=e,t.fog=r}}else delete t.fogNode,delete t.fog}updateEnvironment(e){const t=this.get(e),r=e.environment;if(r){if(t.environment!==r){let e=null;!0===r.isCubeTexture?e=bl(r):!0===r.isTexture?e=xu(r):console.error("Nodes: Unsupported environment configuration.",r),t.environmentNode=e,t.environment=r}}else t.environmentNode&&(delete t.environmentNode,delete t.environment)}getNodeFrame(e=this.renderer,t=null,r=null,s=null,i=null){const n=this.nodeFrame;return n.renderer=e,n.scene=t,n.object=r,n.camera=s,n.material=i,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 PT.get(e)!==this.getOutputCacheKey()}getOutputNode(e){const t=this.renderer,r=this.getOutputCacheKey(),s=xu(e,xc).renderOutput(t.toneMapping,t.currentColorSpace);return PT.set(e,r),s}updateBefore(e){const t=e.getNodeBuilderState();for(const r of t.updateBeforeNodes)this.getNodeFrameForRender(e).updateBeforeNode(r)}updateAfter(e){const t=e.getNodeBuilderState();for(const r of t.updateAfterNodes)this.getNodeFrameForRender(e).updateAfterNode(r)}updateForCompute(e){const t=this.getNodeFrame(),r=this.getForCompute(e);for(const e of r.updateNodes)t.updateNode(e)}updateForRender(e){const t=this.getNodeFrameForRender(e),r=e.getNodeBuilderState();for(const e of r.updateNodes)t.updateNode(e)}needsRefresh(e){const t=this.getNodeFrameForRender(e);return e.getMonitor().needsRefresh(e,t)}dispose(){super.dispose(),this.nodeFrame=new mT,this.nodeBuilderCache=new Map}}const LT=new me;class DT{constructor(e=null){this.version=0,this.clipIntersection=null,this.cacheKey="",null===e?(this.intersectionPlanes=[],this.unionPlanes=[],this.viewNormalMatrix=new i,this.clippingGroupContexts=new WeakMap,this.shadowPass=!1):(this.viewNormalMatrix=e.viewNormalMatrix,this.clippingGroupContexts=e.clippingGroupContexts,this.shadowPass=e.shadowPass,this.viewMatrix=e.viewMatrix),this.parentVersion=null}projectPlanes(e,t,r){const s=e.length;for(let i=0;i{await this.compileAsync(e,t);const s=this._renderLists.get(e,t),i=this._renderContexts.get(e,t,this._renderTarget),n=e.overrideMaterial||r.material,o=this._objects.get(r,n,e,t,s.lightsNode,i,i.clippingContext),{fragmentShader:a,vertexShader:u}=o.getNodeBuilderState();return{fragmentShader:a,vertexShader:u}}}}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 r=this.backend;try{await r.init(this)}catch(e){if(null===this._getFallback)return void t(e);try{this.backend=r=this._getFallback(e),await r.init(this)}catch(e){return void t(e)}}this._nodes=new IT(this,r),this._animation=new Ag(this._nodes,this.info),this._attributes=new Dg(r),this._background=new bx(this,this._nodes),this._geometries=new Gg(this._attributes,this.info),this._textures=new nm(this,r,this.info),this._pipelines=new qg(r,this._nodes),this._bindings=new Kg(r,this._nodes,this._textures,this._attributes,this._pipelines,this.info),this._objects=new Mg(this,this._nodes,this._geometries,this._pipelines,this._bindings,this.info),this._renderLists=new Jg(this.lighting),this._bundles=new OT,this._renderContexts=new sm,this._animation.start(),this._initialized=!0,e()}))),this._initPromise}get coordinateSystem(){return this.backend.coordinateSystem}async compileAsync(e,t,r=null){if(!0===this._isDeviceLost)return;!1===this._initialized&&await this.init();const s=this._nodes.nodeFrame,i=s.renderId,n=this._currentRenderContext,o=this._currentRenderObjectFunction,a=this._compilationPromises,u=!0===e.isScene?e:$T;null===r&&(r=e);const l=this._renderTarget,d=this._renderContexts.get(r,t,l),c=this._activeMipmapLevel,h=[];this._currentRenderContext=d,this._currentRenderObjectFunction=this.renderObject,this._handleObjectFunction=this._createObjectPipeline,this._compilationPromises=h,s.renderId++,s.update(),d.depth=this.depth,d.stencil=this.stencil,d.clippingContext||(d.clippingContext=new DT),d.clippingContext.updateGlobal(u,t),u.onBeforeRender(this,e,t,l);const p=this._renderLists.get(e,t);if(p.begin(),this._projectObject(e,t,0,p,d.clippingContext),r!==e&&r.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);d.textures=e.textures,d.depthTexture=e.depthTexture}else d.textures=null,d.depthTexture=null;this._nodes.updateScene(u),this._background.update(u,p,d);const g=p.opaque,m=p.transparent,f=p.transparentDoublePass,y=p.lightsNode;!0===this.opaque&&g.length>0&&this._renderObjects(g,t,u,y),!0===this.transparent&&m.length>0&&this._renderTransparents(m,f,t,u,y),s.renderId=i,this._currentRenderContext=n,this._currentRenderObjectFunction=o,this._compilationPromises=a,this._handleObjectFunction=this._renderObjectDirect,await Promise.all(h)}async renderAsync(e,t){!1===this._initialized&&await this.init();const r=this._renderScene(e,t);await this.backend.resolveTimestampAsync(r,"render")}async waitForGPU(){await this.backend.waitForGPU()}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}_onDeviceLost(e){let t=`THREE.WebGPURenderer: ${e.api} Device Lost:\n\nMessage: ${e.message}`;e.reason&&(t+=`\nReason: ${e.reason}`),console.error(t),this._isDeviceLost=!0}_renderBundle(e,t,r){const{bundleGroup:s,camera:i,renderList:n}=e,o=this._currentRenderContext,a=this._bundles.get(s,i),u=this.backend.get(a);void 0===u.renderContexts&&(u.renderContexts=new Set);const l=s.version!==u.version,d=!1===u.renderContexts.has(o)||l;if(u.renderContexts.add(o),d){this.backend.beginBundle(o),(void 0===u.renderObjects||l)&&(u.renderObjects=[]),this._currentRenderBundle=a;const e=n.opaque;!0===this.opaque&&e.length>0&&this._renderObjects(e,i,t,r),this._currentRenderBundle=null,this.backend.finishBundle(o,a),u.version=s.version}else{const{renderObjects:e}=u;for(let t=0,r=e.length;t>=c,p.viewportValue.height>>=c,p.viewportValue.minDepth=b,p.viewportValue.maxDepth=x,p.viewport=!1===p.viewportValue.equals(WT),p.scissorValue.copy(f).multiplyScalar(y).floor(),p.scissor=this._scissorTest&&!1===p.scissorValue.equals(WT),p.scissorValue.width>>=c,p.scissorValue.height>>=c,p.clippingContext||(p.clippingContext=new DT),p.clippingContext.updateGlobal(u,t),u.onBeforeRender(this,e,t,h),qT.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),jT.setFromProjectionMatrix(qT,g);const T=this._renderLists.get(e,t);if(T.begin(),this._projectObject(e,t,0,T,p.clippingContext),T.finish(),!0===this.sortObjects&&T.sort(this._opaqueSort,this._transparentSort),null!==h){this._textures.updateRenderTarget(h,c);const e=this._textures.get(h);p.textures=e.textures,p.depthTexture=e.depthTexture,p.width=e.width,p.height=e.height,p.renderTarget=h,p.depth=h.depthBuffer,p.stencil=h.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=d,p.activeMipmapLevel=c,p.occlusionQueryCount=T.occlusionQueryCount,this._nodes.updateScene(u),this._background.update(u,T,p),this.backend.beginRender(p);const{bundles:_,lightsNode:v,transparentDoublePass:N,transparent:S,opaque:A}=T;if(_.length>0&&this._renderBundles(_,u,v),!0===this.opaque&&A.length>0&&this._renderObjects(A,t,u,v),!0===this.transparent&&S.length>0&&this._renderTransparents(S,N,t,u,v),this.backend.finishRender(p),i.renderId=n,this._currentRenderContext=o,this._currentRenderObjectFunction=a,null!==s){this.setRenderTarget(l,d,c);const e=this._quad;this._nodes.hasOutputChange(h.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(h.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}return u.onAfterRender(this,e,t,h),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._pixelRatio=e,this.setSize(this._width,this._height,!1))}setDrawingBufferSize(e,t,r){this._width=e,this._height=t,this._pixelRatio=r,this.domElement.width=Math.floor(e*r),this.domElement.height=Math.floor(t*r),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setSize(e,t,r=!0){this._width=e,this._height=t,this.domElement.width=Math.floor(e*this._pixelRatio),this.domElement.height=Math.floor(t*this._pixelRatio),!0===r&&(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,r,s){const i=this._scissor;e.isVector4?i.copy(e):i.set(e,t,r,s)}getScissorTest(){return this._scissorTest}setScissorTest(e){this._scissorTest=e,this.backend.setScissorTest(e)}getViewport(e){return e.copy(this._viewport)}setViewport(e,t,r,s,i=0,n=1){const o=this._viewport;e.isVector4?o.copy(e):o.set(e,t,r,s),o.minDepth=i,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,r=!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,r);const s=this._renderTarget||this._getFrameBufferTarget();let i=null;if(null!==s&&(this._textures.updateRenderTarget(s),i=this._textures.get(s)),this.backend.clear(e,t,r,i),null!==s&&null===this._renderTarget){const e=this._quad;this._nodes.hasOutputChange(s.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(s.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,r=!0){!1===this._initialized&&await this.init(),this.clear(e,t,r)}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?d:this.toneMapping}get currentColorSpace(){return null!==this._renderTarget?Ae:this.outputColorSpace}dispose(){this.info.dispose(),this.backend.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,r=0){this._renderTarget=e,this._activeCubeFace=t,this._activeMipmapLevel=r}getRenderTarget(){return this._renderTarget}setRenderObjectFunction(e){this._renderObjectFunction=e}getRenderObjectFunction(){return this._renderObjectFunction}compute(e){if(!0===this.isDeviceLost)return;if(!1===this._initialized)return console.warn("THREE.Renderer: .compute() called before the backend is initialized. Try using .computeAsync() instead."),this.computeAsync(e);const t=this._nodes.nodeFrame,r=t.renderId;this.info.calls++,this.info.compute.calls++,this.info.compute.frameCalls++,t.renderId=this.info.calls;const s=this.backend,i=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.");s.beginCompute(e);for(const t of a){if(!1===i.has(t)){const e=()=>{t.removeEventListener("dispose",e),i.delete(t),n.delete(t),o.delete(t)};t.addEventListener("dispose",e);const r=t.onInitFunction;null!==r&&r.call(t,{renderer:this})}o.updateForCompute(t),n.updateForCompute(t);const r=n.getForCompute(t),a=i.getForCompute(t,r);s.compute(e,t,r,a)}s.finishCompute(e),t.renderId=r}async computeAsync(e){!1===this._initialized&&await this.init(),this.compute(e),await this.backend.resolveTimestampAsync(e,"compute")}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)}hasInitialized(){return this._initialized}async initTextureAsync(e){!1===this._initialized&&await this.init(),this._textures.updateTexture(e)}initTexture(e){if(!1===this._initialized)return console.warn("THREE.Renderer: .initTexture() called before the backend is initialized. Try using .initTextureAsync() instead."),!1;this._textures.updateTexture(e)}copyFramebufferToTexture(e,t=null){if(null!==t)if(t.isVector2)t=KT.set(t.x,t.y,e.image.width,e.image.height).floor();else{if(!t.isVector4)return void console.error("THREE.Renderer.copyFramebufferToTexture: Invalid rectangle.");t=KT.copy(t).floor()}else t=KT.set(0,0,e.image.width,e.image.height);let r,s=this._currentRenderContext;null!==s?r=s.renderTarget:(r=this._renderTarget||this._getFrameBufferTarget(),null!==r&&(this._textures.updateRenderTarget(r),s=this._textures.get(r))),this._textures.updateTexture(e,{renderTarget:r}),this.backend.copyFramebufferToTexture(e,s,t)}copyTextureToTexture(e,t,r=null,s=null,i=0){this._textures.updateTexture(e),this._textures.updateTexture(t),this.backend.copyTextureToTexture(e,t,r,s,i)}readRenderTargetPixelsAsync(e,t,r,s,i,n=0,o=0){return this.backend.copyTextureToBuffer(e.textures[n],t,r,s,i,o)}_projectObject(e,t,r,s,i){if(!1===e.visible)return;if(e.layers.test(t.layers))if(e.isGroup)r=e.renderOrder,e.isClippingGroup&&e.enabled&&(i=i.getGroupContext(e));else if(e.isLOD)!0===e.autoUpdate&&e.update(t);else if(e.isLight)s.pushLight(e);else if(e.isSprite){if(!e.frustumCulled||jT.intersectsSprite(e)){!0===this.sortObjects&&KT.setFromMatrixPosition(e.matrixWorld).applyMatrix4(qT);const{geometry:t,material:n}=e;n.visible&&s.push(e,t,n,r,KT.z,null,i)}}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||jT.intersectsObject(e))){const{geometry:t,material:n}=e;if(!0===this.sortObjects&&(null===t.boundingSphere&&t.computeBoundingSphere(),KT.copy(t.boundingSphere.center).applyMatrix4(e.matrixWorld).applyMatrix4(qT)),Array.isArray(n)){const o=t.groups;for(let a=0,u=o.length;a0){for(const{material:e}of t)e.side=x;this._renderObjects(t,r,s,i,"backSide");for(const{material:e}of t)e.side=Ge;this._renderObjects(e,r,s,i);for(const{material:e}of t)e.side=le}else this._renderObjects(e,r,s,i)}_renderObjects(e,t,r,s,i=null){for(let n=0,o=e.length;n0,e.isShadowNodeMaterial&&(e.side=null===i.shadowSide?i.side:i.shadowSide,i.depthNode&&i.depthNode.isNode&&(c=e.depthNode,e.depthNode=i.depthNode),i.castShadowNode&&i.castShadowNode.isNode&&(d=e.colorNode,e.colorNode=i.castShadowNode)),i=e}!0===i.transparent&&i.side===le&&!1===i.forceSinglePass?(i.side=x,this._handleObjectFunction(e,i,t,r,o,n,a,"backSide"),i.side=Ge,this._handleObjectFunction(e,i,t,r,o,n,a,u),i.side=le):this._handleObjectFunction(e,i,t,r,o,n,a,u),void 0!==l&&(t.overrideMaterial.positionNode=l),void 0!==c&&(t.overrideMaterial.depthNode=c),void 0!==d&&(t.overrideMaterial.colorNode=d),e.onAfterRender(this,t,r,s,i,n)}_renderObjectDirect(e,t,r,s,i,n,o,a){const u=this._objects.get(e,t,r,s,i,this._currentRenderContext,o,a);u.drawRange=e.geometry.drawRange,u.group=n;const l=this._nodes.needsRefresh(u);if(l&&(this._nodes.updateBefore(u),this._geometries.updateForRender(u),this._nodes.updateForRender(u),this._bindings.updateForRender(u)),this._pipelines.updateForRender(u),null!==this._currentRenderBundle){this.backend.get(this._currentRenderBundle).renderObjects.push(u),u.bundle=this._currentRenderBundle.scene}this.backend.draw(u,this.info),l&&this._nodes.updateAfter(u)}_createObjectPipeline(e,t,r,s,i,n,o){const a=this._objects.get(e,t,r,s,i,this._currentRenderContext,n,o);this._nodes.updateBefore(a),this._geometries.updateForRender(a),this._nodes.updateForRender(a),this._bindings.updateForRender(a),this._pipelines.getForRender(a,this._compilationPromises),this._nodes.updateAfter(a)}get compile(){return this.compileAsync}}class YT{constructor(e=""){this.name=e,this.visibility=0}setVisibility(e){this.visibility|=e}clone(){return Object.assign(new this.constructor,this)}}class QT extends YT{constructor(e,t=null){super(e),this.isBuffer=!0,this.bytesPerElement=Float32Array.BYTES_PER_ELEMENT,this._buffer=t}get byteLength(){return(e=this._buffer.byteLength)+(Lg-e%Lg)%Lg;var e}get buffer(){return this._buffer}update(){return!0}}class ZT extends QT{constructor(e,t=null){super(e,t),this.isUniformBuffer=!0}}let JT=0;class e_ extends ZT{constructor(e,t){super("UniformBuffer_"+JT++,e?e.value:null),this.nodeUniform=e,this.groupNode=t}get buffer(){return this.nodeUniform.value}}class t_ extends ZT{constructor(e){super(e),this.isUniformsGroup=!0,this._values=null,this.uniforms=[]}addUniform(e){return this.uniforms.push(e),this}removeUniform(e){const t=this.uniforms.indexOf(e);return-1!==t&&this.uniforms.splice(t,1),this}get values(){return null===this._values&&(this._values=Array.from(this.buffer)),this._values}get buffer(){let e=this._buffer;if(null===e){const t=this.byteLength;e=new Float32Array(new ArrayBuffer(t)),this._buffer=e}return e}get byteLength(){let e=0;for(let t=0,r=this.uniforms.length;t0?s:"";t=`${e.name} {\n\t${r} ${i.name}[${n}];\n};\n`}else{t=`${this.getVectorType(i.type)} ${this.getPropertyName(i,e)};`,n=!0}const o=i.node.precision;if(null!==o&&(t=d_[o]+" "+t),n){t="\t"+t;const e=i.groupNode.name;(s[e]||(s[e]=[])).push(t)}else t="uniform "+t,r.push(t)}let i="";for(const t in s){const r=s[t];i+=this._getGLSLUniformStruct(e+"_"+t,r.join("\n"))+"\n"}return i+=r.join("\n"),i}getTypeFromAttribute(e){let t=super.getTypeFromAttribute(e);if(/^[iu]/.test(t)&&e.gpuType!==y){let r=e;e.isInterleavedBufferAttribute&&(r=e.data);const s=r.array;!1==(s instanceof Uint32Array||s instanceof Int32Array)&&(t=t.slice(1))}return t}getAttributes(e){let t="";if("vertex"===e||"compute"===e){const e=this.getAttributesArray();let r=0;for(const s of e)t+=`layout( location = ${r++} ) in ${s.type} ${s.name};\n`}return t}getStructMembers(e){const t=[],r=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,r=this.shaderStage){const s=this.extensions[r]||(this.extensions[r]=new Map);!1===s.has(e)&&s.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 r=this.extensions[e];if(void 0!==r)for(const{name:e,behavior:s}of r.values())t.push(`#extension ${e} : ${s}`);return t.join("\n")}getClipDistance(){return"gl_ClipDistance"}isAvailable(e){let t=c_[e];if(void 0===t){let r;switch(t=!1,e){case"float32Filterable":r="OES_texture_float_linear";break;case"clipDistance":r="WEBGL_clip_cull_distance"}if(void 0!==r){const e=this.renderer.backend.extensions;e.has(r)&&(e.get(r),t=!0)}c_[e]=t}return t}isFlipY(){return!0}enableHardwareClipping(e){this.enableExtension("GL_ANGLE_clip_cull_distance","require"),this.builtins.vertex.push(`out float gl_ClipDistance[ ${e} ]`)}registerTransform(e,t){this.transforms.push({varyingName:e,attributeNode:t})}getTransforms(){const e=this.transforms;let t="";for(let r=0;r0&&(r+="\n"),r+=`\t// flow -> ${n}\n\t`),r+=`${s.code}\n\t`,e===i&&"compute"!==t&&(r+="// result\n\t","vertex"===t?(r+="gl_Position = ",r+=`${s.result};`):"fragment"===t&&(e.outputNode.isOutputStructNode||(r+="fragColor = ",r+=`${s.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=r}null!==this.material?(this.vertexShader=this._getGLSLVertexCode(e.vertex),this.fragmentShader=this._getGLSLFragmentCode(e.fragment)):this.computeShader=this._getGLSLVertexCode(e.compute)}getUniformFromNode(e,t,r,s=null){const i=super.getUniformFromNode(e,t,r,s),n=this.getDataFromNode(e,r,this.globalCache);let o=n.uniformGPU;if(void 0===o){const s=e.groupNode,a=s.name,u=this.getBindGroupArray(a,r);if("texture"===t)o=new o_(i.name,i.node,s),u.push(o);else if("cubeTexture"===t)o=new a_(i.name,i.node,s),u.push(o);else if("texture3D"===t)o=new u_(i.name,i.node,s),u.push(o);else if("buffer"===t){e.name=`NodeBuffer_${e.id}`,i.name=`buffer${e.id}`;const t=new e_(e,s);t.name=e.name,u.push(t),o=t}else{const e=this.uniformGroups[r]||(this.uniformGroups[r]={});let n=e[a];void 0===n&&(n=new s_(r+"_"+a,s),e[a]=n,u.push(n)),o=this.getNodeUniform(i,t),n.addUniform(o)}n.uniformGPU=o}return i}}let g_=null,m_=null,f_=null;class y_{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:r}=e;return r.isInstancedBufferGeometry?r.instanceCount:t.count>1?t.count:1}getDrawingBufferSize(){return g_=g_||new t,this.renderer.getDrawingBufferSize(g_)}getScissor(){return m_=m_||new s,this.renderer.getScissor(m_)}setScissorTest(){}getClearColor(){const e=this.renderer;return f_=f_||new om,e.getClearColor(f_),f_.getRGB(f_,this.renderer.currentColorSpace),f_}getDomElement(){let e=this.domElement;return null===e&&(e=void 0!==this.parameters.canvas?this.parameters.canvas:Ze(),"setAttribute"in e&&e.setAttribute("data-engine",`three.js r${De} webgpu`),this.domElement=e),e}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)}dispose(){}}let b_=0;class x_{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 T_{constructor(e){this.backend=e}createAttribute(e,t){const r=this.backend,{gl:s}=r,i=e.array,n=e.usage||s.STATIC_DRAW,o=e.isInterleavedBufferAttribute?e.data:e,a=r.get(o);let u,l=a.bufferGPU;if(void 0===l&&(l=this._createBuffer(s,t,i,n),a.bufferGPU=l,a.bufferType=t,a.version=o.version),i instanceof Float32Array)u=s.FLOAT;else if(i instanceof Uint16Array)u=e.isFloat16BufferAttribute?s.HALF_FLOAT:s.UNSIGNED_SHORT;else if(i instanceof Int16Array)u=s.SHORT;else if(i instanceof Uint32Array)u=s.UNSIGNED_INT;else if(i instanceof Int32Array)u=s.INT;else if(i instanceof Int8Array)u=s.BYTE;else if(i instanceof Uint8Array)u=s.UNSIGNED_BYTE;else{if(!(i instanceof Uint8ClampedArray))throw new Error("THREE.WebGLBackend: Unsupported buffer data format: "+i);u=s.UNSIGNED_BYTE}let d={bufferGPU:l,bufferType:t,type:u,byteLength:i.byteLength,bytesPerElement:i.BYTES_PER_ELEMENT,version:e.version,pbo:e.pbo,isInteger:u===s.INT||u===s.UNSIGNED_INT||e.gpuType===y,id:b_++};if(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute){const e=this._createBuffer(s,t,i,n);d=new x_(d,e)}r.set(e,d)}updateAttribute(e){const t=this.backend,{gl:r}=t,s=e.array,i=e.isInterleavedBufferAttribute?e.data:e,n=t.get(i),o=n.bufferType,a=e.isInterleavedBufferAttribute?e.data.updateRanges:e.updateRanges;if(r.bindBuffer(o,n.bufferGPU),0===a.length)r.bufferSubData(o,0,s);else{for(let e=0,t=a.length;e1?this.enable(s.SAMPLE_ALPHA_TO_COVERAGE):this.disable(s.SAMPLE_ALPHA_TO_COVERAGE),r>0&&this.currentClippingPlanes!==r){const e=12288;for(let t=0;t<8;t++)t{!function i(){const n=e.clientWaitSync(t,e.SYNC_FLUSH_COMMANDS_BIT,0);if(n===e.WAIT_FAILED)return e.deleteSync(t),void s();n!==e.TIMEOUT_EXPIRED?(e.deleteSync(t),r()):requestAnimationFrame(i)}()}))}}let R_,C_,E_,w_=!1;class M_{constructor(e){this.backend=e,this.gl=e.gl,this.extensions=e.extensions,this.defaultTextures={},!1===w_&&(this._init(this.gl),w_=!0)}_init(e){R_={[dr]:e.REPEAT,[cr]:e.CLAMP_TO_EDGE,[hr]:e.MIRRORED_REPEAT},C_={[pr]:e.NEAREST,[gr]:e.NEAREST_MIPMAP_NEAREST,[Ie]:e.NEAREST_MIPMAP_LINEAR,[$]:e.LINEAR,[Pe]:e.LINEAR_MIPMAP_NEAREST,[M]:e.LINEAR_MIPMAP_LINEAR},E_={[mr]:e.NEVER,[fr]:e.ALWAYS,[Re]:e.LESS,[yr]:e.LEQUAL,[br]:e.EQUAL,[xr]:e.GEQUAL,[Tr]:e.GREATER,[_r]:e.NOTEQUAL}}filterFallback(e){const{gl:t}=this;return e===pr||e===gr||e===Ie?t.NEAREST:t.LINEAR}getGLTextureType(e){const{gl:t}=this;let r;return r=!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,r}getInternalFormat(e,t,r,s,i=!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&&(r===n.FLOAT&&(a=n.R32F),r===n.HALF_FLOAT&&(a=n.R16F),r===n.UNSIGNED_BYTE&&(a=n.R8),r===n.UNSIGNED_SHORT&&(a=n.R16),r===n.UNSIGNED_INT&&(a=n.R32UI),r===n.BYTE&&(a=n.R8I),r===n.SHORT&&(a=n.R16I),r===n.INT&&(a=n.R32I)),t===n.RED_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.R8UI),r===n.UNSIGNED_SHORT&&(a=n.R16UI),r===n.UNSIGNED_INT&&(a=n.R32UI),r===n.BYTE&&(a=n.R8I),r===n.SHORT&&(a=n.R16I),r===n.INT&&(a=n.R32I)),t===n.RG&&(r===n.FLOAT&&(a=n.RG32F),r===n.HALF_FLOAT&&(a=n.RG16F),r===n.UNSIGNED_BYTE&&(a=n.RG8),r===n.UNSIGNED_SHORT&&(a=n.RG16),r===n.UNSIGNED_INT&&(a=n.RG32UI),r===n.BYTE&&(a=n.RG8I),r===n.SHORT&&(a=n.RG16I),r===n.INT&&(a=n.RG32I)),t===n.RG_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RG8UI),r===n.UNSIGNED_SHORT&&(a=n.RG16UI),r===n.UNSIGNED_INT&&(a=n.RG32UI),r===n.BYTE&&(a=n.RG8I),r===n.SHORT&&(a=n.RG16I),r===n.INT&&(a=n.RG32I)),t===n.RGB&&(r===n.FLOAT&&(a=n.RGB32F),r===n.HALF_FLOAT&&(a=n.RGB16F),r===n.UNSIGNED_BYTE&&(a=n.RGB8),r===n.UNSIGNED_SHORT&&(a=n.RGB16),r===n.UNSIGNED_INT&&(a=n.RGB32UI),r===n.BYTE&&(a=n.RGB8I),r===n.SHORT&&(a=n.RGB16I),r===n.INT&&(a=n.RGB32I),r===n.UNSIGNED_BYTE&&(a=s===Ve&&!1===i?n.SRGB8:n.RGB8),r===n.UNSIGNED_SHORT_5_6_5&&(a=n.RGB565),r===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1),r===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGB4),r===n.UNSIGNED_INT_5_9_9_9_REV&&(a=n.RGB9_E5)),t===n.RGB_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RGB8UI),r===n.UNSIGNED_SHORT&&(a=n.RGB16UI),r===n.UNSIGNED_INT&&(a=n.RGB32UI),r===n.BYTE&&(a=n.RGB8I),r===n.SHORT&&(a=n.RGB16I),r===n.INT&&(a=n.RGB32I)),t===n.RGBA&&(r===n.FLOAT&&(a=n.RGBA32F),r===n.HALF_FLOAT&&(a=n.RGBA16F),r===n.UNSIGNED_BYTE&&(a=n.RGBA8),r===n.UNSIGNED_SHORT&&(a=n.RGBA16),r===n.UNSIGNED_INT&&(a=n.RGBA32UI),r===n.BYTE&&(a=n.RGBA8I),r===n.SHORT&&(a=n.RGBA16I),r===n.INT&&(a=n.RGBA32I),r===n.UNSIGNED_BYTE&&(a=s===Ve&&!1===i?n.SRGB8_ALPHA8:n.RGBA8),r===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGBA4),r===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1)),t===n.RGBA_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RGBA8UI),r===n.UNSIGNED_SHORT&&(a=n.RGBA16UI),r===n.UNSIGNED_INT&&(a=n.RGBA32UI),r===n.BYTE&&(a=n.RGBA8I),r===n.SHORT&&(a=n.RGBA16I),r===n.INT&&(a=n.RGBA32I)),t===n.DEPTH_COMPONENT&&(r===n.UNSIGNED_INT&&(a=n.DEPTH24_STENCIL8),r===n.FLOAT&&(a=n.DEPTH_COMPONENT32F)),t===n.DEPTH_STENCIL&&r===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:r,extensions:s,backend:i}=this;r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,t.flipY),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,t.premultiplyAlpha),r.pixelStorei(r.UNPACK_ALIGNMENT,t.unpackAlignment),r.pixelStorei(r.UNPACK_COLORSPACE_CONVERSION_WEBGL,r.NONE),r.texParameteri(e,r.TEXTURE_WRAP_S,R_[t.wrapS]),r.texParameteri(e,r.TEXTURE_WRAP_T,R_[t.wrapT]),e!==r.TEXTURE_3D&&e!==r.TEXTURE_2D_ARRAY||r.texParameteri(e,r.TEXTURE_WRAP_R,R_[t.wrapR]),r.texParameteri(e,r.TEXTURE_MAG_FILTER,C_[t.magFilter]);const n=void 0!==t.mipmaps&&t.mipmaps.length>0,o=t.minFilter===$&&n?M:t.minFilter;if(r.texParameteri(e,r.TEXTURE_MIN_FILTER,C_[o]),t.compareFunction&&(r.texParameteri(e,r.TEXTURE_COMPARE_MODE,r.COMPARE_REF_TO_TEXTURE),r.texParameteri(e,r.TEXTURE_COMPARE_FUNC,E_[t.compareFunction])),!0===s.has("EXT_texture_filter_anisotropic")){if(t.magFilter===pr)return;if(t.minFilter!==Ie&&t.minFilter!==M)return;if(t.type===E&&!1===s.has("OES_texture_float_linear"))return;if(t.anisotropy>1){const n=s.get("EXT_texture_filter_anisotropic");r.texParameterf(e,n.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(t.anisotropy,i.getMaxAnisotropy()))}}}createDefaultTexture(e){const{gl:t,backend:r,defaultTextures:s}=this,i=this.getGLTextureType(e);let n=s[i];void 0===n&&(n=t.createTexture(),r.state.bindTexture(i,n),t.texParameteri(i,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(i,t.TEXTURE_MAG_FILTER,t.NEAREST),s[i]=n),r.set(e,{textureGPU:n,glTextureType:i,isDefault:!0})}createTexture(e,t){const{gl:r,backend:s}=this,{levels:i,width:n,height:o,depth:a}=t,u=s.utils.convert(e.format,e.colorSpace),l=s.utils.convert(e.type),d=this.getInternalFormat(e.internalFormat,u,l,e.colorSpace,e.isVideoTexture),c=r.createTexture(),h=this.getGLTextureType(e);s.state.bindTexture(h,c),this.setTextureParameters(h,e),e.isDataArrayTexture||e.isCompressedArrayTexture?r.texStorage3D(r.TEXTURE_2D_ARRAY,i,d,n,o,a):e.isData3DTexture?r.texStorage3D(r.TEXTURE_3D,i,d,n,o,a):e.isVideoTexture||r.texStorage2D(h,i,d,n,o),s.set(e,{textureGPU:c,glTextureType:h,glFormat:u,glType:l,glInternalFormat:d})}copyBufferToTexture(e,t){const{gl:r,backend:s}=this,{textureGPU:i,glTextureType:n,glFormat:o,glType:a}=s.get(t),{width:u,height:l}=t.source.data;r.bindBuffer(r.PIXEL_UNPACK_BUFFER,e),s.state.bindTexture(n,i),r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,!1),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),r.texSubImage2D(n,0,0,0,u,l,o,a,0),r.bindBuffer(r.PIXEL_UNPACK_BUFFER,null),s.state.unbindTexture()}updateTexture(e,t){const{gl:r}=this,{width:s,height:i}=t,{textureGPU:n,glTextureType:o,glFormat:a,glType:u,glInternalFormat:l}=this.backend.get(e);if(e.isRenderTargetTexture||void 0===n)return;const d=e=>e.isDataTexture?e.image.data:"undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap||e instanceof OffscreenCanvas?e:e.data;if(this.backend.state.bindTexture(o,n),this.setTextureParameters(o,e),e.isCompressedTexture){const s=e.mipmaps,i=t.image;for(let t=0;t0,c=t.renderTarget?t.renderTarget.height:this.backend.gerDrawingBufferSize().y;if(d){const r=0!==o||0!==a;let d,h;if(!0===e.isDepthTexture?(d=s.DEPTH_BUFFER_BIT,h=s.DEPTH_ATTACHMENT,t.stencil&&(d|=s.STENCIL_BUFFER_BIT)):(d=s.COLOR_BUFFER_BIT,h=s.COLOR_ATTACHMENT0),r){const e=this.backend.get(t.renderTarget),r=e.framebuffers[t.getCacheKey()],h=e.msaaFrameBuffer;i.bindFramebuffer(s.DRAW_FRAMEBUFFER,r),i.bindFramebuffer(s.READ_FRAMEBUFFER,h);const p=c-a-l;s.blitFramebuffer(o,p,o+u,p+l,o,p,o+u,p+l,d,s.NEAREST),i.bindFramebuffer(s.READ_FRAMEBUFFER,r),i.bindTexture(s.TEXTURE_2D,n),s.copyTexSubImage2D(s.TEXTURE_2D,0,0,0,o,p,u,l),i.unbindTexture()}else{const e=s.createFramebuffer();i.bindFramebuffer(s.DRAW_FRAMEBUFFER,e),s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,h,s.TEXTURE_2D,n,0),s.blitFramebuffer(0,0,u,l,0,0,u,l,d,s.NEAREST),s.deleteFramebuffer(e)}}else i.bindTexture(s.TEXTURE_2D,n),s.copyTexSubImage2D(s.TEXTURE_2D,0,0,0,o,c-l-a,u,l),i.unbindTexture();e.generateMipmaps&&this.generateMipmaps(e),this.backend._setFramebuffer(t)}setupRenderBufferStorage(e,t){const{gl:r}=this,s=t.renderTarget,{samples:i,depthTexture:n,depthBuffer:o,stencilBuffer:a,width:u,height:l}=s;if(r.bindRenderbuffer(r.RENDERBUFFER,e),o&&!a){let t=r.DEPTH_COMPONENT24;i>0?(n&&n.isDepthTexture&&n.type===r.FLOAT&&(t=r.DEPTH_COMPONENT32F),r.renderbufferStorageMultisample(r.RENDERBUFFER,i,t,u,l)):r.renderbufferStorage(r.RENDERBUFFER,t,u,l),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,e)}else o&&a&&(i>0?r.renderbufferStorageMultisample(r.RENDERBUFFER,i,r.DEPTH24_STENCIL8,u,l):r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_STENCIL,u,l),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,e))}async copyTextureToBuffer(e,t,r,s,i,n){const{backend:o,gl:a}=this,{textureGPU:u,glFormat:l,glType:d}=this.backend.get(e),c=a.createFramebuffer();a.bindFramebuffer(a.READ_FRAMEBUFFER,c);const h=e.isCubeTexture?a.TEXTURE_CUBE_MAP_POSITIVE_X+n:a.TEXTURE_2D;a.framebufferTexture2D(a.READ_FRAMEBUFFER,a.COLOR_ATTACHMENT0,h,u,0);const p=this._getTypedArrayType(d),g=s*i*this._getBytesPerTexel(d,l),m=a.createBuffer();a.bindBuffer(a.PIXEL_PACK_BUFFER,m),a.bufferData(a.PIXEL_PACK_BUFFER,g,a.STREAM_READ),a.readPixels(t,r,s,i,l,d,0),a.bindBuffer(a.PIXEL_PACK_BUFFER,null),await o.utils._clientWaitAsync();const f=new p(g/p.BYTES_PER_ELEMENT);return a.bindBuffer(a.PIXEL_PACK_BUFFER,m),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:r}=this;let s=0;return e===r.UNSIGNED_BYTE&&(s=1),e!==r.UNSIGNED_SHORT_4_4_4_4&&e!==r.UNSIGNED_SHORT_5_5_5_1&&e!==r.UNSIGNED_SHORT_5_6_5&&e!==r.UNSIGNED_SHORT&&e!==r.HALF_FLOAT||(s=2),e!==r.UNSIGNED_INT&&e!==r.FLOAT||(s=4),t===r.RGBA?4*s:t===r.RGB?3*s:t===r.ALPHA?s:void 0}}class B_{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 U_{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 r=t.get("EXT_texture_filter_anisotropic");this.maxAnisotropy=e.getParameter(r.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else this.maxAnisotropy=0;return this.maxAnisotropy}}const F_={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 P_{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:r,mode:s,object:i,type:n,info:o,index:a}=this;0!==a?r.drawElements(s,t,n,e):r.drawArrays(s,e,t),o.update(i,t,s,1)}renderInstances(e,t,r){const{gl:s,mode:i,type:n,index:o,object:a,info:u}=this;0!==r&&(0!==o?s.drawElementsInstanced(i,t,n,e,r):s.drawArraysInstanced(i,e,t,r),u.update(a,t,i,r))}renderMultiDraw(e,t,r){const{extensions:s,mode:i,object:n,info:o}=this;if(0===r)return;const a=s.get("WEBGL_multi_draw");if(null===a)for(let s=0;s0)){const e=t.queryQueue.shift();this.initTimestampQuery(e)}}async resolveTimestampAsync(e,t="render"){if(!this.disjoint||!this.trackTimestamp)return;const r=this.get(e);r.gpuQueries||(r.gpuQueries=[]);for(let e=0;e0&&(r.currentOcclusionQueries=r.occlusionQueries,r.currentOcclusionQueryObjects=r.occlusionQueryObjects,r.lastOcclusionObject=null,r.occlusionQueries=new Array(s),r.occlusionQueryObjects=new Array(s),r.occlusionQueryIndex=0)}finishRender(e){const{gl:t,state:r}=this,s=this.get(e),i=s.previousContext,n=e.occlusionQueryCount;n>0&&(n>s.occlusionQueryIndex&&t.endQuery(t.ANY_SAMPLES_PASSED),this.resolveOccludedAsync(e));const o=e.textures;if(null!==o)for(let e=0;e0){const i=s.framebuffers[e.getCacheKey()],n=t.COLOR_BUFFER_BIT,o=s.msaaFrameBuffer,a=e.textures;r.bindFramebuffer(t.READ_FRAMEBUFFER,o),r.bindFramebuffer(t.DRAW_FRAMEBUFFER,i);for(let r=0;r{let o=0;for(let t=0;t0&&e.add(s[t]),r[t]=null,i.deleteQuery(n),o++))}o1?f.renderInstances(x,y,b):f.render(x,y),a.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,r,s,i,n){return this.textureUtils.copyTextureToBuffer(e,t,r,s,i,n)}createSampler(){}destroySampler(){}createNodeBuilder(e,t){return new p_(e,t)}createProgram(e){const t=this.gl,{stage:r,code:s}=e,i="fragment"===r?t.createShader(t.FRAGMENT_SHADER):t.createShader(t.VERTEX_SHADER);t.shaderSource(i,s),t.compileShader(i),this.set(e,{shaderGPU:i})}destroyProgram(){console.warn("Abstract class.")}createRenderPipeline(e,t){const r=this.gl,s=e.pipeline,{fragmentProgram:i,vertexProgram:n}=s,o=r.createProgram(),a=this.get(i).shaderGPU,u=this.get(n).shaderGPU;if(r.attachShader(o,a),r.attachShader(o,u),r.linkProgram(o),this.set(s,{programGPU:o,fragmentShader:a,vertexShader:u}),null!==t&&this.parallel){const i=new Promise((t=>{const i=this.parallel,n=()=>{r.getProgramParameter(o,i.COMPLETION_STATUS_KHR)?(this._completeCompile(e,s),t()):requestAnimationFrame(n)};n()}));t.push(i)}else this._completeCompile(e,s)}_handleSource(e,t){const r=e.split("\n"),s=[],i=Math.max(t-6,0),n=Math.min(t+6,r.length);for(let e=i;e":" "} ${i}: ${r[e]}`)}return s.join("\n")}_getShaderErrors(e,t,r){const s=e.getShaderParameter(t,e.COMPILE_STATUS),i=e.getShaderInfoLog(t).trim();if(s&&""===i)return"";const n=/ERROR: 0:(\d+)/.exec(i);if(n){const s=parseInt(n[1]);return r.toUpperCase()+"\n\n"+i+"\n\n"+this._handleSource(e.getShaderSource(t),s)}return i}_logProgramError(e,t,r){if(this.renderer.debug.checkShaderErrors){const s=this.gl,i=s.getProgramInfoLog(e).trim();if(!1===s.getProgramParameter(e,s.LINK_STATUS))if("function"==typeof this.renderer.debug.onShaderError)this.renderer.debug.onShaderError(s,e,r,t);else{const n=this._getShaderErrors(s,r,"vertex"),o=this._getShaderErrors(s,t,"fragment");console.error("THREE.WebGLProgram: Shader Error "+s.getError()+" - VALIDATE_STATUS "+s.getProgramParameter(e,s.VALIDATE_STATUS)+"\n\nProgram Info Log: "+i+"\n"+n+"\n"+o)}else""!==i&&console.warn("THREE.WebGLProgram: Program Info Log:",i)}}_completeCompile(e,t){const{state:r,gl:s}=this,i=this.get(t),{programGPU:n,fragmentShader:o,vertexShader:a}=i;!1===s.getProgramParameter(n,s.LINK_STATUS)&&this._logProgramError(n,o,a),r.useProgram(n);const u=e.getBindings();this._setupBindings(u,n),this.set(t,{programGPU:n})}createComputePipeline(e,t){const{state:r,gl:s}=this,i={stage:"fragment",code:"#version 300 es\nprecision highp float;\nvoid main() {}"};this.createProgram(i);const{computeProgram:n}=e,o=s.createProgram(),a=this.get(i).shaderGPU,u=this.get(n).shaderGPU,l=n.transforms,d=[],c=[];for(let e=0;eF_[t]===e)),r=this.extensions;for(let e=0;e0){if(void 0===d){const s=[];d=t.createFramebuffer(),r.bindFramebuffer(t.FRAMEBUFFER,d);const i=[],l=e.textures;for(let r=0;r,\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:G_,stripIndexFormat:sv},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:G_,stripIndexFormat:sv},layout:"auto"}),this.flipYPipelines[e]=t),t}flipY(e,t,r=0){const s=t.format,{width:i,height:n}=t.size,o=this.getTransferPipeline(s),a=this.getFlipYPipeline(s),u=this.device.createTexture({size:{width:i,height:n,depthOrArrayLayers:1},format:s,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),l=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:Yv,baseArrayLayer:r}),d=u.createView({baseMipLevel:0,mipLevelCount:1,dimension:Yv,baseArrayLayer:0}),c=this.device.createCommandEncoder({}),h=(e,t,r)=>{const s=e.getBindGroupLayout(0),i=this.device.createBindGroup({layout:s,entries:[{binding:0,resource:this.flipYSampler},{binding:1,resource:t}]}),n=c.beginRenderPass({colorAttachments:[{view:r,loadOp:Q_,storeOp:X_,clearValue:[0,0,0,0]}]});n.setPipeline(e),n.setBindGroup(0,i),n.draw(4,1,0,0),n.end()};h(o,l,d),h(a,d,l),this.device.queue.submit([c.finish()]),u.destroy()}generateMipmaps(e,t,r=0){const s=this.get(e);void 0===s.useCount&&(s.useCount=0,s.layers=[]);const i=s.layers[r]||this._mipmapCreateBundles(e,t,r),n=this.device.createCommandEncoder({});this._mipmapRunBundles(n,i),this.device.queue.submit([n.finish()]),0!==s.useCount&&(s.layers[r]=i),s.useCount++}_mipmapCreateBundles(e,t,r){const s=this.getTransferPipeline(t.format),i=s.getBindGroupLayout(0);let n=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:Yv,baseArrayLayer:r});const o=[];for(let a=1;a1;for(let o=0;o]*\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/i,mN=/([a-z_0-9]+)\s*:\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/gi,fN={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 yN extends ET{constructor(e){const{type:t,inputs:r,name:s,inputsCode:i,blockCode:n,outputType:o}=(e=>{const t=(e=e.trim()).match(gN);if(null!==t&&4===t.length){const r=t[2],s=[];let i=null;for(;null!==(i=mN.exec(r));)s.push({name:i[1],type:i[2]});const n=[];for(let e=0;e "+this.outputType:"";return`fn ${e} ( ${this.inputsCode.trim()} ) ${t}`+this.blockCode}}class bN extends CT{parseFunction(e){return new yN(e)}}const xN="undefined"!=typeof self?self.GPUShaderStage:{VERTEX:1,FRAGMENT:2,COMPUTE:4},TN={[Ss.READ_ONLY]:"read",[Ss.WRITE_ONLY]:"write",[Ss.READ_WRITE]:"read_write"},_N={[dr]:"repeat",[cr]:"clamp",[hr]:"mirror"},vN={vertex:xN?xN.VERTEX:1,fragment:xN?xN.FRAGMENT:2,compute:xN?xN.COMPUTE:4},NN={instance:!0,swizzleAssign:!1,storageBuffer:!0},SN={"^^":"tsl_xor"},AN={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",mat3:"mat3x3",mat4:"mat4x4"},RN={},CN={tsl_xor:new iy("fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }"),mod_float:new iy("fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }"),mod_vec2:new iy("fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }"),mod_vec3:new iy("fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }"),mod_vec4:new iy("fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }"),equals_bool:new iy("fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }"),equals_bvec2:new iy("fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }"),equals_bvec3:new iy("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 iy("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_float:new iy("fn tsl_repeatWrapping_float( coord: f32 ) -> f32 { return fract( coord ); }"),mirrorWrapping_float:new iy("fn tsl_mirrorWrapping_float( coord: f32 ) -> f32 { let mirrored = fract( coord * 0.5 ) * 2.0; return 1.0 - abs( 1.0 - mirrored ); }"),clampWrapping_float:new iy("fn tsl_clampWrapping_float( coord: f32 ) -> f32 { return clamp( coord, 0.0, 1.0 ); }"),biquadraticTexture:new iy("\nfn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, iRes : vec2u, level : u32 ) -> vec4f {\n\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, vec2u( iuv + vec2( 0.5, 0.5 ) ) % iRes, level );\n\tlet rg2 = textureLoad( map, vec2u( iuv + vec2( 1.5, 0.5 ) ) % iRes, level );\n\tlet rg3 = textureLoad( map, vec2u( iuv + vec2( 0.5, 1.5 ) ) % iRes, level );\n\tlet rg4 = textureLoad( map, vec2u( 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")},EN={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"};"undefined"!=typeof navigator&&/Windows/g.test(navigator.userAgent)&&(CN.pow_float=new iy("fn tsl_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }"),CN.pow_vec2=new iy("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 ) ); }",[CN.pow_float]),CN.pow_vec3=new iy("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 ) ); }",[CN.pow_float]),CN.pow_vec4=new iy("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 ) ); }",[CN.pow_float]),EN.pow_float="tsl_pow_float",EN.pow_vec2="tsl_pow_vec2",EN.pow_vec3="tsl_pow_vec3",EN.pow_vec4="tsl_pow_vec4");let wN="";!0!==("undefined"!=typeof navigator&&/Firefox|Deno/g.test(navigator.userAgent))&&(wN+="diagnostic( off, derivative_uniformity );\n");class MN extends gT{constructor(e,t){super(e,t,new bN),this.uniformGroups={},this.builtins={},this.directives={},this.scopedArrays=new Map}needsToWorkingColorSpace(e){return!0===e.isVideoTexture&&e.colorSpace!==m}_generateTextureSample(e,t,r,s,i=this.shaderStage){return"fragment"===i?s?`textureSample( ${t}, ${t}_sampler, ${r}, ${s} )`:`textureSample( ${t}, ${t}_sampler, ${r} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,r):this.generateTextureLod(e,t,r,s,"0")}_generateVideoSample(e,t,r=this.shaderStage){if("fragment"===r)return`textureSampleBaseClampToEdge( ${e}, ${e}_sampler, vec2( ${t}.x, 1.0 - ${t}.y ) )`;console.error(`WebGPURenderer: THREE.VideoTexture does not support ${r} shader.`)}_generateTextureSampleLevel(e,t,r,s,i,n=this.shaderStage){return"fragment"!==n&&"compute"!==n||!1!==this.isUnfilterable(e)?this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,r,s):this.generateTextureLod(e,t,r,i,s):`textureSampleLevel( ${t}, ${t}_sampler, ${r}, ${s} )`}generateWrapFunction(e){const t=`tsl_coord_${_N[e.wrapS]}S_${_N[e.wrapT]}T`;let r=RN[t];if(void 0===r){const s=[];let i=`fn ${t}( coord : vec2f ) -> vec2f {\n\n\treturn vec2f(\n`;const n=(e,t)=>{e===dr?(s.push(CN.repeatWrapping_float),i+=`\t\ttsl_repeatWrapping_float( coord.${t} )`):e===cr?(s.push(CN.clampWrapping_float),i+=`\t\ttsl_clampWrapping_float( coord.${t} )`):e===hr?(s.push(CN.mirrorWrapping_float),i+=`\t\ttsl_mirrorWrapping_float( coord.${t} )`):(i+=`\t\tcoord.${t}`,console.warn(`WebGPURenderer: Unsupported texture wrap type "${e}" for vertex shader.`))};n(e.wrapS,"x"),i+=",\n",n(e.wrapT,"y"),i+="\n\t);\n\n}\n",RN[t]=r=new iy(i,s)}return r.build(this),t}generateTextureDimension(e,t,r){const s=this.getDataFromNode(e,this.shaderStage,this.globalCache);void 0===s.dimensionsSnippet&&(s.dimensionsSnippet={});let i=s.dimensionsSnippet[r];if(void 0===s.dimensionsSnippet[r]){let n;const{primarySamples:o}=this.renderer.backend.utils.getTextureSampleData(e);n=o>1?t:`${t}, u32( ${r} )`,i=new Aa(new ou(`textureDimensions( ${n} )`,"uvec2")),s.dimensionsSnippet[r]=i}return i.build(this)}generateFilteredTexture(e,t,r,s="0u"){this._include("biquadraticTexture");return`tsl_biquadraticTexture( ${t}, ${this.generateWrapFunction(e)}( ${r} ), ${this.generateTextureDimension(e,t,s)}, u32( ${s} ) )`}generateTextureLod(e,t,r,s,i="0u"){const n=`vec2u( ${this.generateWrapFunction(e)}( ${r} ) * vec2f( ${this.generateTextureDimension(e,t,i)} ) )`;return this.generateTextureLoad(e,t,n,s,i)}generateTextureLoad(e,t,r,s,i="0u"){return!0===e.isVideoTexture||!0===e.isStorageTexture?`textureLoad( ${t}, ${r} )`:s?`textureLoad( ${t}, ${r}, ${s}, u32( ${i} ) )`:`textureLoad( ${t}, ${r}, u32( ${i} ) )`}generateTextureStore(e,t,r,s){return`textureStore( ${t}, ${r}, ${s} )`}isSampleCompare(e){return!0===e.isDepthTexture&&null!==e.compareFunction}isUnfilterable(e){return"float"!==this.getComponentTypeFromTexture(e)||!this.isAvailable("float32Filterable")&&!0===e.isDataTexture&&e.type===E||!1===this.isSampleCompare(e)&&e.minFilter===pr&&e.magFilter===pr||this.renderer.backend.utils.getTextureSampleData(e).primarySamples>1}generateTexture(e,t,r,s,i=this.shaderStage){let n=null;return n=!0===e.isVideoTexture?this._generateVideoSample(t,r,i):this.isUnfilterable(e)?this.generateTextureLod(e,t,r,s,"0",i):this._generateTextureSample(e,t,r,s,i),n}generateTextureGrad(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleGrad( ${t}, ${t}_sampler, ${r}, ${s[0]}, ${s[1]} )`;console.error(`WebGPURenderer: THREE.TextureNode.gradient() does not support ${n} shader.`)}generateTextureCompare(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleCompare( ${t}, ${t}_sampler, ${r}, ${s} )`;console.error(`WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${n} shader.`)}generateTextureLevel(e,t,r,s,i,n=this.shaderStage){let o=null;return o=!0===e.isVideoTexture?this._generateVideoSample(t,r,n):this._generateTextureSampleLevel(e,t,r,s,i,n),o}generateTextureBias(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleBias( ${t}, ${t}_sampler, ${r}, ${s} )`;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,r=e.type;return"texture"===r||"cubeTexture"===r||"storageTexture"===r||"texture3D"===r?t:"buffer"===r||"storageBuffer"===r||"indirectStorageBuffer"===r?`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=SN[e];return void 0!==t?(this._include(t),t):null}getNodeAccess(e,t){return"compute"!==t?Ss.READ_ONLY:e.access}getStorageAccess(e,t){return TN[this.getNodeAccess(e,t)]}getUniformFromNode(e,t,r,s=null){const i=super.getUniformFromNode(e,t,r,s),n=this.getDataFromNode(e,r,this.globalCache);if(void 0===n.uniformGPU){let s;const o=e.groupNode,a=o.name,u=this.getBindGroupArray(a,r);if("texture"===t||"cubeTexture"===t||"storageTexture"===t||"texture3D"===t){let n=null;const a=this.getNodeAccess(e,r);if("texture"===t||"storageTexture"===t?n=new o_(i.name,i.node,o,a):"cubeTexture"===t?n=new a_(i.name,i.node,o,a):"texture3D"===t&&(n=new u_(i.name,i.node,o,a)),n.store=!0===e.isStorageTextureNode,n.setVisibility(vN[r]),"fragment"!==r&&"compute"!==r||!1!==this.isUnfilterable(e.value)||!1!==n.store)u.push(n),s=[n];else{const e=new nN(`${i.name}_sampler`,i.node,o);e.setVisibility(vN[r]),u.push(e,n),s=[e,n]}}else if("buffer"===t||"storageBuffer"===t||"indirectStorageBuffer"===t){const i=new("buffer"===t?e_:uN)(e,o);i.setVisibility(vN[r]),u.push(i),s=i}else{const e=this.uniformGroups[r]||(this.uniformGroups[r]={});let n=e[a];void 0===n&&(n=new s_(a,o),n.setVisibility(vN[r]),e[a]=n,u.push(n)),s=this.getNodeUniform(i,t),n.addUniform(s)}n.uniformGPU=s}return i}getBuiltin(e,t,r,s=this.shaderStage){const i=this.builtins[s]||(this.builtins[s]=new Map);return!1===i.has(e)&&i.set(e,{name:e,property:t,type:r}),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,r=this.flowShaderNode(e),s=[];for(const e of t.inputs)s.push(e.name+" : "+this.getType(e.type));let i=`fn ${t.name}( ${s.join(", ")} ) -> ${this.getType(t.type)} {\n${r.vars}\n${r.code}\n`;return r.result&&(i+=`\treturn ${r.result};\n`),i+="\n}\n",i}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")}getClipDistance(){return"varyings.hw_clip_distances"}isFlipY(){return!1}enableDirective(e,t=this.shaderStage){(this.directives[t]||(this.directives[t]=new Set)).add(e)}getDirectives(e){const t=[],r=this.directives[e];if(void 0!==r)for(const e of r)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")}enableHardwareClipping(e){this.enableClipDistances(),this.getBuiltin("clip_distances","hw_clip_distances",`array`,"vertex")}getBuiltins(e){const t=[],r=this.builtins[e];if(void 0!==r)for(const{name:e,property:s,type:i}of r.values())t.push(`@builtin( ${e} ) ${s} : ${i}`);return t.join(",\n\t")}getScopedArray(e,t,r,s){return!1===this.scopedArrays.has(e)&&this.scopedArrays.set(e,{name:e,scope:t,bufferType:r,bufferCount:s}),e}getScopedArrays(e){if("compute"!==e)return;const t=[];for(const{name:e,scope:r,bufferType:s,bufferCount:i}of this.scopedArrays.values()){const n=this.getType(s);t.push(`var<${r}> ${e}: array< ${n}, ${i} >;`)}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 r=this.getAttributesArray();for(let e=0,s=r.length;e`)}const s=this.getBuiltins("output");return s&&t.push("\t"+s),t.join(",\n")}getStructs(e){const t=[],r=this.structs[e];for(let e=0,s=r.length;e output : ${i};\n\n`)}return t.join("\n\n")}getVar(e,t){return`var ${t} : ${this.getType(e)}`}getVars(e){const t=[],r=this.vars[e];if(void 0!==r)for(const e of r)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 r=this.varyings,s=this.vars[e];for(let i=0;i1&&(n="_multisampled"),!0===t.isCubeTexture)s="texture_cube";else if(!0===t.isDataArrayTexture||!0===t.isCompressedArrayTexture)s="texture_2d_array";else if(!0===t.isDepthTexture)s=`texture_depth${n}_2d`;else if(!0===t.isVideoTexture)s="texture_external";else if(!0===t.isData3DTexture)s="texture_3d";else if(!0===i.node.isStorageTextureNode){s=`texture_storage_2d<${pN(t)}, ${this.getStorageAccess(i.node,e)}>`}else{s=`texture${n}_2d<${this.getComponentTypeFromTexture(t).charAt(0)}32>`}r.push(`@binding( ${o.binding++} ) @group( ${o.group} ) var ${i.name} : ${s};`)}else if("buffer"===i.type||"storageBuffer"===i.type||"indirectStorageBuffer"===i.type){const t=i.node,r=this.getType(t.bufferType),n=t.bufferCount,a=n>0&&"buffer"===i.type?", "+n:"",u=t.isAtomic?`atomic<${r}>`:`${r}`,l=`\t${i.name} : array< ${u}${a} >\n`,d=t.isStorageBufferNode?`storage, ${this.getStorageAccess(t,e)}`:"uniform";s.push(this._getWGSLStructBinding("NodeBuffer_"+t.id,l,d,o.binding++,o.group))}else{const e=this.getType(this.getVectorType(i.type)),t=i.groupNode.name;(n[t]||(n[t]={index:o.binding++,id:o.group,snippets:[]})).snippets.push(`\t${i.name} : ${e}`)}}for(const e in n){const t=n[e];i.push(this._getWGSLStructBinding(e,t.snippets.join(",\n"),"uniform",t.index,t.id))}let o=r.join("\n");return o+=s.join("\n"),o+=i.join("\n"),o}buildCode(){const e=null!==this.material?{fragment:{},vertex:{}}:{compute:{}};this.sortBindingGroups();for(const t in e){const r=e[t];r.uniforms=this.getUniforms(t),r.attributes=this.getAttributes(t),r.varyings=this.getVaryings(t),r.structs=this.getStructs(t),r.vars=this.getVars(t),r.codes=this.getCodes(t),r.directives=this.getDirectives(t),r.scopedArrays=this.getScopedArrays(t);let s="// code\n\n";s+=this.flowCode[t];const i=this.flowNodes[t],n=i[i.length-1],o=n.outputNode,a=void 0!==o&&!0===o.isOutputStructNode;for(const e of i){const i=this.getFlowData(e),u=e.name;if(u&&(s.length>0&&(s+="\n"),s+=`\t// flow -> ${u}\n\t`),s+=`${i.code}\n\t`,e===n&&"compute"!==t)if(s+="// result\n\n\t","vertex"===t)s+=`varyings.Vertex = ${i.result};`;else if("fragment"===t)if(a)r.returnType=o.nodeType,s+=`return ${i.result};`;else{let e="\t@location(0) color: vec4";const t=this.getBuiltins("output");t&&(e+=",\n\t"+t),r.returnType="OutputStruct",r.structs+=this._getWGSLStruct("OutputStruct",e),r.structs+="\nvar output : OutputStruct;\n\n",s+=`output.color = ${i.result};\n\n\treturn output;`}}r.flow=s}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 r;return null!==t&&(r=this._getWGSLMethod(e+"_"+t)),void 0===r&&(r=this._getWGSLMethod(e)),r||e}getType(e){return AN[e]||e}isAvailable(e){let t=NN[e];return void 0===t&&("float32Filterable"===e?t=this.renderer.hasFeature("float32-filterable"):"clipDistance"===e&&(t=this.renderer.hasFeature("clip-distances")),NN[e]=t),t}_getWGSLMethod(e){return void 0!==CN[e]&&this._include(e),EN[e]}_include(e){const t=CN[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${wN}\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,r,s=0,i=0){const n=e+"Struct";return`${this._getWGSLStruct(n,t)}\n@binding( ${s} ) @group( ${i} )\nvar<${r}> ${e} : ${n};`}}class BN{constructor(e){this.backend=e}getCurrentDepthStencilFormat(e){let t;return null!==e.depthTexture?t=this.getTextureFormatGPU(e.depthTexture):e.depth&&e.stencil?t=iv.Depth24PlusStencil8:e.depth&&(t=iv.Depth24Plus),t}getTextureFormatGPU(e){return this.backend.get(e).format}getTextureSampleData(e){let t;if(e.isFramebufferTexture)t=1;else if(e.isDepthTexture&&!e.renderTarget){const e=this.backend.renderer,r=e.getRenderTarget();t=r?r.samples:e.samples}else e.renderTarget&&(t=e.renderTarget.samples);t=t||1;const r=t>1&&null!==e.renderTarget&&!0!==e.isDepthTexture&&!0!==e.isFramebufferTexture;return{samples:t,primarySamples:r?1:t,isMSAA:r}}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?L_:e.isLineSegments||e.isMesh&&!0===t.wireframe?D_:e.isLine?V_:e.isMesh?O_: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")?iv.BGRA8Unorm:navigator.gpu.getPreferredCanvasFormat()}}const UN=new Map([[Int8Array,["sint8","snorm8"]],[Uint8Array,["uint8","unorm8"]],[Int16Array,["sint16","snorm16"]],[Uint16Array,["uint16","unorm16"]],[Int32Array,["sint32","snorm32"]],[Uint32Array,["uint32","unorm32"]],[Float32Array,["float32"]]]),FN=new Map([[Le,["float16"]]]),PN=new Map([[Int32Array,"sint32"],[Int16Array,"sint32"],[Uint32Array,"uint32"],[Uint16Array,"uint32"],[Float32Array,"float32"]]);class IN{constructor(e){this.backend=e}createAttribute(e,t){const r=this._getBufferAttribute(e),s=this.backend,i=s.get(r);let n=i.buffer;if(void 0===n){const o=s.device;let a=r.array;if(!1===e.normalized&&(a.constructor===Int16Array||a.constructor===Uint16Array)){const e=new Uint32Array(a.length);for(let t=0;t1&&(s.multisampled=!0,r.texture.isDepthTexture||(s.sampleType=Hv)),r.texture.isDepthTexture)s.sampleType=Wv;else if(r.texture.isDataTexture||r.texture.isDataArrayTexture||r.texture.isData3DTexture){const e=r.texture.type;e===y?s.sampleType=jv:e===f?s.sampleType=qv:e===E&&(this.backend.hasFeature("float32-filterable")?s.sampleType=$v:s.sampleType=Hv)}r.isSampledCubeTexture?s.viewDimension=Zv:r.texture.isDataArrayTexture||r.texture.isCompressedArrayTexture?s.viewDimension=Qv:r.isSampledTexture3D&&(s.viewDimension=Jv),e.texture=s}else console.error(`WebGPUBindingUtils: Unsupported binding "${r}".`);s.push(e)}return r.createBindGroupLayout({entries:s})}createBindings(e,t,r,s=0){const{backend:i,bindGroupLayoutCache:n}=this,o=i.get(e);let a,u=n.get(e.bindingsReference);void 0===u&&(u=this.createBindingsLayout(e),n.set(e.bindingsReference,u)),r>0&&(void 0===o.groups&&(o.groups=[],o.versions=[]),o.versions[r]===s&&(a=o.groups[r])),void 0===a&&(a=this.createBindGroup(e,u),r>0&&(o.groups[r]=a,o.versions[r]=s)),o.group=a,o.layout=u}updateBinding(e){const t=this.backend,r=t.device,s=e.buffer,i=t.get(e).buffer;r.queue.writeBuffer(i,0,s,0)}createBindGroup(e,t){const r=this.backend,s=r.device;let i=0;const n=[];for(const t of e.bindings){if(t.isUniformBuffer){const e=r.get(t);if(void 0===e.buffer){const r=t.byteLength,i=GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,n=s.createBuffer({label:"bindingBuffer_"+t.name,size:r,usage:i});e.buffer=n}n.push({binding:i,resource:{buffer:e.buffer}})}else if(t.isStorageBuffer){const e=r.get(t);if(void 0===e.buffer){const s=t.attribute;e.buffer=r.get(s).buffer}n.push({binding:i,resource:{buffer:e.buffer}})}else if(t.isSampler){const e=r.get(t.texture);n.push({binding:i,resource:e.sampler})}else if(t.isSampledTexture){const e=r.get(t.texture);let o;if(void 0!==e.externalTexture)o=s.importExternalTexture({source:e.externalTexture});else{const r=t.store?1:e.texture.mipLevelCount,s=`view-${e.texture.width}-${e.texture.height}-${r}`;if(o=e[s],void 0===o){const i=eN;let n;n=t.isSampledCubeTexture?Zv:t.isSampledTexture3D?Jv:t.texture.isDataArrayTexture||t.texture.isCompressedArrayTexture?Qv:Yv,o=e[s]=e.texture.createView({aspect:i,dimension:n,mipLevelCount:r})}}n.push({binding:i,resource:o})}i++}return s.createBindGroup({label:"bindGroup_"+e.name,layout:t,entries:n})}}class DN{constructor(e){this.backend=e}_getSampleCount(e){return this.backend.utils.getSampleCountRenderContext(e)}createRenderPipeline(e,t){const{object:r,material:s,geometry:i,pipeline:n}=e,{vertexProgram:o,fragmentProgram:a}=n,u=this.backend,l=u.device,d=u.utils,c=u.get(n),h=[];for(const t of e.getBindings()){const e=u.get(t);h.push(e.layout)}const p=u.attributeUtils.createShaderVertexBuffers(e);let g;!0===s.transparent&&s.blending!==D&&(g=this._getBlending(s));let m={};!0===s.stencilWrite&&(m={compare:this._getStencilCompare(s),failOp:this._getStencilOperation(s.stencilFail),depthFailOp:this._getStencilOperation(s.stencilZFail),passOp:this._getStencilOperation(s.stencilZPass)});const f=this._getColorWriteMask(s),y=[];if(null!==e.context.textures){const t=e.context.textures;for(let e=0;e1},layout:l.createPipelineLayout({bindGroupLayouts:h})},A={},R=e.context.depth,C=e.context.stencil;if(!0!==R&&!0!==C||(!0===R&&(A.format=v,A.depthWriteEnabled=s.depthWrite,A.depthCompare=_),!0===C&&(A.stencilFront=m,A.stencilBack={},A.stencilReadMask=s.stencilFuncMask,A.stencilWriteMask=s.stencilWriteMask),S.depthStencil=A),null===t)c.pipeline=l.createRenderPipeline(S);else{const e=new Promise((e=>{l.createRenderPipelineAsync(S).then((t=>{c.pipeline=t,e()}))}));t.push(e)}}createBundleEncoder(e){const t=this.backend,{utils:r,device:s}=t,i=r.getCurrentDepthStencilFormat(e),n={label:"renderBundleEncoder",colorFormats:[r.getCurrentColorFormat(e)],depthStencilFormat:i,sampleCount:this._getSampleCount(e)};return s.createRenderBundleEncoder(n)}createComputePipeline(e,t){const r=this.backend,s=r.device,i=r.get(e.computeProgram).module,n=r.get(e),o=[];for(const e of t){const t=r.get(e);o.push(t.layout)}n.pipeline=s.createComputePipeline({compute:i,layout:s.createPipelineLayout({bindGroupLayouts:o})})}_getBlending(e){let t,r;const s=e.blending,i=e.blendSrc,n=e.blendDst,o=e.blendEquation;if(s===ft){const s=null!==e.blendSrcAlpha?e.blendSrcAlpha:i,a=null!==e.blendDstAlpha?e.blendDstAlpha:n,u=null!==e.blendEquationAlpha?e.blendEquationAlpha:o;t={srcFactor:this._getBlendFactor(i),dstFactor:this._getBlendFactor(n),operation:this._getBlendOperation(o)},r={srcFactor:this._getBlendFactor(s),dstFactor:this._getBlendFactor(a),operation:this._getBlendOperation(u)}}else{const i=(e,s,i,n)=>{t={srcFactor:e,dstFactor:s,operation:Nv},r={srcFactor:i,dstFactor:n,operation:Nv}};if(e.premultipliedAlpha)switch(s){case F:i(cv,mv,cv,mv);break;case xt:i(cv,cv,cv,cv);break;case bt:i(dv,pv,dv,cv);break;case yt:i(dv,hv,dv,gv)}else switch(s){case F:i(gv,mv,cv,mv);break;case xt:i(gv,cv,gv,cv);break;case bt:i(dv,pv,dv,cv);break;case yt:i(dv,hv,dv,hv)}}if(void 0!==t&&void 0!==r)return{color:t,alpha:r};console.error("THREE.WebGPURenderer: Invalid blending: ",s)}_getBlendFactor(e){let t;switch(e){case rt:t=dv;break;case st:t=cv;break;case it:t=hv;break;case lt:t=pv;break;case nt:t=gv;break;case dt:t=mv;break;case at:t=fv;break;case ct:t=yv;break;case ut:t=bv;break;case ht:t=xv;break;case ot:t=Tv;break;case 211:t=_v;break;case 212:t=vv;break;default:console.error("THREE.WebGPURenderer: Blend factor not supported.",e)}return t}_getStencilCompare(e){let t;const r=e.stencilFunc;switch(r){case Mr:t=k_;break;case wr:t=K_;break;case Er:t=z_;break;case Cr:t=H_;break;case Rr:t=$_;break;case Ar:t=q_;break;case Sr:t=W_;break;case Nr:t=j_;break;default:console.error("THREE.WebGPURenderer: Invalid stencil function.",r)}return t}_getStencilOperation(e){let t;switch(e){case Vr:t=Mv;break;case Dr:t=Bv;break;case Lr:t=Uv;break;case Ir:t=Fv;break;case Pr:t=Pv;break;case Fr:t=Iv;break;case Ur:t=Lv;break;case Br:t=Dv;break;default:console.error("THREE.WebGPURenderer: Invalid stencil operation.",t)}return t}_getBlendOperation(e){let t;switch(e){case Je:t=Nv;break;case et:t=Sv;break;case tt:t=Av;break;case Gr:t=Rv;break;case Or:t=Cv;break;default:console.error("THREE.WebGPUPipelineUtils: Blend equation not supported.",e)}return t}_getPrimitiveState(e,t,r){const s={},i=this.backend.utils;switch(s.topology=i.getPrimitiveTopology(e,r),null!==t.index&&!0===e.isLine&&!0!==e.isLineSegments&&(s.stripIndexFormat=t.index.array instanceof Uint16Array?rv:sv),r.side){case Ge:s.frontFace=Z_,s.cullMode=tv;break;case x:s.frontFace=Z_,s.cullMode=ev;break;case le:s.frontFace=Z_,s.cullMode=J_;break;default:console.error("THREE.WebGPUPipelineUtils: Unknown material.side value.",r.side)}return s}_getColorWriteMask(e){return!0===e.colorWrite?wv:Ev}_getDepthCompare(e){let t;if(!1===e.depthTest)t=K_;else{const r=e.depthFunc;switch(r){case Ct:t=k_;break;case Rt:t=K_;break;case At:t=z_;break;case St:t=H_;break;case Nt:t=$_;break;case vt:t=q_;break;case _t:t=W_;break;case Tt:t=j_;break;default:console.error("THREE.WebGPUPipelineUtils: Invalid depth function.",r)}}return t}}class VN extends y_{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 BN(this),this.attributeUtils=new IN(this),this.bindingUtils=new LN(this),this.pipelineUtils=new DN(this),this.textureUtils=new hN(this),this.occludedResolveCache=new Map}async init(e){await super.init(e);const t=this.parameters;let r;if(void 0===t.device){const e={powerPreference:t.powerPreference},s="undefined"!=typeof navigator?await navigator.gpu.requestAdapter(e):null;if(null===s)throw new Error("WebGPUBackend: Unable to create WebGPU adapter.");const i=Object.values(sN),n=[];for(const e of i)s.features.has(e)&&n.push(e);const o={requiredFeatures:n,requiredLimits:t.requiredLimits};r=await s.requestDevice(o)}else r=t.device;r.lost.then((t=>{const r={api:"WebGPU",message:t.message||"Unknown reason",reason:t.reason||null,originalEvent:t};e.onDeviceLost(r)}));const s=void 0!==t.context?t.context:e.domElement.getContext("webgpu");this.device=r,this.context=s;const i=t.alpha?"premultiplied":"opaque";this.trackTimestamp=this.trackTimestamp&&this.hasFeature(sN.TimestampQuery),this.context.configure({device:this.device,format:this.utils.getPreferredCanvasFormat(),usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:i}),this.updateSize()}get coordinateSystem(){return v}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}]},!0!==this.renderer.depth&&!0!==this.renderer.stencil||(e.depthStencilAttachment={view:this.textureUtils.getDepthBuffer(t.depth,t.stencil).createView()});const r=e.colorAttachments[0];this.renderer.samples>0?r.view=this.colorBuffer.createView():r.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,r=this.get(t);let s=r.descriptors;if(void 0===s||r.width!==t.width||r.height!==t.height||r.activeMipmapLevel!==t.activeMipmapLevel||r.samples!==t.samples){s={},r.descriptors=s;const e=()=>{t.removeEventListener("dispose",e),this.delete(t)};t.addEventListener("dispose",e)}const i=e.getCacheKey();let n=s[i];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,i=r.createQuerySet({type:"occlusion",count:s,label:`occlusionQuerySet_${e.id}`}),t.occlusionQuerySet=i,t.occlusionQueryIndex=0,t.occlusionQueryObjects=new Array(s),t.lastOcclusionObject=null),n=null===e.textures?this._getDefaultRenderPassDescriptor():this._getRenderPassDescriptor(e),this.initTimestampQuery(e,n),n.occlusionQuerySet=i;const o=n.depthStencilAttachment;if(null!==e.textures){const t=n.colorAttachments;for(let r=0;r0&&t.currentPass.executeBundles(t.renderBundles),r>t.occlusionQueryIndex&&t.currentPass.endOcclusionQuery(),t.currentPass.end(),r>0){const s=8*r;let i=this.occludedResolveCache.get(s);void 0===i&&(i=this.device.createBuffer({size:s,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),this.occludedResolveCache.set(s,i));const n=this.device.createBuffer({size:s,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});t.encoder.resolveQuerySet(t.occlusionQuerySet,0,r,i,0),t.encoder.copyBufferToBuffer(i,0,n,0,s),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?(u.x=Math.min(t.dispatchCount,o),u.y=Math.ceil(t.dispatchCount/o)):u.x=t.dispatchCount,i.dispatchWorkgroups(u.x,u.y,u.z)}finishCompute(e){const t=this.get(e);t.passEncoderGPU.end(),this.prepareTimestampBuffer(e,t.cmdEncoderGPU),this.device.queue.submit([t.cmdEncoderGPU.finish()])}async waitForGPU(){await this.device.queue.onSubmittedWorkDone()}draw(e,t){const{object:r,context:s,pipeline:i}=e,n=e.getBindings(),o=this.get(s),a=this.get(i).pipeline,u=o.currentSets,l=o.currentPass,d=e.getDrawParameters();if(null===d)return;u.pipeline!==a&&(l.setPipeline(a),u.pipeline=a);const c=u.bindingGroups;for(let e=0,t=n.length;e1?0:r;l.drawIndexed(t[r],s,e[r]/n,0,o)}}else if(!0===p){const{vertexCount:s,instanceCount:i,firstVertex:n}=d,o=e.getIndirect();if(null!==o){const e=this.get(o).buffer;l.drawIndexedIndirect(e,0)}else l.drawIndexed(s,i,n,0,0);t.update(r,s,i)}else{const{vertexCount:s,instanceCount:i,firstVertex:n}=d,o=e.getIndirect();if(null!==o){const e=this.get(o).buffer;l.drawIndirect(e,0)}else l.draw(s,i,n,0);t.update(r,s,i)}}needsRenderUpdate(e){const t=this.get(e),{object:r,material:s}=e,i=this.utils,n=i.getSampleCountRenderContext(e.context),o=i.getCurrentColorSpace(e.context),a=i.getCurrentColorFormat(e.context),u=i.getCurrentDepthStencilFormat(e.context),l=i.getPrimitiveTopology(r,s);let d=!1;return t.material===s&&t.materialVersion===s.version&&t.transparent===s.transparent&&t.blending===s.blending&&t.premultipliedAlpha===s.premultipliedAlpha&&t.blendSrc===s.blendSrc&&t.blendDst===s.blendDst&&t.blendEquation===s.blendEquation&&t.blendSrcAlpha===s.blendSrcAlpha&&t.blendDstAlpha===s.blendDstAlpha&&t.blendEquationAlpha===s.blendEquationAlpha&&t.colorWrite===s.colorWrite&&t.depthWrite===s.depthWrite&&t.depthTest===s.depthTest&&t.depthFunc===s.depthFunc&&t.stencilWrite===s.stencilWrite&&t.stencilFunc===s.stencilFunc&&t.stencilFail===s.stencilFail&&t.stencilZFail===s.stencilZFail&&t.stencilZPass===s.stencilZPass&&t.stencilFuncMask===s.stencilFuncMask&&t.stencilWriteMask===s.stencilWriteMask&&t.side===s.side&&t.alphaToCoverage===s.alphaToCoverage&&t.sampleCount===n&&t.colorSpace===o&&t.colorFormat===a&&t.depthStencilFormat===u&&t.primitiveTopology===l&&t.clippingContextCacheKey===e.clippingContextCacheKey||(t.material=s,t.materialVersion=s.version,t.transparent=s.transparent,t.blending=s.blending,t.premultipliedAlpha=s.premultipliedAlpha,t.blendSrc=s.blendSrc,t.blendDst=s.blendDst,t.blendEquation=s.blendEquation,t.blendSrcAlpha=s.blendSrcAlpha,t.blendDstAlpha=s.blendDstAlpha,t.blendEquationAlpha=s.blendEquationAlpha,t.colorWrite=s.colorWrite,t.depthWrite=s.depthWrite,t.depthTest=s.depthTest,t.depthFunc=s.depthFunc,t.stencilWrite=s.stencilWrite,t.stencilFunc=s.stencilFunc,t.stencilFail=s.stencilFail,t.stencilZFail=s.stencilZFail,t.stencilZPass=s.stencilZPass,t.stencilFuncMask=s.stencilFuncMask,t.stencilWriteMask=s.stencilWriteMask,t.side=s.side,t.alphaToCoverage=s.alphaToCoverage,t.sampleCount=n,t.colorSpace=o,t.colorFormat=a,t.depthStencilFormat=u,t.primitiveTopology=l,t.clippingContextCacheKey=e.clippingContextCacheKey,d=!0),d}getRenderCacheKey(e){const{object:t,material:r}=e,s=this.utils,i=e.context;return[r.transparent,r.blending,r.premultipliedAlpha,r.blendSrc,r.blendDst,r.blendEquation,r.blendSrcAlpha,r.blendDstAlpha,r.blendEquationAlpha,r.colorWrite,r.depthWrite,r.depthTest,r.depthFunc,r.stencilWrite,r.stencilFunc,r.stencilFail,r.stencilZFail,r.stencilZPass,r.stencilFuncMask,r.stencilWriteMask,r.side,s.getSampleCountRenderContext(i),s.getCurrentColorSpace(i),s.getCurrentColorFormat(i),s.getCurrentDepthStencilFormat(i),s.getPrimitiveTopology(t,r),e.getGeometryCacheKey(),e.clippingContextCacheKey].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,r,s,i,n){return this.textureUtils.copyTextureToBuffer(e,t,r,s,i,n)}initTimestampQuery(e,t){if(!this.trackTimestamp)return;const r=this.get(e);if(!r.timeStampQuerySet){const s=e.isComputeNode?"compute":"render",i=this.device.createQuerySet({type:"timestamp",count:2,label:`timestamp_${s}_${e.id}`}),n={querySet:i,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1};Object.assign(t,{timestampWrites:n}),r.timeStampQuerySet=i}}prepareTimestampBuffer(e,t){if(!this.trackTimestamp)return;const r=this.get(e),s=2*BigInt64Array.BYTES_PER_ELEMENT;void 0===r.currentTimestampQueryBuffers&&(r.currentTimestampQueryBuffers={resolveBuffer:this.device.createBuffer({label:"timestamp resolve buffer",size:s,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),resultBuffer:this.device.createBuffer({label:"timestamp result buffer",size:s,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ})});const{resolveBuffer:i,resultBuffer:n}=r.currentTimestampQueryBuffers;t.resolveQuerySet(r.timeStampQuerySet,0,2,i,0),"unmapped"===n.mapState&&t.copyBufferToBuffer(i,0,n,0,s)}async resolveTimestampAsync(e,t="render"){if(!this.trackTimestamp)return;const r=this.get(e);if(void 0===r.currentTimestampQueryBuffers)return;const{resultBuffer:s}=r.currentTimestampQueryBuffers;"unmapped"===s.mapState&&s.mapAsync(GPUMapMode.READ).then((()=>{const e=new BigUint64Array(s.getMappedRange()),r=Number(e[1]-e[0])/1e6;this.renderer.info.updateTimestamp(t,r),s.unmap()}))}createNodeBuilder(e,t){return new MN(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 r=this.get(e),s=r.currentPass.finish();this.get(t).bundleGPU=s,r.currentSets=r._currentSets,r.currentPass=r._currentPass}addBundle(e,t){this.get(e).renderBundles.push(this.get(t).bundleGPU)}createBindings(e,t,r,s){this.bindingUtils.createBindings(e,t,r,s)}updateBindings(e,t,r,s){this.bindingUtils.createBindings(e,t,r,s)}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)}createIndirectStorageAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.STORAGE|GPUBufferUsage.INDIRECT|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,r=null,s=null,i=0){let n=0,o=0,a=0,u=0,l=0,d=0,c=e.image.width,h=e.image.height;null!==r&&(u=r.x,l=r.y,d=r.z||0,c=r.width,h=r.height),null!==s&&(n=s.x,o=s.y,a=s.z||0);const p=this.device.createCommandEncoder({label:"copyTextureToTexture_"+e.id+"_"+t.id}),g=this.get(e).texture,m=this.get(t).texture;p.copyTextureToTexture({texture:g,mipLevel:i,origin:{x:u,y:l,z:d}},{texture:m,mipLevel:i,origin:{x:n,y:o,z:a}},[c,h,1]),this.device.queue.submit([p.finish()])}copyFramebufferToTexture(e,t,r){const s=this.get(t);let i=null;i=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 n=this.get(e).texture;if(i.format!==n.format)return void console.error("WebGPUBackend: copyFramebufferToTexture: Source and destination formats do not match.",i.format,n.format);let o;if(s.currentPass?(s.currentPass.end(),o=s.encoder):o=this.device.createCommandEncoder({label:"copyFramebufferToTexture_"+e.id}),o.copyTextureToTexture({texture:i,origin:[r.x,r.y,0]},{texture:n},[r.z,r.w]),e.generateMipmaps&&this.textureUtils.generateMipmaps(e),s.currentPass){const{descriptor:e}=s;for(let t=0;t(console.warn("THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend."),new I_(e)));super(new t(e),e),this.library=new GN,this.isWebGPURenderer=!0}}class zN extends es{constructor(){super(),this.isBundleGroup=!0,this.type="BundleGroup",this.static=!0,this.version=0}set needsUpdate(e){!0===e&&this.version++}}const $N=new Yc,HN=new Jm($N);class WN{constructor(e,t=Oi(0,0,1,1)){this.renderer=e,this.outputNode=t,this.outputColorTransform=!0,this.needsUpdate=!0,$N.name="PostProcessing"}render(){this.update();const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;e.toneMapping=d,e.outputColorSpace=Ae,HN.render(e),e.toneMapping=t,e.outputColorSpace=r}update(){if(!0===this.needsUpdate){const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;HN.material.fragmentNode=!0===this.outputColorTransform?du(this.outputNode,t,r):this.outputNode.context({toneMapping:t,outputColorSpace:r}),HN.material.needsUpdate=!0,this.needsUpdate=!1}}async renderAsync(){this.update();const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;e.toneMapping=d,e.outputColorSpace=Ae,await HN.renderAsync(e),e.toneMapping=t,e.outputColorSpace=r}}function jN(t,r={}){return r.toneMapping=t.toneMapping,r.toneMappingExposure=t.toneMappingExposure,r.outputColorSpace=t.outputColorSpace,r.renderTarget=t.getRenderTarget(),r.activeCubeFace=t.getActiveCubeFace(),r.activeMipmapLevel=t.getActiveMipmapLevel(),r.renderObjectFunction=t.getRenderObjectFunction(),r.pixelRatio=t.getPixelRatio(),r.mrt=t.getMRT(),r.clearColor=t.getClearColor(r.clearColor||new e),r.clearAlpha=t.getClearAlpha(),r.autoClear=t.autoClear,r.scissorTest=t.getScissorTest(),r}function qN(e,t){e.toneMapping=t.toneMapping,e.toneMappingExposure=t.toneMappingExposure,e.outputColorSpace=t.outputColorSpace,e.setRenderTarget(t.renderTarget,t.activeCubeFace,t.activeMipmapLevel),e.setRenderObjectFunction(t.renderObjectFunction),e.setPixelRatio(t.pixelRatio),e.setMRT(t.mrt),e.setClearColor(t.clearColor,t.clearAlpha),e.autoClear=t.autoClear,e.setScissorTest(t.scissorTest)}function KN(e,t,r={}){return(r=jN(e,r)).background=t.background,r.backgroundNode=t.backgroundNode,r.overrideMaterial=t.overrideMaterial,r}var XN=Object.freeze({__proto__:null,resetRendererAndSceneState:function(e,t,r){return r=KN(e,t,r),t.background=null,t.backgroundNode=null,t.overrideMaterial=null,r},resetRendererState:function(e,t){return t=jN(e,t),e.setMRT(null),e.setRenderObjectFunction(null),e.setClearColor(0,1),e.autoClear=!0,t},restoreRendererAndSceneState:function(e,t,r){qN(e,r),t.background=r.background,t.backgroundNode=r.backgroundNode,t.overrideMaterial=r.overrideMaterial},restoreRendererState:qN,saveRendererAndSceneState:KN,saveRendererState:jN});class YN extends ee{constructor(e=1,t=1){super(),this.image={width:e,height:t},this.magFilter=$,this.minFilter=$,this.isStorageTexture=!0}}class QN extends uf{constructor(e,t){super(e,t,Uint32Array),this.isIndirectStorageBufferAttribute=!0}}class ZN extends ts{constructor(e){super(e),this.textures={},this.nodes={}}load(e,t,r,s){const i=new rs(this.manager);i.setPath(this.path),i.setRequestHeader(this.requestHeader),i.setWithCredentials(this.withCredentials),i.load(e,(r=>{try{t(this.parse(JSON.parse(r)))}catch(t){s?s(t):console.error(t),this.manager.itemError(e)}}),r,s)}parseNodes(e){const t={};if(void 0!==e){for(const r of e){const{uuid:e,type:s}=r;t[e]=this.createNodeFromType(s),t[e].uuid=e}const r={nodes:t,textures:this.textures};for(const s of e){s.meta=r;t[s.uuid].deserialize(s),delete s.meta}}return t}parse(e){const t=this.createNodeFromType(e.type);t.uuid=e.uuid;const r={nodes:this.parseNodes(e.nodes),textures:this.textures};return e.meta=r,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),Ci()):fi(new this.nodes[e])}}class JN extends ss{constructor(e){super(e),this.nodes={},this.nodeMaterials={}}parse(e){const t=super.parse(e),r=this.nodes,s=e.inputNodes;for(const e in s){const i=s[e];t[e]=r[i]}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 eS extends is{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 r=super.parse(e,t);return this._nodesJSON=null,r}parseNodes(e,t){if(void 0!==e){const r=new ZN;return r.setNodes(this.nodes),r.setTextures(t),r.parseNodes(e)}return{}}parseMaterials(e,t){const r={};if(void 0!==e){const s=this.parseNodes(this._nodesJSON,t),i=new JN;i.setTextures(t),i.setNodes(s),i.setNodeMaterials(this.nodeMaterials);for(let t=0,s=e.length;t0){const{width:r,height:s}=e.context;t.bufferWidth=r,t.bufferHeight=s}this.renderObjects.set(e,t)}return t}getAttributesData(e){const t={};for(const r in e){const s=e[r];t[r]={version:s.version}}return t}containsNode(e){const t=e.material;for(const e in t)if(t[e]&&t[e].isNode)return!0;return null!==e.renderer.nodes.modelViewMatrix||null!==e.renderer.nodes.modelNormalViewMatrix}getMaterialData(e){const t={};for(const r of this.refreshUniforms){const s=e[r];null!=s&&("object"==typeof s&&void 0!==s.clone?!0===s.isTexture?t[r]={id:s.id,version:s.version}:t[r]=s.clone():t[r]=s)}return t}equals(e){const{object:t,material:r,geometry:s}=e,i=this.getRenderObjectData(e);if(!0!==i.worldMatrix.equals(t.matrixWorld))return i.worldMatrix.copy(t.matrixWorld),!1;const n=i.material;for(const e in n){const t=n[e],s=r[e];if(void 0!==t.equals){if(!1===t.equals(s))return t.copy(s),!1}else if(!0===s.isTexture){if(t.id!==s.id||t.version!==s.version)return t.id=s.id,t.version=s.version,!1}else if(t!==s)return n[e]=s,!1}if(n.transmission>0){const{width:t,height:r}=e.context;if(i.bufferWidth!==t||i.bufferHeight!==r)return i.bufferWidth=t,i.bufferHeight=r,!1}const o=i.geometry,a=s.attributes,u=o.attributes,l=Object.keys(u),d=Object.keys(a);if(l.length!==d.length)return i.geometry.attributes=this.getAttributesData(a),!1;for(const e of l){const t=u[e],r=a[e];if(void 0===r)return delete u[e],!1;if(t.version!==r.version)return t.version=r.version,!1}const c=s.index,h=o.indexVersion,p=c?c.version:null;if(h!==p)return o.indexVersion=p,!1;if(o.drawRange.start!==s.drawRange.start||o.drawRange.count!==s.drawRange.count)return o.drawRange.start=s.drawRange.start,o.drawRange.count=s.drawRange.count,!1;if(i.morphTargetInfluences){let e=!1;for(let r=0;r>>16,2246822507),r^=Math.imul(s^s>>>13,3266489909),s=Math.imul(s^s>>>16,2246822507),s^=Math.imul(r^r>>>13,3266489909),4294967296*(2097151&s)+(r>>>0)}const ls=e=>us(e),ds=e=>us(e),cs=(...e)=>us(e);function hs(e,t=!1){const r=[];!0===e.isNode&&(r.push(e.id),e=e.getSelf());for(const{property:s,childNode:i}of ps(e))r.push(us(s.slice(0,-4)),i.getCacheKey(t));return us(r)}function*ps(e,t=!1){for(const r in e){if(!0===r.startsWith("_"))continue;const s=e[r];if(!0===Array.isArray(s))for(let e=0;ee.charCodeAt(0))).buffer}var Ss=Object.freeze({__proto__:null,arrayBufferToBase64:vs,base64ToArrayBuffer:Ns,getCacheKey:hs,getDataFromObject:_s,getLengthFromType:bs,getNodeChildren:ps,getTypeFromLength:fs,getTypedArrayFromType:ys,getValueFromType:Ts,getValueType:xs,hash:cs,hashArray:ds,hashString:ls});const As={VERTEX:"vertex",FRAGMENT:"fragment"},Rs={NONE:"none",FRAME:"frame",RENDER:"render",OBJECT:"object"},Cs={BOOLEAN:"bool",INTEGER:"int",FLOAT:"float",VECTOR2:"vec2",VECTOR3:"vec3",VECTOR4:"vec4",MATRIX2:"mat2",MATRIX3:"mat3",MATRIX4:"mat4"},Es={READ_ONLY:"readOnly",WRITE_ONLY:"writeOnly",READ_WRITE:"readWrite"},ws=["fragment","vertex"],Ms=["setup","analyze","generate"],Bs=[...ws,"compute"],Us=["x","y","z","w"];let Fs=0;class Ps extends o{static get type(){return"Node"}constructor(e=null){super(),this.nodeType=e,this.updateType=Rs.NONE,this.updateBeforeType=Rs.NONE,this.updateAfterType=Rs.NONE,this.uuid=a.generateUUID(),this.version=0,this.global=!1,this.isNode=!0,this._cacheKey=null,this._cacheKeyVersion=0,Object.defineProperty(this,"id",{value:Fs++})}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,Rs.FRAME)}onRenderUpdate(e){return this.onUpdate(e,Rs.RENDER)}onObjectUpdate(e){return this.onUpdate(e,Rs.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 ps(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=cs(hs(this,e),this.customCacheKey()),this._cacheKeyVersion=this.version),this._cacheKey}customCacheKey(){return 0}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 r=0;for(const e of this.getChildren())t["node"+r++]=e;return t.outputNode||null}analyze(e){if(1===e.increaseUsage(this)){const t=e.getNodeProperties(this);for(const r of Object.values(t))r&&!0===r.isNode&&r.build(e)}}generate(e,t){const{outputNode:r}=e.getNodeProperties(this);if(r&&!0===r.isNode)return r.build(e,t)}updateBefore(){console.warn("Abstract function.")}updateAfter(){console.warn("Abstract function.")}update(){console.warn("Abstract function.")}build(e,t=null){const r=this.getShared(e);if(this!==r)return r.build(e,t);e.addNode(this),e.addChain(this);let s=null;const i=e.getBuildStage();if("setup"===i){this.updateReference(e);const t=e.getNodeProperties(this);if(!0!==t.initialized){t.initialized=!0;const r=this.setup(e),s=r&&!0===r.isNode;for(const r of Object.values(t))r&&!0===r.isNode&&r.build(e);s&&r.build(e),t.outputNode=r}}else if("analyze"===i)this.analyze(e);else if("generate"===i){if(1===this.generate.length){const r=this.getNodeType(e),i=e.getDataFromNode(this);s=i.snippet,void 0===s?(s=this.generate(e)||"",i.snippet=s):void 0!==i.flowCodes&&void 0!==e.context.nodeBlock&&e.addFlowCodeHierarchy(this,e.context.nodeBlock),s=e.format(s,r,t)}else s=this.generate(e,t)||""}return e.removeChain(this),e.addSequentialNode(this),s}getSerializeChildren(){return ps(this)}serialize(e){const t=this.getSerializeChildren(),r={};for(const{property:s,index:i,childNode:n}of t)void 0!==i?(void 0===r[s]&&(r[s]=Number.isInteger(i)?[]:{}),r[s][i]=n.toJSON(e.meta).uuid):r[s]=n.toJSON(e.meta).uuid;Object.keys(r).length>0&&(e.inputNodes=r)}deserialize(e){if(void 0!==e.inputNodes){const t=e.meta.nodes;for(const r in e.inputNodes)if(Array.isArray(e.inputNodes[r])){const s=[];for(const i of e.inputNodes[r])s.push(t[i]);this[r]=s}else if("object"==typeof e.inputNodes[r]){const s={};for(const i in e.inputNodes[r]){const n=e.inputNodes[r][i];s[i]=t[n]}this[r]=s}else{const s=e.inputNodes[r];this[r]=t[s]}}}toJSON(e){const{uuid:t,type:r}=this,s=void 0===e||"string"==typeof e;s&&(e={textures:{},images:{},nodes:{}});let i=e.nodes[t];function n(e){const t=[];for(const r in e){const s=e[r];delete s.metadata,t.push(s)}return t}if(void 0===i&&(i={uuid:t,type:r,meta:e,metadata:{version:4.6,type:"Node",generator:"Node.toJSON"}},!0!==s&&(e.nodes[i.uuid]=i),this.serialize(i),delete i.meta),s){const t=n(e.textures),r=n(e.images),s=n(e.nodes);t.length>0&&(i.textures=t),r.length>0&&(i.images=r),s.length>0&&(i.nodes=s)}return i}}class Is extends Ps{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 Ds extends Ps{static get type(){return"ConvertNode"}constructor(e,t){super(),this.node=e,this.convertTo=t}getNodeType(e){const t=this.node.getNodeType(e);let r=null;for(const s of this.convertTo.split("|"))null!==r&&e.getTypeLength(t)!==e.getTypeLength(s)||(r=s);return r}serialize(e){super.serialize(e),e.convertTo=this.convertTo}deserialize(e){super.deserialize(e),this.convertTo=e.convertTo}generate(e,t){const r=this.node,s=this.getNodeType(e),i=r.build(e,s);return e.format(i,s,t)}}class Ls extends Ps{static get type(){return"TempNode"}constructor(e=null){super(e),this.isTempNode=!0}hasDependencies(e){return e.getDataFromNode(this).usageCount>1}build(e,t){if("generate"===e.getBuildStage()){const r=e.getVectorType(this.getNodeType(e,t)),s=e.getDataFromNode(this);if(void 0!==s.propertyName)return e.format(s.propertyName,r,t);if("void"!==r&&"void"!==t&&this.hasDependencies(e)){const i=super.build(e,r),n=e.getVarFromNode(this,null,r),o=e.getPropertyName(n);return e.addLineFlowCode(`${o} = ${i}`,this),s.snippet=i,s.propertyName=o,e.format(s.propertyName,r,t)}}return super.build(e,t)}}class Vs extends Ls{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,r)=>t+e.getTypeLength(r.getNodeType(e))),0))}generate(e,t){const r=this.getNodeType(e),s=this.nodes,i=e.getComponentType(r),n=[];for(const t of s){let r=t.build(e);const s=e.getComponentType(t.getNodeType(e));s!==i&&(r=e.format(r,s,i)),n.push(r)}const o=`${e.getType(r)}( ${n.join(", ")} )`;return e.format(o,r,t)}}const Os=Us.join("");class Gs extends Ps{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(Us.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 r=this.node,s=e.getTypeLength(r.getNodeType(e));let i=null;if(s>1){let n=null;this.getVectorLength()>=s&&(n=e.getTypeFromLength(this.getVectorLength(),this.getComponentType(e)));const o=r.build(e,n);i=this.components.length===s&&this.components===Os.slice(0,this.components.length)?e.format(o,n,t):e.format(`${o}.${this.components}`,this.getNodeType(e),t)}else i=r.build(e,t);return i}serialize(e){super.serialize(e),e.components=this.components}deserialize(e){super.deserialize(e),this.components=e.components}}class ks extends Ls{static get type(){return"SetNode"}constructor(e,t,r){super(),this.sourceNode=e,this.components=t,this.targetNode=r}getNodeType(e){return this.sourceNode.getNodeType(e)}generate(e){const{sourceNode:t,components:r,targetNode:s}=this,i=this.getNodeType(e),n=e.getComponentType(s.getNodeType(e)),o=e.getTypeFromLength(r.length,n),a=s.build(e,o),u=t.build(e,i),l=e.getTypeLength(i),d=[];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"),Xs=e=>Ks(e).split("").sort().join(""),Ys={setup(e,t){const r=t.shift();return e(_i(r),...t)},get(e,t,r){if("string"==typeof t&&void 0===e[t]){if(!0!==e.isStackNode&&"assign"===t)return(...e)=>(Ws.assign(r,...e),r);if(js.has(t)){const s=js.get(t);return e.isStackNode?(...e)=>r.add(s(...e)):(...e)=>s(r,...e)}if("self"===t)return e;if(t.endsWith("Assign")&&js.has(t.slice(0,t.length-6))){const s=js.get(t.slice(0,t.length-6));return e.isStackNode?(...e)=>r.assign(e[0],s(...e)):(...e)=>r.assign(s(r,...e))}if(!0===/^[xyzwrgbastpq]{1,4}$/.test(t))return t=Ks(t),Ti(new Gs(r,t));if(!0===/^set[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Xs(t.slice(3).toLowerCase()),r=>Ti(new ks(e,t,r));if(!0===/^flip[XYZWRGBASTPQ]{1,4}$/.test(t))return t=Xs(t.slice(4).toLowerCase()),()=>Ti(new zs(Ti(e),t));if("width"===t||"height"===t||"depth"===t)return"width"===t?t="x":"height"===t?t="y":"depth"===t&&(t="z"),Ti(new Gs(e,t));if(!0===/^\d+$/.test(t))return Ti(new Is(r,new Hs(Number(t),"uint")))}return Reflect.get(e,t,r)},set:(e,t,r,s)=>"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,r,s):(s[t].assign(r),!0)},Qs=new WeakMap,Zs=new WeakMap,Js=function(e,t=null){for(const r in e)e[r]=Ti(e[r],t);return e},ei=function(e,t=null){const r=e.length;for(let s=0;sTi(null!==s?Object.assign(e,s):e);return null===t?(...t)=>i(new e(...vi(t))):null!==r?(r=Ti(r),(...s)=>i(new e(t,...vi(s),r))):(...r)=>i(new e(t,...vi(r)))},ri=function(e,...t){return Ti(new e(...vi(t)))};class si extends Ps{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:r}=this,s=e.getNodeProperties(t);if(s.onceOutput)return s.onceOutput;let i=null;if(t.layout){let s=Zs.get(e.constructor);void 0===s&&(s=new WeakMap,Zs.set(e.constructor,s));let n=s.get(t);void 0===n&&(n=Ti(e.buildFunctionNode(t)),s.set(t,n)),null!==e.currentFunctionNode&&e.currentFunctionNode.includes.push(n),i=Ti(n.call(r))}else{const s=t.jsFunc,n=null!==r||s.length>1?s(r||[],e):s(e);i=Ti(n)}return t.once&&(s.onceOutput=i),i}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 ii extends Ps{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 _i(e),Ti(new si(this,e))}setup(){return this.call()}}const ni=[!1,!0],oi=[0,1,2,3],ai=[-1,-2],ui=[.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],li=new Map;for(const e of ni)li.set(e,new Hs(e));const di=new Map;for(const e of oi)di.set(e,new Hs(e,"uint"));const ci=new Map([...di].map((e=>new Hs(e.value,"int"))));for(const e of ai)ci.set(e,new Hs(e,"int"));const hi=new Map([...ci].map((e=>new Hs(e.value))));for(const e of ui)hi.set(e,new Hs(e));for(const e of ui)hi.set(-e,new Hs(-e));const pi={bool:li,uint:di,ints:ci,float:hi},gi=new Map([...li,...hi]),mi=(e,t)=>gi.has(e)?gi.get(e):!0===e.isNode?e:new Hs(e,t),fi=function(e,t=null){return(...r)=>{if((0===r.length||!["bool","float","int","uint"].includes(e)&&r.every((e=>"object"!=typeof e)))&&(r=[Ts(e,...r)]),1===r.length&&null!==t&&t.has(r[0]))return Ti(t.get(r[0]));if(1===r.length){const t=mi(r[0],e);return(e=>{try{return e.getNodeType()}catch(e){return}})(t)===e?Ti(t):Ti(new Ds(t,e))}const s=r.map((e=>mi(e)));return Ti(new Vs(s,e))}},yi=e=>"object"==typeof e&&null!==e?e.value:e,bi=e=>null!=e?e.nodeType||e.convertTo||("string"==typeof e?e:null):null;function xi(e,t){return new Proxy(new ii(e,t),Ys)}const Ti=(e,t=null)=>function(e,t=null){const r=xs(e);if("node"===r){let t=Qs.get(e);return void 0===t&&(t=new Proxy(e,Ys),Qs.set(e,t),Qs.set(t,t)),t}return null===t&&("float"===r||"boolean"===r)||r&&"shader"!==r&&"string"!==r?Ti(mi(e,t)):"shader"===r?Ai(e):e}(e,t),_i=(e,t=null)=>new Js(e,t),vi=(e,t=null)=>new ei(e,t),Ni=(...e)=>new ti(...e),Si=(...e)=>new ri(...e),Ai=(e,t)=>{const r=new xi(e,t),s=(...e)=>{let t;return _i(e),t=e[0]&&e[0].isNode?[...e]:e[0],r.call(t)};return s.shaderNode=r,s.setLayout=e=>(r.setLayout(e),s),s.once=()=>(r.once=!0,s),s};qs("toGlobal",(e=>(e.global=!0,e)));const Ri=e=>{Ws=e},Ci=()=>Ws,Ei=(...e)=>Ws.If(...e);function wi(e){return Ws&&Ws.add(e),e}qs("append",wi);const Mi=new fi("color"),Bi=new fi("float",pi.float),Ui=new fi("int",pi.ints),Fi=new fi("uint",pi.uint),Pi=new fi("bool",pi.bool),Ii=new fi("vec2"),Di=new fi("ivec2"),Li=new fi("uvec2"),Vi=new fi("bvec2"),Oi=new fi("vec3"),Gi=new fi("ivec3"),ki=new fi("uvec3"),zi=new fi("bvec3"),$i=new fi("vec4"),Hi=new fi("ivec4"),Wi=new fi("uvec4"),ji=new fi("bvec4"),qi=new fi("mat2"),Ki=new fi("mat3"),Xi=new fi("mat4");qs("toColor",Mi),qs("toFloat",Bi),qs("toInt",Ui),qs("toUint",Fi),qs("toBool",Pi),qs("toVec2",Ii),qs("toIVec2",Di),qs("toUVec2",Li),qs("toBVec2",Vi),qs("toVec3",Oi),qs("toIVec3",Gi),qs("toUVec3",ki),qs("toBVec3",zi),qs("toVec4",$i),qs("toIVec4",Hi),qs("toUVec4",Wi),qs("toBVec4",ji),qs("toMat2",qi),qs("toMat3",Ki),qs("toMat4",Xi);const Yi=Ni(Is),Qi=(e,t)=>Ti(new Ds(Ti(e),t));qs("element",Yi),qs("convert",Qi);class Zi extends Ps{static get type(){return"UniformGroupNode"}constructor(e,t=!1,r=1){super("string"),this.name=e,this.shared=t,this.order=r,this.isUniformGroup=!0}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 Ji=e=>new Zi(e),en=(e,t=0)=>new Zi(e,!0,t),tn=en("frame"),rn=en("render"),sn=Ji("object");class nn extends $s{static get type(){return"UniformNode"}constructor(e,t=null){super(e,t),this.isUniformNode=!0,this.name="",this.groupNode=sn}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 r=this.getSelf();return e=e.bind(r),super.onUpdate((t=>{const s=e(t,r);void 0!==s&&(this.value=s)}),t)}generate(e,t){const r=this.getNodeType(e),s=this.getUniformHash(e);let i=e.getNodeFromHash(s);void 0===i&&(e.setHashNode(this,s),i=this);const n=i.getInputType(e),o=e.getUniformFromNode(i,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,r,t)}}const on=(e,t)=>{const r=bi(t||e),s=e&&!0===e.isNode?e.node&&e.node.value||e.value:e;return Ti(new nn(s,r))};class an extends Ps{static get type(){return"PropertyNode"}constructor(e,t=null,r=!1){super(e),this.name=t,this.varying=r,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 un=(e,t)=>Ti(new an(e,t)),ln=(e,t)=>Ti(new an(e,t,!0)),dn=Si(an,"vec4","DiffuseColor"),cn=Si(an,"vec3","EmissiveColor"),hn=Si(an,"float","Roughness"),pn=Si(an,"float","Metalness"),gn=Si(an,"float","Clearcoat"),mn=Si(an,"float","ClearcoatRoughness"),fn=Si(an,"vec3","Sheen"),yn=Si(an,"float","SheenRoughness"),bn=Si(an,"float","Iridescence"),xn=Si(an,"float","IridescenceIOR"),Tn=Si(an,"float","IridescenceThickness"),_n=Si(an,"float","AlphaT"),vn=Si(an,"float","Anisotropy"),Nn=Si(an,"vec3","AnisotropyT"),Sn=Si(an,"vec3","AnisotropyB"),An=Si(an,"color","SpecularColor"),Rn=Si(an,"float","SpecularF90"),Cn=Si(an,"float","Shininess"),En=Si(an,"vec4","Output"),wn=Si(an,"float","dashSize"),Mn=Si(an,"float","gapSize"),Bn=Si(an,"float","pointWidth"),Un=Si(an,"float","IOR"),Fn=Si(an,"float","Transmission"),Pn=Si(an,"float","Thickness"),In=Si(an,"float","AttenuationDistance"),Dn=Si(an,"color","AttenuationColor"),Ln=Si(an,"float","Dispersion");class Vn extends Ls{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 r=e.getTypeLength(t.node.getNodeType(e));return Us.join("").slice(0,r)!==t.components}return!1}generate(e,t){const{targetNode:r,sourceNode:s}=this,i=this.needsSplitAssign(e),n=r.getNodeType(e),o=r.context({assign:!0}).build(e),a=s.build(e,n),u=s.getNodeType(e),l=e.getDataFromNode(this);let d;if(!0===l.initialized)"void"!==t&&(d=o);else if(i){const s=e.getVarFromNode(this,null,n),i=e.getPropertyName(s);e.addLineFlowCode(`${i} = ${a}`,this);const u=r.node.context({assign:!0}).build(e);for(let t=0;t{const s=r.type;let i;return i="pointer"===s?"&"+t.build(e):t.build(e,s),i};if(Array.isArray(i))for(let e=0;e(t=t.length>1||t[0]&&!0===t[0].isNode?vi(t):_i(t[0]),Ti(new Gn(Ti(e),t)));qs("call",kn);class zn extends Ls{static get type(){return"OperatorNode"}constructor(e,t,r,...s){if(super(),s.length>0){let i=new zn(e,t,r);for(let t=0;t>"===r||"<<"===r)return e.getIntegerType(n);if("!"===r||"=="===r||"&&"===r||"||"===r||"^^"===r)return"bool";if("<"===r||">"===r||"<="===r||">="===r){const r=t?e.getTypeLength(t):Math.max(e.getTypeLength(n),e.getTypeLength(o));return r>1?`bvec${r}`:"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 r=this.op,s=this.aNode,i=this.bNode,n=this.getNodeType(e,t);let o=null,a=null;"void"!==n?(o=s.getNodeType(e),a=void 0!==i?i.getNodeType(e):null,"<"===r||">"===r||"<="===r||">="===r||"=="===r?e.isVector(o)?a=o:o!==a&&(o=a="float"):">>"===r||"<<"===r?(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 u=s.build(e,o),l=void 0!==i?i.build(e,a):null,d=e.getTypeLength(t),c=e.getFunctionOperator(r);return"void"!==t?"<"===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThan",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} < ${l} )`,n,t):"<="===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("lessThanEqual",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} <= ${l} )`,n,t):">"===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThan",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} > ${l} )`,n,t):">="===r&&d>1?e.useComparisonMethod?e.format(`${e.getMethod("greaterThanEqual",t)}( ${u}, ${l} )`,n,t):e.format(`( ${u} >= ${l} )`,n,t):"!"===r||"~"===r?e.format(`(${r}${u})`,o,t):c?e.format(`${c}( ${u}, ${l} )`,n,t):e.format(`( ${u} ${r} ${l} )`,n,t):"void"!==o?c?e.format(`${c}( ${u}, ${l} )`,n,t):e.format(`${u} ${r} ${l}`,n,t):void 0}serialize(e){super.serialize(e),e.op=this.op}deserialize(e){super.deserialize(e),this.op=e.op}}const $n=Ni(zn,"+"),Hn=Ni(zn,"-"),Wn=Ni(zn,"*"),jn=Ni(zn,"/"),qn=Ni(zn,"%"),Kn=Ni(zn,"=="),Xn=Ni(zn,"!="),Yn=Ni(zn,"<"),Qn=Ni(zn,">"),Zn=Ni(zn,"<="),Jn=Ni(zn,">="),eo=Ni(zn,"&&"),to=Ni(zn,"||"),ro=Ni(zn,"!"),so=Ni(zn,"^^"),io=Ni(zn,"&"),no=Ni(zn,"~"),oo=Ni(zn,"|"),ao=Ni(zn,"^"),uo=Ni(zn,"<<"),lo=Ni(zn,">>");qs("add",$n),qs("sub",Hn),qs("mul",Wn),qs("div",jn),qs("modInt",qn),qs("equal",Kn),qs("notEqual",Xn),qs("lessThan",Yn),qs("greaterThan",Qn),qs("lessThanEqual",Zn),qs("greaterThanEqual",Jn),qs("and",eo),qs("or",to),qs("not",ro),qs("xor",so),qs("bitAnd",io),qs("bitNot",no),qs("bitOr",oo),qs("bitXor",ao),qs("shiftLeft",uo),qs("shiftRight",lo);const co=(...e)=>(console.warn("TSL.OperatorNode: .remainder() has been renamed to .modInt()."),qn(...e));qs("remainder",co);class ho extends Ls{static get type(){return"MathNode"}constructor(e,t,r=null,s=null){super(),this.method=e,this.aNode=t,this.bNode=r,this.cNode=s,this.isMathNode=!0}getInputType(e){const t=this.aNode.getNodeType(e),r=this.bNode?this.bNode.getNodeType(e):null,s=this.cNode?this.cNode.getNodeType(e):null,i=e.isMatrix(t)?0:e.getTypeLength(t),n=e.isMatrix(r)?0:e.getTypeLength(r),o=e.isMatrix(s)?0:e.getTypeLength(s);return i>n&&i>o?t:n>o?r:o>i?s:t}getNodeType(e){const t=this.method;return t===ho.LENGTH||t===ho.DISTANCE||t===ho.DOT?"float":t===ho.CROSS?"vec3":t===ho.ALL?"bool":t===ho.EQUALS?e.changeComponentType(this.aNode.getNodeType(e),"bool"):t===ho.MOD?this.aNode.getNodeType(e):this.getInputType(e)}generate(e,t){let r=this.method;const s=this.getNodeType(e),i=this.getInputType(e),n=this.aNode,o=this.bNode,a=this.cNode,d=e.renderer.coordinateSystem;if(r===ho.TRANSFORM_DIRECTION){let r=n,s=o;e.isMatrix(r.getNodeType(e))?s=$i(Oi(s),0):r=$i(Oi(r),0);const i=Wn(r,s).xyz;return wo(i).build(e,t)}if(r===ho.NEGATE)return e.format("( - "+n.build(e,i)+" )",s,t);if(r===ho.ONE_MINUS)return Hn(1,n).build(e,t);if(r===ho.RECIPROCAL)return jn(1,n).build(e,t);if(r===ho.DIFFERENCE)return Lo(Hn(n,o)).build(e,t);{const c=[];return r===ho.CROSS||r===ho.MOD?c.push(n.build(e,s),o.build(e,s)):d===u&&r===ho.STEP?c.push(n.build(e,1===e.getTypeLength(n.getNodeType(e))?"float":i),o.build(e,i)):d===u&&(r===ho.MIN||r===ho.MAX)||r===ho.MOD?c.push(n.build(e,i),o.build(e,1===e.getTypeLength(o.getNodeType(e))?"float":i)):r===ho.REFRACT?c.push(n.build(e,i),o.build(e,i),a.build(e,"float")):r===ho.MIX?c.push(n.build(e,i),o.build(e,i),a.build(e,1===e.getTypeLength(a.getNodeType(e))?"float":i)):(d===l&&r===ho.ATAN&&null!==o&&(r="atan2"),c.push(n.build(e,i)),null!==o&&c.push(o.build(e,i)),null!==a&&c.push(a.build(e,i))),e.format(`${e.getMethod(r,s)}( ${c.join(", ")} )`,s,t)}}serialize(e){super.serialize(e),e.method=this.method}deserialize(e){super.deserialize(e),this.method=e.method}}ho.ALL="all",ho.ANY="any",ho.RADIANS="radians",ho.DEGREES="degrees",ho.EXP="exp",ho.EXP2="exp2",ho.LOG="log",ho.LOG2="log2",ho.SQRT="sqrt",ho.INVERSE_SQRT="inversesqrt",ho.FLOOR="floor",ho.CEIL="ceil",ho.NORMALIZE="normalize",ho.FRACT="fract",ho.SIN="sin",ho.COS="cos",ho.TAN="tan",ho.ASIN="asin",ho.ACOS="acos",ho.ATAN="atan",ho.ABS="abs",ho.SIGN="sign",ho.LENGTH="length",ho.NEGATE="negate",ho.ONE_MINUS="oneMinus",ho.DFDX="dFdx",ho.DFDY="dFdy",ho.ROUND="round",ho.RECIPROCAL="reciprocal",ho.TRUNC="trunc",ho.FWIDTH="fwidth",ho.TRANSPOSE="transpose",ho.BITCAST="bitcast",ho.EQUALS="equals",ho.MIN="min",ho.MAX="max",ho.MOD="mod",ho.STEP="step",ho.REFLECT="reflect",ho.DISTANCE="distance",ho.DIFFERENCE="difference",ho.DOT="dot",ho.CROSS="cross",ho.POW="pow",ho.TRANSFORM_DIRECTION="transformDirection",ho.MIX="mix",ho.CLAMP="clamp",ho.REFRACT="refract",ho.SMOOTHSTEP="smoothstep",ho.FACEFORWARD="faceforward";const po=Bi(1e-6),go=Bi(1e6),mo=Bi(Math.PI),fo=Bi(2*Math.PI),yo=Ni(ho,ho.ALL),bo=Ni(ho,ho.ANY),xo=Ni(ho,ho.RADIANS),To=Ni(ho,ho.DEGREES),_o=Ni(ho,ho.EXP),vo=Ni(ho,ho.EXP2),No=Ni(ho,ho.LOG),So=Ni(ho,ho.LOG2),Ao=Ni(ho,ho.SQRT),Ro=Ni(ho,ho.INVERSE_SQRT),Co=Ni(ho,ho.FLOOR),Eo=Ni(ho,ho.CEIL),wo=Ni(ho,ho.NORMALIZE),Mo=Ni(ho,ho.FRACT),Bo=Ni(ho,ho.SIN),Uo=Ni(ho,ho.COS),Fo=Ni(ho,ho.TAN),Po=Ni(ho,ho.ASIN),Io=Ni(ho,ho.ACOS),Do=Ni(ho,ho.ATAN),Lo=Ni(ho,ho.ABS),Vo=Ni(ho,ho.SIGN),Oo=Ni(ho,ho.LENGTH),Go=Ni(ho,ho.NEGATE),ko=Ni(ho,ho.ONE_MINUS),zo=Ni(ho,ho.DFDX),$o=Ni(ho,ho.DFDY),Ho=Ni(ho,ho.ROUND),Wo=Ni(ho,ho.RECIPROCAL),jo=Ni(ho,ho.TRUNC),qo=Ni(ho,ho.FWIDTH),Ko=Ni(ho,ho.TRANSPOSE),Xo=Ni(ho,ho.BITCAST),Yo=Ni(ho,ho.EQUALS),Qo=Ni(ho,ho.MIN),Zo=Ni(ho,ho.MAX),Jo=Ni(ho,ho.MOD),ea=Ni(ho,ho.STEP),ta=Ni(ho,ho.REFLECT),ra=Ni(ho,ho.DISTANCE),sa=Ni(ho,ho.DIFFERENCE),ia=Ni(ho,ho.DOT),na=Ni(ho,ho.CROSS),oa=Ni(ho,ho.POW),aa=Ni(ho,ho.POW,2),ua=Ni(ho,ho.POW,3),la=Ni(ho,ho.POW,4),da=Ni(ho,ho.TRANSFORM_DIRECTION),ca=e=>Wn(Vo(e),oa(Lo(e),1/3)),ha=e=>ia(e,e),pa=Ni(ho,ho.MIX),ga=(e,t=0,r=1)=>Ti(new ho(ho.CLAMP,Ti(e),Ti(t),Ti(r))),ma=e=>ga(e),fa=Ni(ho,ho.REFRACT),ya=Ni(ho,ho.SMOOTHSTEP),ba=Ni(ho,ho.FACEFORWARD),xa=Ai((([e])=>{const t=ia(e.xy,Ii(12.9898,78.233)),r=Jo(t,mo);return Mo(Bo(r).mul(43758.5453))})),Ta=(e,t,r)=>pa(t,r,e),_a=(e,t,r)=>ya(t,r,e),va=(e,t)=>(console.warn('THREE.TSL: "atan2" is overloaded. Use "atan" instead.'),Do(e,t)),Na=ba,Sa=Ro;qs("all",yo),qs("any",bo),qs("equals",Yo),qs("radians",xo),qs("degrees",To),qs("exp",_o),qs("exp2",vo),qs("log",No),qs("log2",So),qs("sqrt",Ao),qs("inverseSqrt",Ro),qs("floor",Co),qs("ceil",Eo),qs("normalize",wo),qs("fract",Mo),qs("sin",Bo),qs("cos",Uo),qs("tan",Fo),qs("asin",Po),qs("acos",Io),qs("atan",Do),qs("abs",Lo),qs("sign",Vo),qs("length",Oo),qs("lengthSq",ha),qs("negate",Go),qs("oneMinus",ko),qs("dFdx",zo),qs("dFdy",$o),qs("round",Ho),qs("reciprocal",Wo),qs("trunc",jo),qs("fwidth",qo),qs("atan2",va),qs("min",Qo),qs("max",Zo),qs("mod",Jo),qs("step",ea),qs("reflect",ta),qs("distance",ra),qs("dot",ia),qs("cross",na),qs("pow",oa),qs("pow2",aa),qs("pow3",ua),qs("pow4",la),qs("transformDirection",da),qs("mix",Ta),qs("clamp",ga),qs("refract",fa),qs("smoothstep",_a),qs("faceForward",ba),qs("difference",sa),qs("saturate",ma),qs("cbrt",ca),qs("transpose",Ko),qs("rand",xa);class Aa extends Ps{static get type(){return"ConditionalNode"}constructor(e,t,r=null){super(),this.condNode=e,this.ifNode=t,this.elseNode=r}getNodeType(e){const{ifNode:t,elseNode:r}=e.getNodeProperties(this);if(void 0===t)return this.setup(e),this.getNodeType(e);const s=t.getNodeType(e);if(null!==r){const t=r.getNodeType(e);if(e.getTypeLength(t)>e.getTypeLength(s))return t}return s}setup(e){const t=this.condNode.cache(),r=this.ifNode.cache(),s=this.elseNode?this.elseNode.cache():null,i=e.context.nodeBlock;e.getDataFromNode(r).parentNodeBlock=i,null!==s&&(e.getDataFromNode(s).parentNodeBlock=i);const n=e.getNodeProperties(this);n.condNode=t,n.ifNode=r.context({nodeBlock:r}),n.elseNode=s?s.context({nodeBlock:s}):null}generate(e,t){const r=this.getNodeType(e),s=e.getDataFromNode(this);if(void 0!==s.nodeProperty)return s.nodeProperty;const{condNode:i,ifNode:n,elseNode:o}=e.getNodeProperties(this),a="void"!==t,u=a?un(r).build(e):"";s.nodeProperty=u;const l=i.build(e,"bool");e.addFlowCode(`\n${e.tab}if ( ${l} ) {\n\n`).addFlowTab();let d=n.build(e,r);if(d&&(d=a?u+" = "+d+";":"return "+d+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+d+"\n\n"+e.tab+"}"),null!==o){e.addFlowCode(" else {\n\n").addFlowTab();let t=o.build(e,r);t&&(t=a?u+" = "+t+";":"return "+t+";"),e.removeFlowTab().addFlowCode(e.tab+"\t"+t+"\n\n"+e.tab+"}\n\n")}else e.addFlowCode("\n\n");return e.format(u,r,t)}}const Ra=Ni(Aa);qs("select",Ra);const Ca=(...e)=>(console.warn("TSL.ConditionalNode: cond() has been renamed to select()."),Ra(...e));qs("cond",Ca);class Ea extends Ps{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 r=this.node.build(e);return e.setContext(t),r}generate(e,t){const r=e.getContext();e.setContext({...e.context,...this.value});const s=this.node.build(e,t);return e.setContext(r),s}}const wa=Ni(Ea),Ma=(e,t)=>wa(e,{label:t});qs("context",wa),qs("label",Ma);class Ba extends Ps{static get type(){return"VarNode"}constructor(e,t=null,r=!1){super(),this.node=e,this.name=t,this.global=!0,this.isVarNode=!0,this.readOnly=r}getHash(e){return this.name||super.getHash(e)}getNodeType(e){return this.node.getNodeType(e)}generate(e){const{node:t,name:r,readOnly:s}=this,{renderer:i}=e,n=!0===i.backend.isWebGPUBackend;let o=!1,a=!1;s&&(o=e.isDeterministic(t),a=n?s:o);const u=e.getVectorType(this.getNodeType(e)),l=t.build(e,u),d=e.getVarFromNode(this,r,u,void 0,a),c=e.getPropertyName(d);let h=c;if(a){const t=e.getType(d.type);h=n?o?`const ${c}`:`let ${c}`:`const ${t} ${c}`}return e.addLineFlowCode(`${h} = ${l}`,this),c}}const Ua=Ni(Ba),Fa=(e,t=null)=>Ua(e,t).append(),Pa=(e,t=null)=>Ua(e,t,!0).append();qs("toVar",Fa),qs("toConst",Pa);const Ia=e=>(console.warn('TSL: "temp( node )" is deprecated. Use "Var( node )" or "node.toVar()" instead.'),Ua(e));qs("temp",Ia);class Da extends Ps{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 r=t.varying;if(void 0===r){const s=this.name,i=this.getNodeType(e);t.varying=r=e.getVaryingFromNode(this,s,i),t.node=this.node}return r.needsInterpolation||(r.needsInterpolation="fragment"===e.shaderStage),r}setup(e){this.setupVarying(e)}analyze(e){return this.setupVarying(e),this.node.analyze(e)}generate(e){const t=e.getNodeProperties(this),r=this.setupVarying(e),s="fragment"===e.shaderStage&&!0===t.reassignPosition&&e.context.needsPositionReassign;if(void 0===t.propertyName||s){const i=this.getNodeType(e),n=e.getPropertyName(r,As.VERTEX);e.flowNodeFromShaderStage(As.VERTEX,this.node,i,n),t.propertyName=n,s?t.reassignPosition=!1:void 0===t.reassignPosition&&e.context.isPositionNodeInput&&(t.reassignPosition=!0)}return e.getPropertyName(r)}}const La=Ni(Da),Va=e=>La(e);qs("varying",La),qs("vertexStage",Va);const Oa=Ai((([e])=>{const t=e.mul(.9478672986).add(.0521327014).pow(2.4),r=e.mul(.0773993808),s=e.lessThanEqual(.04045);return pa(t,r,s)})).setLayout({name:"sRGBTransferEOTF",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),Ga=Ai((([e])=>{const t=e.pow(.41666).mul(1.055).sub(.055),r=e.mul(12.92),s=e.lessThanEqual(.0031308);return pa(t,r,s)})).setLayout({name:"sRGBTransferOETF",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),ka="WorkingColorSpace",za="OutputColorSpace";class $a extends Ls{static get type(){return"ColorSpaceNode"}constructor(e,t,r){super("vec4"),this.colorNode=e,this.source=t,this.target=r}resolveColorSpace(e,t){return t===ka?d.workingColorSpace:t===za?e.context.outputColorSpace||e.renderer.outputColorSpace:t}setup(e){const{colorNode:t}=this,r=this.resolveColorSpace(e,this.source),s=this.resolveColorSpace(e,this.target);let n=t;return!1!==d.enabled&&r!==s&&r&&s?(d.getTransfer(r)===c&&(n=$i(Oa(n.rgb),n.a)),d.getPrimaries(r)!==d.getPrimaries(s)&&(n=$i(Ki(d._getMatrix(new i,r,s)).mul(n.rgb),n.a)),d.getTransfer(s)===c&&(n=$i(Ga(n.rgb),n.a)),n):n}}const Ha=e=>Ti(new $a(Ti(e),ka,za)),Wa=e=>Ti(new $a(Ti(e),za,ka)),ja=(e,t)=>Ti(new $a(Ti(e),ka,t)),qa=(e,t)=>Ti(new $a(Ti(e),t,ka));qs("toOutputColorSpace",Ha),qs("toWorkingColorSpace",Wa),qs("workingToColorSpace",ja),qs("colorSpaceToWorking",qa);let Ka=class extends Is{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),r=this.referenceNode.getNodeType(),s=this.getNodeType();return e.format(t,r,s)}};class Xa extends Ps{static get type(){return"ReferenceBaseNode"}constructor(e,t,r=null,s=null){super(),this.property=e,this.uniformType=t,this.object=r,this.count=s,this.properties=e.split("."),this.reference=r,this.node=null,this.group=null,this.updateType=Rs.OBJECT}setGroup(e){return this.group=e,this}element(e){return Ti(new Ka(this,Ti(e)))}setNodeType(e){const t=on(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 r=e[t[0]];for(let e=1;eTi(new Ya(e,t,r));class Za extends Ls{static get type(){return"ToneMappingNode"}constructor(e,t=eu,r=null){super("vec3"),this.toneMapping=e,this.exposureNode=t,this.colorNode=r}customCacheKey(){return cs(this.toneMapping)}setup(e){const t=this.colorNode||e.context.color,r=this.toneMapping;if(r===h)return t;let s=null;const i=e.renderer.library.getToneMappingFunction(r);return null!==i?s=$i(i(t.rgb,this.exposureNode),t.a):(console.error("ToneMappingNode: Unsupported Tone Mapping configuration.",r),s=t),s}}const Ja=(e,t,r)=>Ti(new Za(e,Ti(t),Ti(r))),eu=Qa("toneMappingExposure","float");qs("toneMapping",((e,t,r)=>Ja(t,r,e)));class tu extends $s{static get type(){return"BufferAttributeNode"}constructor(e,t=null,r=0,s=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferStride=r,this.bufferOffset=s,this.usage=p,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),r=this.value,s=e.getTypeLength(t),i=this.bufferStride||s,n=this.bufferOffset,o=!0===r.isInterleavedBuffer?r:new g(r,i),a=new f(o,s,n);o.setUsage(this.usage),this.attribute=a,this.attribute.isInstancedBufferAttribute=this.instanced}generate(e){const t=this.getNodeType(e),r=e.getBufferAttributeFromNode(this,t),s=e.getPropertyName(r);let i=null;if("vertex"===e.shaderStage||"compute"===e.shaderStage)this.name=s,i=s;else{i=La(this).build(e,t)}return i}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 ru=(e,t=null,r=0,s=0)=>Ti(new tu(e,t,r,s)),su=(e,t=null,r=0,s=0)=>ru(e,t,r,s).setUsage(m),iu=(e,t=null,r=0,s=0)=>ru(e,t,r,s).setInstanced(!0),nu=(e,t=null,r=0,s=0)=>su(e,t,r,s).setInstanced(!0);qs("toAttribute",(e=>ru(e.value)));class ou extends Ps{static get type(){return"ComputeNode"}constructor(e,t,r=[64]){super("void"),this.isComputeNode=!0,this.computeNode=e,this.count=t,this.workgroupSize=r,this.dispatchCount=0,this.version=1,this.name="",this.updateBeforeType=Rs.OBJECT,this.onInitFunction=null,this.updateDispatchCount()}dispose(){this.dispatchEvent({type:"dispose"})}label(e){return this.name=e,this}updateDispatchCount(){const{count:e,workgroupSize:t}=this;let r=t[0];for(let e=1;eTi(new ou(Ti(e),t,r));qs("compute",au);class uu extends Ps{static get type(){return"CacheNode"}constructor(e,t=!0){super(),this.node=e,this.parent=t,this.isCacheNode=!0}getNodeType(e){const t=e.getCache(),r=e.getCacheFromNode(this,this.parent);e.setCache(r);const s=this.node.getNodeType(e);return e.setCache(t),s}build(e,...t){const r=e.getCache(),s=e.getCacheFromNode(this,this.parent);e.setCache(s);const i=this.node.build(e,...t);return e.setCache(r),i}}const lu=(e,t)=>Ti(new uu(Ti(e),t));qs("cache",lu);class du extends Ps{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 cu=Ni(du);qs("bypass",cu);class hu extends Ps{static get type(){return"RemapNode"}constructor(e,t,r,s=Bi(0),i=Bi(1)){super(),this.node=e,this.inLowNode=t,this.inHighNode=r,this.outLowNode=s,this.outHighNode=i,this.doClamp=!0}setup(){const{node:e,inLowNode:t,inHighNode:r,outLowNode:s,outHighNode:i,doClamp:n}=this;let o=e.sub(t).div(r.sub(t));return!0===n&&(o=o.clamp()),o.mul(i.sub(s)).add(s)}}const pu=Ni(hu,null,null,{doClamp:!1}),gu=Ni(hu);qs("remap",pu),qs("remapClamp",gu);class mu extends Ps{static get type(){return"ExpressionNode"}constructor(e="",t="void"){super(t),this.snippet=e}generate(e,t){const r=this.getNodeType(e),s=this.snippet;if("void"!==r)return e.format(`( ${s} )`,r,t);e.addLineFlowCode(s,this)}}const fu=Ni(mu),yu=e=>(e?Ra(e,fu("discard")):fu("discard")).append();qs("discard",yu);class bu extends Ls{static get type(){return"RenderOutputNode"}constructor(e,t,r){super("vec4"),this.colorNode=e,this.toneMapping=t,this.outputColorSpace=r,this.isRenderOutputNode=!0}setup({context:e}){let t=this.colorNode||e.color;const r=(null!==this.toneMapping?this.toneMapping:e.toneMapping)||h,s=(null!==this.outputColorSpace?this.outputColorSpace:e.outputColorSpace)||y;return r!==h&&(t=t.toneMapping(r)),s!==y&&s!==d.workingColorSpace&&(t=t.workingToColorSpace(s)),t}}const xu=(e,t=null,r=null)=>Ti(new bu(Ti(e),t,r));qs("renderOutput",xu);class Tu extends Ps{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 r=this.getAttributeName(e);if(e.hasGeometryAttribute(r)){const s=e.geometry.getAttribute(r);t=e.getTypeFromAttribute(s)}else t="float"}return t}setAttributeName(e){return this._attributeName=e,this}getAttributeName(){return this._attributeName}generate(e){const t=this.getAttributeName(e),r=this.getNodeType(e);if(!0===e.hasGeometryAttribute(t)){const s=e.geometry.getAttribute(t),i=e.getTypeFromAttribute(s),n=e.getAttribute(t,i);if("vertex"===e.shaderStage)return e.format(n.name,i,r);return La(this).build(e,r)}return console.warn(`AttributeNode: Vertex attribute "${t}" not found on geometry.`),e.generateConst(r)}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 _u=(e,t)=>Ti(new Tu(e,t)),vu=(e=0)=>_u("uv"+(e>0?e:""),"vec2");class Nu extends Ps{static get type(){return"TextureSizeNode"}constructor(e,t=null){super("uvec2"),this.isTextureSizeNode=!0,this.textureNode=e,this.levelNode=t}generate(e,t){const r=this.textureNode.build(e,"property"),s=null===this.levelNode?"0":this.levelNode.build(e,"int");return e.format(`${e.getMethod("textureDimensions")}( ${r}, ${s} )`,this.getNodeType(e),t)}}const Su=Ni(Nu);class Au extends nn{static get type(){return"MaxMipLevelNode"}constructor(e){super(0),this._textureNode=e,this.updateType=Rs.FRAME}get textureNode(){return this._textureNode}get texture(){return this._textureNode.value}update(){const e=this.texture,t=e.images,r=t&&t.length>0?t[0]&&t[0].image||t[0]:e.image;if(r&&void 0!==r.width){const{width:e,height:t}=r;this.value=Math.log2(Math.max(e,t))}}}const Ru=Ni(Au);class Cu extends nn{static get type(){return"TextureNode"}constructor(e,t=null,r=null,s=null){super(e),this.isTextureNode=!0,this.uvNode=t,this.levelNode=r,this.biasNode=s,this.compareNode=null,this.depthNode=null,this.gradNode=null,this.sampler=!0,this.updateMatrix=!1,this.updateType=Rs.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===b?"uvec4":this.value.type===x?"ivec4":"vec4"}getInputType(){return"texture"}getDefaultUV(){return vu(this.value.channel)}updateReference(){return this.value}getTransformedUV(e){return null===this._matrixUniform&&(this._matrixUniform=on(this.value.matrix)),this._matrixUniform.mul(Oi(e,1)).xy}setUpdateMatrix(e){return this.updateMatrix=e,this.updateType=e?Rs.RENDER:Rs.NONE,this}setupUV(e,t){const r=this.value;return e.isFlipY()&&(r.image instanceof ImageBitmap&&!0===r.flipY||!0===r.isRenderTargetTexture||!0===r.isFramebufferTexture||!0===r.isDepthTexture)&&(t=this.sampler?t.flipY():t.setY(Ui(Su(this,this.levelNode).y).sub(t.y).sub(1))),t}setup(e){const t=e.getNodeProperties(this);t.referenceNode=this.referenceNode;const r=this.value;if(!r||!0!==r.isTexture)throw new Error("THREE.TSL: `texture( value )` function expects a valid instance of THREE.Texture().");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,r,s,i,n,o,a){const u=this.value;let l;return l=s?e.generateTextureLevel(u,t,r,s,n):i?e.generateTextureBias(u,t,r,i,n):a?e.generateTextureGrad(u,t,r,a,n):o?e.generateTextureCompare(u,t,r,o,n):!1===this.sampler?e.generateTextureLoad(u,t,r,n):e.generateTexture(u,t,r,n),l}generate(e,t){const r=this.value,s=e.getNodeProperties(this),i=super.generate(e,"property");if("sampler"===t)return i+"_sampler";if(e.isReference(t))return i;{const n=e.getDataFromNode(this);let o=n.propertyName;if(void 0===o){const{uvNode:t,levelNode:r,biasNode:a,compareNode:u,depthNode:l,gradNode:d}=s,c=this.generateUV(e,t),h=r?r.build(e,"float"):null,p=a?a.build(e,"float"):null,g=l?l.build(e,"int"):null,m=u?u.build(e,"float"):null,f=d?[d[0].build(e,"vec2"),d[1].build(e,"vec2")]:null,y=e.getVarFromNode(this);o=e.getPropertyName(y);const b=this.generateSnippet(e,i,c,h,p,g,m,f);e.addLineFlowCode(`${o} = ${b}`,this),n.snippet=b,n.propertyName=o}let a=o;const u=this.getNodeType(e);return e.needsToWorkingColorSpace(r)&&(a=qa(fu(a,u),r.colorSpace).setup(e).build(e,u)),e.format(a,u,t)}}setSampler(e){return this.sampler=e,this}getSampler(){return this.sampler}uv(e){return console.warn("THREE.TextureNode: .uv() has been renamed. Use .sample() instead."),this.sample(e)}sample(e){const t=this.clone();return t.uvNode=Ti(e),t.referenceNode=this.getSelf(),Ti(t)}blur(e){const t=this.clone();return t.biasNode=Ti(e).mul(Ru(t)),t.referenceNode=this.getSelf(),Ti(t)}level(e){const t=this.clone();return t.levelNode=Ti(e),t.referenceNode=this.getSelf(),Ti(t)}size(e){return Su(this,e)}bias(e){const t=this.clone();return t.biasNode=Ti(e),t.referenceNode=this.getSelf(),Ti(t)}compare(e){const t=this.clone();return t.compareNode=Ti(e),t.referenceNode=this.getSelf(),Ti(t)}grad(e,t){const r=this.clone();return r.gradNode=[Ti(e),Ti(t)],r.referenceNode=this.getSelf(),Ti(r)}depth(e){const t=this.clone();return t.depthNode=Ti(e),t.referenceNode=this.getSelf(),Ti(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 Eu=Ni(Cu),wu=(...e)=>Eu(...e).setSampler(!1),Mu=on("float").label("cameraNear").setGroup(rn).onRenderUpdate((({camera:e})=>e.near)),Bu=on("float").label("cameraFar").setGroup(rn).onRenderUpdate((({camera:e})=>e.far)),Uu=on("mat4").label("cameraProjectionMatrix").setGroup(rn).onRenderUpdate((({camera:e})=>e.projectionMatrix)),Fu=on("mat4").label("cameraProjectionMatrixInverse").setGroup(rn).onRenderUpdate((({camera:e})=>e.projectionMatrixInverse)),Pu=on("mat4").label("cameraViewMatrix").setGroup(rn).onRenderUpdate((({camera:e})=>e.matrixWorldInverse)),Iu=on("mat4").label("cameraWorldMatrix").setGroup(rn).onRenderUpdate((({camera:e})=>e.matrixWorld)),Du=on("mat3").label("cameraNormalMatrix").setGroup(rn).onRenderUpdate((({camera:e})=>e.normalMatrix)),Lu=on(new r).label("cameraPosition").setGroup(rn).onRenderUpdate((({camera:e},t)=>t.value.setFromMatrixPosition(e.matrixWorld)));class Vu extends Ps{static get type(){return"Object3DNode"}constructor(e,t=null){super(),this.scope=e,this.object3d=t,this.updateType=Rs.OBJECT,this._uniformNode=new nn(null)}getNodeType(){const e=this.scope;return e===Vu.WORLD_MATRIX?"mat4":e===Vu.POSITION||e===Vu.VIEW_POSITION||e===Vu.DIRECTION||e===Vu.SCALE?"vec3":void 0}update(e){const t=this.object3d,s=this._uniformNode,i=this.scope;if(i===Vu.WORLD_MATRIX)s.value=t.matrixWorld;else if(i===Vu.POSITION)s.value=s.value||new r,s.value.setFromMatrixPosition(t.matrixWorld);else if(i===Vu.SCALE)s.value=s.value||new r,s.value.setFromMatrixScale(t.matrixWorld);else if(i===Vu.DIRECTION)s.value=s.value||new r,t.getWorldDirection(s.value);else if(i===Vu.VIEW_POSITION){const i=e.camera;s.value=s.value||new r,s.value.setFromMatrixPosition(t.matrixWorld),s.value.applyMatrix4(i.matrixWorldInverse)}}generate(e){const t=this.scope;return t===Vu.WORLD_MATRIX?this._uniformNode.nodeType="mat4":t!==Vu.POSITION&&t!==Vu.VIEW_POSITION&&t!==Vu.DIRECTION&&t!==Vu.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}}Vu.WORLD_MATRIX="worldMatrix",Vu.POSITION="position",Vu.SCALE="scale",Vu.VIEW_POSITION="viewPosition",Vu.DIRECTION="direction";const Ou=Ni(Vu,Vu.DIRECTION),Gu=Ni(Vu,Vu.WORLD_MATRIX),ku=Ni(Vu,Vu.POSITION),zu=Ni(Vu,Vu.SCALE),$u=Ni(Vu,Vu.VIEW_POSITION);class Hu extends Vu{static get type(){return"ModelNode"}constructor(e){super(e)}update(e){this.object3d=e.object,super.update(e)}}const Wu=Si(Hu,Hu.DIRECTION),ju=Si(Hu,Hu.WORLD_MATRIX),qu=Si(Hu,Hu.POSITION),Ku=Si(Hu,Hu.SCALE),Xu=Si(Hu,Hu.VIEW_POSITION),Yu=on(new i).onObjectUpdate((({object:e},t)=>t.value.getNormalMatrix(e.matrixWorld))),Qu=on(new n).onObjectUpdate((({object:e},t)=>t.value.copy(e.matrixWorld).invert())),Zu=Ai((e=>e.renderer.nodes.modelViewMatrix||Ju)).once()().toVar("modelViewMatrix"),Ju=Pu.mul(ju),el=Ai((e=>(e.context.isHighPrecisionModelViewMatrix=!0,on("mat4").onObjectUpdate((({object:e,camera:t})=>e.modelViewMatrix.multiplyMatrices(t.matrixWorldInverse,e.matrixWorld)))))).once()().toVar("highpModelViewMatrix"),tl=Ai((e=>{const t=e.context.isHighPrecisionModelViewMatrix;return on("mat3").onObjectUpdate((({object:e,camera:r})=>(!0!==t&&e.modelViewMatrix.multiplyMatrices(r.matrixWorldInverse,e.matrixWorld),e.normalMatrix.getNormalMatrix(e.modelViewMatrix))))})).once()().toVar("highpModelNormalViewMatrix"),rl=_u("position","vec3"),sl=rl.varying("positionLocal"),il=rl.varying("positionPrevious"),nl=ju.mul(sl).xyz.varying("v_positionWorld").context({needsPositionReassign:!0}),ol=sl.transformDirection(ju).varying("v_positionWorldDirection").normalize().toVar("positionWorldDirection").context({needsPositionReassign:!0}),al=Ai((e=>e.context.setupPositionView()),"vec3").once()().varying("v_positionView").context({needsPositionReassign:!0}),ul=al.negate().varying("v_positionViewDirection").normalize().toVar("positionViewDirection");class ll extends Ps{static get type(){return"FrontFacingNode"}constructor(){super("bool"),this.isFrontFacingNode=!0}generate(e){const{renderer:t,material:r}=e;return t.coordinateSystem===u&&r.side===T?"false":e.getFrontFacing()}}const dl=Si(ll),cl=Bi(dl).mul(2).sub(1),hl=_u("normal","vec3"),pl=Ai((e=>!1===e.geometry.hasAttribute("normal")?(console.warn('TSL.NormalNode: Vertex attribute "normal" not found on geometry.'),Oi(0,1,0)):hl),"vec3").once()().toVar("normalLocal"),gl=al.dFdx().cross(al.dFdy()).normalize().toVar("normalFlat"),ml=Ai((e=>{let t;return t=!0===e.material.flatShading?gl:La(_l(pl),"v_normalView").normalize(),t}),"vec3").once()().toVar("normalView"),fl=La(ml.transformDirection(Pu),"v_normalWorld").normalize().toVar("normalWorld"),yl=Ai((e=>e.context.setupNormal().context({getUV:null})),"vec3").once()().mul(cl).toVar("transformedNormalView"),bl=yl.transformDirection(Pu).toVar("transformedNormalWorld"),xl=Ai((e=>e.context.setupClearcoatNormal().context({getUV:null})),"vec3").once()().mul(cl).toVar("transformedClearcoatNormalView"),Tl=Ai((([e,t=ju])=>{const r=Ki(t),s=e.div(Oi(r[0].dot(r[0]),r[1].dot(r[1]),r[2].dot(r[2])));return r.mul(s).xyz})),_l=Ai((([e],t)=>{const r=t.renderer.nodes.modelNormalViewMatrix;if(null!==r)return r.transformDirection(e);const s=Yu.mul(e);return Pu.transformDirection(s)})),vl=on(0).onReference((({material:e})=>e)).onRenderUpdate((({material:e})=>e.refractionRatio)),Nl=ul.negate().reflect(yl),Sl=ul.negate().refract(yl,vl),Al=Nl.transformDirection(Pu).toVar("reflectVector"),Rl=Sl.transformDirection(Pu).toVar("reflectVector");class Cl extends Cu{static get type(){return"CubeTextureNode"}constructor(e,t=null,r=null,s=null){super(e,t,r,s),this.isCubeTextureNode=!0}getInputType(){return"cubeTexture"}getDefaultUV(){const e=this.value;return e.mapping===_?Al:e.mapping===v?Rl:(console.error('THREE.CubeTextureNode: Mapping "%s" not supported.',e.mapping),Oi(0,0,0))}setUpdateMatrix(){}setupUV(e,t){const r=this.value;return e.renderer.coordinateSystem!==l&&r.isRenderTargetTexture?t:Oi(t.x.negate(),t.yz)}generateUV(e,t){return t.build(e,"vec3")}}const El=Ni(Cl);class wl extends nn{static get type(){return"BufferNode"}constructor(e,t,r=0){super(e,t),this.isBufferNode=!0,this.bufferType=t,this.bufferCount=r}getElementType(e){return this.getNodeType(e)}getInputType(){return"buffer"}}const Ml=(e,t,r)=>Ti(new wl(e,t,r));class Bl extends Is{static get type(){return"UniformArrayElementNode"}constructor(e,t){super(e,t),this.isArrayBufferElementNode=!0}generate(e){const t=super.generate(e),r=this.getNodeType(),s=this.node.getPaddedType();return e.format(t,s,r)}}class Ul extends wl{static get type(){return"UniformArrayNode"}constructor(e,t=null){super(null),this.array=e,this.elementType=null===t?xs(e[0]):t,this.paddedType=this.getPaddedType(),this.updateType=Rs.RENDER,this.isArrayBufferNode=!0}getNodeType(){return this.paddedType}getElementType(){return this.elementType}getPaddedType(){const e=this.elementType;let t="vec4";return"mat2"===e?t="mat2":!0===/mat/.test(e)?t="mat4":"i"===e.charAt(0)?t="ivec4":"u"===e.charAt(0)&&(t="uvec4"),t}update(){const{array:e,value:t}=this,r=this.elementType;if("float"===r||"int"===r||"uint"===r)for(let r=0;rTi(new Ul(e,t));class Pl extends Is{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),r=this.referenceNode.getNodeType(),s=this.getNodeType();return e.format(t,r,s)}}class Il extends Ps{static get type(){return"ReferenceNode"}constructor(e,t,r=null,s=null){super(),this.property=e,this.uniformType=t,this.object=r,this.count=s,this.properties=e.split("."),this.reference=r,this.node=null,this.group=null,this.name=null,this.updateType=Rs.OBJECT}element(e){return Ti(new Pl(this,Ti(e)))}setGroup(e){return this.group=e,this}label(e){return this.name=e,this}setNodeType(e){let t=null;t=null!==this.count?Ml(null,e,this.count):Array.isArray(this.getValueFromReference())?Fl(null,e):"texture"===e?Eu(null):"cubeTexture"===e?El(null):on(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 r=e[t[0]];for(let e=1;eTi(new Il(e,t,r)),Ll=(e,t,r,s)=>Ti(new Il(e,t,s,r));class Vl extends Il{static get type(){return"MaterialReferenceNode"}constructor(e,t,r=null){super(e,t,r),this.material=r,this.isMaterialReferenceNode=!0}updateReference(e){return this.reference=null!==this.material?this.material:e.material,this.reference}}const Ol=(e,t,r=null)=>Ti(new Vl(e,t,r)),Gl=Ai((e=>(!1===e.geometry.hasAttribute("tangent")&&e.geometry.computeTangents(),_u("tangent","vec4"))))(),kl=Gl.xyz.toVar("tangentLocal"),zl=Zu.mul($i(kl,0)).xyz.varying("v_tangentView").normalize().toVar("tangentView"),$l=zl.transformDirection(Pu).varying("v_tangentWorld").normalize().toVar("tangentWorld"),Hl=zl.toVar("transformedTangentView"),Wl=Hl.transformDirection(Pu).normalize().toVar("transformedTangentWorld"),jl=e=>e.mul(Gl.w).xyz,ql=La(jl(hl.cross(Gl)),"v_bitangentGeometry").normalize().toVar("bitangentGeometry"),Kl=La(jl(pl.cross(kl)),"v_bitangentLocal").normalize().toVar("bitangentLocal"),Xl=La(jl(ml.cross(zl)),"v_bitangentView").normalize().toVar("bitangentView"),Yl=La(jl(fl.cross($l)),"v_bitangentWorld").normalize().toVar("bitangentWorld"),Ql=jl(yl.cross(Hl)).normalize().toVar("transformedBitangentView"),Zl=Ql.transformDirection(Pu).normalize().toVar("transformedBitangentWorld"),Jl=Ki(zl,Xl,ml),ed=ul.mul(Jl),td=(()=>{let e=Sn.cross(ul);return e=e.cross(Sn).normalize(),e=pa(e,yl,vn.mul(hn.oneMinus()).oneMinus().pow2().pow2()).normalize(),e})(),rd=Ai((e=>{const{eye_pos:t,surf_norm:r,mapN:s,uv:i}=e,n=t.dFdx(),o=t.dFdy(),a=i.dFdx(),u=i.dFdy(),l=r,d=o.cross(l),c=l.cross(n),h=d.mul(a.x).add(c.mul(u.x)),p=d.mul(a.y).add(c.mul(u.y)),g=h.dot(h).max(p.dot(p)),m=cl.mul(g.inverseSqrt());return $n(h.mul(s.x,m),p.mul(s.y,m),l.mul(s.z)).normalize()}));class sd extends Ls{static get type(){return"NormalMapNode"}constructor(e,t=null){super("vec3"),this.node=e,this.scaleNode=t,this.normalMapType=N}setup(e){const{normalMapType:t,scaleNode:r}=this;let s=this.node.mul(2).sub(1);null!==r&&(s=Oi(s.xy.mul(r),s.z));let i=null;if(t===S)i=_l(s);else if(t===N){i=!0===e.hasGeometryAttribute("tangent")?Jl.mul(s).normalize():rd({eye_pos:al,surf_norm:ml,mapN:s,uv:vu()})}return i}}const id=Ni(sd),nd=Ai((({textureNode:e,bumpScale:t})=>{const r=t=>e.cache().context({getUV:e=>t(e.uvNode||vu()),forceUVContext:!0}),s=Bi(r((e=>e)));return Ii(Bi(r((e=>e.add(e.dFdx())))).sub(s),Bi(r((e=>e.add(e.dFdy())))).sub(s)).mul(t)})),od=Ai((e=>{const{surf_pos:t,surf_norm:r,dHdxy:s}=e,i=t.dFdx().normalize(),n=r,o=t.dFdy().normalize().cross(n),a=n.cross(i),u=i.dot(o).mul(cl),l=u.sign().mul(s.x.mul(o).add(s.y.mul(a)));return u.abs().mul(r).sub(l).normalize()}));class ad extends Ls{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=nd({textureNode:this.textureNode,bumpScale:e});return od({surf_pos:al,surf_norm:ml,dHdxy:t})}}const ud=Ni(ad),ld=new Map;class dd extends Ps{static get type(){return"MaterialNode"}constructor(e){super(),this.scope=e}getCache(e,t){let r=ld.get(e);return void 0===r&&(r=Ol(e,t),ld.set(e,r)),r}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,r=this.scope;let s=null;if(r===dd.COLOR){const e=void 0!==t.color?this.getColor(r):Oi();s=t.map&&!0===t.map.isTexture?e.mul(this.getTexture("map")):e}else if(r===dd.OPACITY){const e=this.getFloat(r);s=t.alphaMap&&!0===t.alphaMap.isTexture?e.mul(this.getTexture("alpha")):e}else if(r===dd.SPECULAR_STRENGTH)s=t.specularMap&&!0===t.specularMap.isTexture?this.getTexture("specular").r:Bi(1);else if(r===dd.SPECULAR_INTENSITY){const e=this.getFloat(r);s=t.specularIntensityMap&&!0===t.specularIntensityMap.isTexture?e.mul(this.getTexture(r).a):e}else if(r===dd.SPECULAR_COLOR){const e=this.getColor(r);s=t.specularColorMap&&!0===t.specularColorMap.isTexture?e.mul(this.getTexture(r).rgb):e}else if(r===dd.ROUGHNESS){const e=this.getFloat(r);s=t.roughnessMap&&!0===t.roughnessMap.isTexture?e.mul(this.getTexture(r).g):e}else if(r===dd.METALNESS){const e=this.getFloat(r);s=t.metalnessMap&&!0===t.metalnessMap.isTexture?e.mul(this.getTexture(r).b):e}else if(r===dd.EMISSIVE){const e=this.getFloat("emissiveIntensity"),i=this.getColor(r).mul(e);s=t.emissiveMap&&!0===t.emissiveMap.isTexture?i.mul(this.getTexture(r)):i}else if(r===dd.NORMAL)t.normalMap?(s=id(this.getTexture("normal"),this.getCache("normalScale","vec2")),s.normalMapType=t.normalMapType):s=t.bumpMap?ud(this.getTexture("bump").r,this.getFloat("bumpScale")):ml;else if(r===dd.CLEARCOAT){const e=this.getFloat(r);s=t.clearcoatMap&&!0===t.clearcoatMap.isTexture?e.mul(this.getTexture(r).r):e}else if(r===dd.CLEARCOAT_ROUGHNESS){const e=this.getFloat(r);s=t.clearcoatRoughnessMap&&!0===t.clearcoatRoughnessMap.isTexture?e.mul(this.getTexture(r).r):e}else if(r===dd.CLEARCOAT_NORMAL)s=t.clearcoatNormalMap?id(this.getTexture(r),this.getCache(r+"Scale","vec2")):ml;else if(r===dd.SHEEN){const e=this.getColor("sheenColor").mul(this.getFloat("sheen"));s=t.sheenColorMap&&!0===t.sheenColorMap.isTexture?e.mul(this.getTexture("sheenColor").rgb):e}else if(r===dd.SHEEN_ROUGHNESS){const e=this.getFloat(r);s=t.sheenRoughnessMap&&!0===t.sheenRoughnessMap.isTexture?e.mul(this.getTexture(r).a):e,s=s.clamp(.07,1)}else if(r===dd.ANISOTROPY)if(t.anisotropyMap&&!0===t.anisotropyMap.isTexture){const e=this.getTexture(r);s=qi(Kd.x,Kd.y,Kd.y.negate(),Kd.x).mul(e.rg.mul(2).sub(Ii(1)).normalize().mul(e.b))}else s=Kd;else if(r===dd.IRIDESCENCE_THICKNESS){const e=Dl("1","float",t.iridescenceThicknessRange);if(t.iridescenceThicknessMap){const i=Dl("0","float",t.iridescenceThicknessRange);s=e.sub(i).mul(this.getTexture(r).g).add(i)}else s=e}else if(r===dd.TRANSMISSION){const e=this.getFloat(r);s=t.transmissionMap?e.mul(this.getTexture(r).r):e}else if(r===dd.THICKNESS){const e=this.getFloat(r);s=t.thicknessMap?e.mul(this.getTexture(r).g):e}else if(r===dd.IOR)s=this.getFloat(r);else if(r===dd.LIGHT_MAP)s=this.getTexture(r).rgb.mul(this.getFloat("lightMapIntensity"));else if(r===dd.AO)s=this.getTexture(r).r.sub(1).mul(this.getFloat("aoMapIntensity")).add(1);else{const t=this.getNodeType(e);s=this.getCache(r,t)}return s}}dd.ALPHA_TEST="alphaTest",dd.COLOR="color",dd.OPACITY="opacity",dd.SHININESS="shininess",dd.SPECULAR="specular",dd.SPECULAR_STRENGTH="specularStrength",dd.SPECULAR_INTENSITY="specularIntensity",dd.SPECULAR_COLOR="specularColor",dd.REFLECTIVITY="reflectivity",dd.ROUGHNESS="roughness",dd.METALNESS="metalness",dd.NORMAL="normal",dd.CLEARCOAT="clearcoat",dd.CLEARCOAT_ROUGHNESS="clearcoatRoughness",dd.CLEARCOAT_NORMAL="clearcoatNormal",dd.EMISSIVE="emissive",dd.ROTATION="rotation",dd.SHEEN="sheen",dd.SHEEN_ROUGHNESS="sheenRoughness",dd.ANISOTROPY="anisotropy",dd.IRIDESCENCE="iridescence",dd.IRIDESCENCE_IOR="iridescenceIOR",dd.IRIDESCENCE_THICKNESS="iridescenceThickness",dd.IOR="ior",dd.TRANSMISSION="transmission",dd.THICKNESS="thickness",dd.ATTENUATION_DISTANCE="attenuationDistance",dd.ATTENUATION_COLOR="attenuationColor",dd.LINE_SCALE="scale",dd.LINE_DASH_SIZE="dashSize",dd.LINE_GAP_SIZE="gapSize",dd.LINE_WIDTH="linewidth",dd.LINE_DASH_OFFSET="dashOffset",dd.POINT_SIZE="size",dd.DISPERSION="dispersion",dd.LIGHT_MAP="light",dd.AO="ao";const cd=Si(dd,dd.ALPHA_TEST),hd=Si(dd,dd.COLOR),pd=Si(dd,dd.SHININESS),gd=Si(dd,dd.EMISSIVE),md=Si(dd,dd.OPACITY),fd=Si(dd,dd.SPECULAR),yd=Si(dd,dd.SPECULAR_INTENSITY),bd=Si(dd,dd.SPECULAR_COLOR),xd=Si(dd,dd.SPECULAR_STRENGTH),Td=Si(dd,dd.REFLECTIVITY),_d=Si(dd,dd.ROUGHNESS),vd=Si(dd,dd.METALNESS),Nd=Si(dd,dd.NORMAL),Sd=Si(dd,dd.CLEARCOAT),Ad=Si(dd,dd.CLEARCOAT_ROUGHNESS),Rd=Si(dd,dd.CLEARCOAT_NORMAL),Cd=Si(dd,dd.ROTATION),Ed=Si(dd,dd.SHEEN),wd=Si(dd,dd.SHEEN_ROUGHNESS),Md=Si(dd,dd.ANISOTROPY),Bd=Si(dd,dd.IRIDESCENCE),Ud=Si(dd,dd.IRIDESCENCE_IOR),Fd=Si(dd,dd.IRIDESCENCE_THICKNESS),Pd=Si(dd,dd.TRANSMISSION),Id=Si(dd,dd.THICKNESS),Dd=Si(dd,dd.IOR),Ld=Si(dd,dd.ATTENUATION_DISTANCE),Vd=Si(dd,dd.ATTENUATION_COLOR),Od=Si(dd,dd.LINE_SCALE),Gd=Si(dd,dd.LINE_DASH_SIZE),kd=Si(dd,dd.LINE_GAP_SIZE),zd=Si(dd,dd.LINE_WIDTH),$d=Si(dd,dd.LINE_DASH_OFFSET),Hd=Si(dd,dd.POINT_SIZE),Wd=Si(dd,dd.DISPERSION),jd=Si(dd,dd.LIGHT_MAP),qd=Si(dd,dd.AO),Kd=on(new t).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))})),Xd=Ai((e=>e.context.setupModelViewProjection()),"vec4").once()().varying("v_modelViewProjection");class Yd extends Ps{static get type(){return"IndexNode"}constructor(e){super("uint"),this.scope=e,this.isIndexNode=!0}generate(e){const t=this.getNodeType(e),r=this.scope;let s,i;if(r===Yd.VERTEX)s=e.getVertexIndex();else if(r===Yd.INSTANCE)s=e.getInstanceIndex();else if(r===Yd.DRAW)s=e.getDrawIndex();else if(r===Yd.INVOCATION_LOCAL)s=e.getInvocationLocalIndex();else if(r===Yd.INVOCATION_SUBGROUP)s=e.getInvocationSubgroupIndex();else{if(r!==Yd.SUBGROUP)throw new Error("THREE.IndexNode: Unknown scope: "+r);s=e.getSubgroupIndex()}if("vertex"===e.shaderStage||"compute"===e.shaderStage)i=s;else{i=La(this).build(e,t)}return i}}Yd.VERTEX="vertex",Yd.INSTANCE="instance",Yd.SUBGROUP="subgroup",Yd.INVOCATION_LOCAL="invocationLocal",Yd.INVOCATION_SUBGROUP="invocationSubgroup",Yd.DRAW="draw";const Qd=Si(Yd,Yd.VERTEX),Zd=Si(Yd,Yd.INSTANCE),Jd=Si(Yd,Yd.SUBGROUP),ec=Si(Yd,Yd.INVOCATION_SUBGROUP),tc=Si(Yd,Yd.INVOCATION_LOCAL),rc=Si(Yd,Yd.DRAW);class sc extends Ps{static get type(){return"InstanceNode"}constructor(e,t,r){super("void"),this.count=e,this.instanceMatrix=t,this.instanceColor=r,this.instanceMatrixNode=null,this.instanceColorNode=null,this.updateType=Rs.FRAME,this.buffer=null,this.bufferColor=null}setup(e){const{count:t,instanceMatrix:r,instanceColor:s}=this;let{instanceMatrixNode:i,instanceColorNode:n}=this;if(null===i){if(t<=1e3)i=Ml(r.array,"mat4",Math.max(t,1)).element(Zd);else{const e=new A(r.array,16,1);this.buffer=e;const t=r.usage===m?nu:iu,s=[t(e,"vec4",16,0),t(e,"vec4",16,4),t(e,"vec4",16,8),t(e,"vec4",16,12)];i=Xi(...s)}this.instanceMatrixNode=i}if(s&&null===n){const e=new R(s.array,3),t=s.usage===m?nu:iu;this.bufferColor=e,n=Oi(t(e,"vec3",3,0)),this.instanceColorNode=n}const o=i.mul(sl).xyz;if(sl.assign(o),e.hasGeometryAttribute("normal")){const e=Tl(pl,i);pl.assign(e)}null!==this.instanceColorNode&&ln("vec3","vInstanceColor").assign(this.instanceColorNode)}update(){this.instanceMatrix.usage!==m&&null!==this.buffer&&this.instanceMatrix.version!==this.buffer.version&&(this.buffer.version=this.instanceMatrix.version),this.instanceColor&&this.instanceColor.usage!==m&&null!==this.bufferColor&&this.instanceColor.version!==this.bufferColor.version&&(this.bufferColor.version=this.instanceColor.version)}}const ic=Ni(sc);class nc extends sc{static get type(){return"InstancedMeshNode"}constructor(e){const{count:t,instanceMatrix:r,instanceColor:s}=e;super(t,r,s),this.instancedMesh=e}}const oc=Ni(nc);class ac extends Ps{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=Zd:this.batchingIdNode=rc);const t=Ai((([e])=>{const t=Su(wu(this.batchMesh._indirectTexture),0),r=Ui(e).modInt(Ui(t)),s=Ui(e).div(Ui(t));return wu(this.batchMesh._indirectTexture,Di(r,s)).x})).setLayout({name:"getIndirectIndex",type:"uint",inputs:[{name:"id",type:"int"}]}),r=t(Ui(this.batchingIdNode)),s=this.batchMesh._matricesTexture,i=Su(wu(s),0),n=Bi(r).mul(4).toInt().toVar(),o=n.modInt(i),a=n.div(Ui(i)),u=Xi(wu(s,Di(o,a)),wu(s,Di(o.add(1),a)),wu(s,Di(o.add(2),a)),wu(s,Di(o.add(3),a))),l=this.batchMesh._colorsTexture;if(null!==l){const e=Ai((([e])=>{const t=Su(wu(l),0).x,r=e,s=r.modInt(t),i=r.div(t);return wu(l,Di(s,i)).rgb})).setLayout({name:"getBatchingColor",type:"vec3",inputs:[{name:"id",type:"int"}]}),t=e(r);ln("vec3","vBatchColor").assign(t)}const d=Ki(u);sl.assign(u.mul(sl));const c=pl.div(Oi(d[0].dot(d[0]),d[1].dot(d[1]),d[2].dot(d[2]))),h=d.mul(c).xyz;pl.assign(h),e.hasGeometryAttribute("tangent")&&kl.mulAssign(d)}}const uc=Ni(ac),lc=new WeakMap;class dc extends Ps{static get type(){return"SkinningNode"}constructor(e,t=!1){let r,s,i;super("void"),this.skinnedMesh=e,this.useReference=t,this.updateType=Rs.OBJECT,this.skinIndexNode=_u("skinIndex","uvec4"),this.skinWeightNode=_u("skinWeight","vec4"),t?(r=Dl("bindMatrix","mat4"),s=Dl("bindMatrixInverse","mat4"),i=Ll("skeleton.boneMatrices","mat4",e.skeleton.bones.length)):(r=on(e.bindMatrix,"mat4"),s=on(e.bindMatrixInverse,"mat4"),i=Ml(e.skeleton.boneMatrices,"mat4",e.skeleton.bones.length)),this.bindMatrixNode=r,this.bindMatrixInverseNode=s,this.boneMatricesNode=i,this.previousBoneMatricesNode=null}getSkinnedPosition(e=this.boneMatricesNode,t=sl){const{skinIndexNode:r,skinWeightNode:s,bindMatrixNode:i,bindMatrixInverseNode:n}=this,o=e.element(r.x),a=e.element(r.y),u=e.element(r.z),l=e.element(r.w),d=i.mul(t),c=$n(o.mul(s.x).mul(d),a.mul(s.y).mul(d),u.mul(s.z).mul(d),l.mul(s.w).mul(d));return n.mul(c).xyz}getSkinnedNormal(e=this.boneMatricesNode,t=pl){const{skinIndexNode:r,skinWeightNode:s,bindMatrixNode:i,bindMatrixInverseNode:n}=this,o=e.element(r.x),a=e.element(r.y),u=e.element(r.z),l=e.element(r.w);let d=$n(s.x.mul(o),s.y.mul(a),s.z.mul(u),s.w.mul(l));return d=n.mul(d).mul(i),d.transformDirection(t).xyz}getPreviousSkinnedPosition(e){const t=e.object;return null===this.previousBoneMatricesNode&&(t.skeleton.previousBoneMatrices=new Float32Array(t.skeleton.boneMatrices),this.previousBoneMatricesNode=Ll("skeleton.previousBoneMatrices","mat4",t.skeleton.bones.length)),this.getSkinnedPosition(this.previousBoneMatricesNode,il)}needsPreviousBoneMatrices(e){const t=e.renderer.getMRT();return t&&t.has("velocity")||!0===_s(e.object).useVelocity}setup(e){this.needsPreviousBoneMatrices(e)&&il.assign(this.getPreviousSkinnedPosition(e));const t=this.getSkinnedPosition();if(sl.assign(t),e.hasGeometryAttribute("normal")){const t=this.getSkinnedNormal();pl.assign(t),e.hasGeometryAttribute("tangent")&&kl.assign(t)}}generate(e,t){if("void"!==t)return sl.build(e,t)}update(e){const t=(this.useReference?e.object:this.skinnedMesh).skeleton;lc.get(t)!==e.frameId&&(lc.set(t,e.frameId),null!==this.previousBoneMatricesNode&&t.previousBoneMatrices.set(t.boneMatrices),t.update())}}const cc=e=>Ti(new dc(e,!0));class hc extends Ps{static get type(){return"LoopNode"}constructor(e=[]){super(),this.params=e}getVarName(e){return String.fromCharCode("i".charCodeAt(0)+e)}getProperties(e){const t=e.getNodeProperties(this);if(void 0!==t.stackNode)return t;const r={};for(let e=0,t=this.params.length-1;eNumber(n)?">=":"<"));const d={start:i,end:n,condition:u},c=d.start,h=d.end;let p="",g="",m="";l||(l="int"===a||"uint"===a?u.includes("<")?"++":"--":u.includes("<")?"+= 1.":"-= 1."),p+=e.getVar(a,o)+" = "+c,g+=o+" "+u+" "+h,m+=o+" "+l;const f=`for ( ${p}; ${g}; ${m} )`;e.addFlowCode((0===t?"\n":"")+e.tab+f+" {\n\n").addFlowTab()}const i=s.build(e,"void"),n=t.returnsNode?t.returnsNode.build(e):"";e.removeFlowTab().addFlowCode("\n"+e.tab+i);for(let t=0,r=this.params.length-1;tTi(new hc(vi(e,"int"))).append(),gc=()=>fu("break").append(),mc=new WeakMap,fc=new s,yc=Ai((({bufferMap:e,influence:t,stride:r,width:s,depth:i,offset:n})=>{const o=Ui(Qd).mul(r).add(n),a=o.div(s),u=o.sub(a.mul(s));return wu(e,Di(u,a)).depth(i).mul(t)}));class bc extends Ps{static get type(){return"MorphNode"}constructor(e){super("void"),this.mesh=e,this.morphBaseInfluence=on(1),this.updateType=Rs.OBJECT}setup(e){const{geometry:r}=e,s=void 0!==r.morphAttributes.position,i=r.hasAttribute("normal")&&void 0!==r.morphAttributes.normal,n=r.morphAttributes.position||r.morphAttributes.normal||r.morphAttributes.color,o=void 0!==n?n.length:0,{texture:a,stride:u,size:l}=function(e){const r=void 0!==e.morphAttributes.position,s=void 0!==e.morphAttributes.normal,i=void 0!==e.morphAttributes.color,n=e.morphAttributes.position||e.morphAttributes.normal||e.morphAttributes.color,o=void 0!==n?n.length:0;let a=mc.get(e);if(void 0===a||a.count!==o){void 0!==a&&a.texture.dispose();const u=e.morphAttributes.position||[],l=e.morphAttributes.normal||[],d=e.morphAttributes.color||[];let c=0;!0===r&&(c=1),!0===s&&(c=2),!0===i&&(c=3);let h=e.attributes.position.count*c,p=1;const g=4096;h>g&&(p=Math.ceil(h/g),h=g);const m=new Float32Array(h*p*4*o),f=new C(m,h,p,o);f.type=E,f.needsUpdate=!0;const y=4*c;for(let x=0;x{const t=Bi(0).toVar();this.mesh.count>1&&null!==this.mesh.morphTexture&&void 0!==this.mesh.morphTexture?t.assign(wu(this.mesh.morphTexture,Di(Ui(e).add(1),Ui(Zd))).r):t.assign(Dl("morphTargetInfluences","float").element(e).toVar()),!0===s&&sl.addAssign(yc({bufferMap:a,influence:t,stride:u,width:d,depth:e,offset:Ui(0)})),!0===i&&pl.addAssign(yc({bufferMap:a,influence:t,stride:u,width:d,depth:e,offset:Ui(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 xc=Ni(bc);class Tc extends Ps{static get type(){return"LightingNode"}constructor(){super("vec3"),this.isLightingNode=!0}}class _c extends Tc{static get type(){return"AONode"}constructor(e=null){super(),this.aoNode=e}setup(e){e.context.ambientOcclusion.mulAssign(this.aoNode)}}class vc extends Ea{static get type(){return"LightingContextNode"}constructor(e,t=null,r=null,s=null){super(e),this.lightingModel=t,this.backdropNode=r,this.backdropAlphaNode=s,this._value=null}getContext(){const{backdropNode:e,backdropAlphaNode:t}=this,r={directDiffuse:Oi().toVar("directDiffuse"),directSpecular:Oi().toVar("directSpecular"),indirectDiffuse:Oi().toVar("indirectDiffuse"),indirectSpecular:Oi().toVar("indirectSpecular")};return{radiance:Oi().toVar("radiance"),irradiance:Oi().toVar("irradiance"),iblIrradiance:Oi().toVar("iblIrradiance"),ambientOcclusion:Bi(1).toVar("ambientOcclusion"),reflectedLight:r,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 Nc=Ni(vc);class Sc extends Tc{static get type(){return"IrradianceNode"}constructor(e){super(),this.node=e}setup(e){e.context.irradiance.addAssign(this.node)}}let Ac,Rc;class Cc extends Ps{static get type(){return"ScreenNode"}constructor(e){super(),this.scope=e,this.isViewportNode=!0}getNodeType(){return this.scope===Cc.VIEWPORT?"vec4":"vec2"}getUpdateType(){let e=Rs.NONE;return this.scope!==Cc.SIZE&&this.scope!==Cc.VIEWPORT||(e=Rs.RENDER),this.updateType=e,e}update({renderer:e}){const t=e.getRenderTarget();this.scope===Cc.VIEWPORT?null!==t?Rc.copy(t.viewport):(e.getViewport(Rc),Rc.multiplyScalar(e.getPixelRatio())):null!==t?(Ac.width=t.width,Ac.height=t.height):e.getDrawingBufferSize(Ac)}setup(){const e=this.scope;let r=null;return r=e===Cc.SIZE?on(Ac||(Ac=new t)):e===Cc.VIEWPORT?on(Rc||(Rc=new s)):Ii(Mc.div(wc)),r}generate(e){if(this.scope===Cc.COORDINATE){let t=e.getFragCoord();if(e.isFlipY()){const r=e.getNodeProperties(wc).outputNode.build(e);t=`${e.getType("vec2")}( ${t}.x, ${r}.y - ${t}.y )`}return t}return super.generate(e)}}Cc.COORDINATE="coordinate",Cc.VIEWPORT="viewport",Cc.SIZE="size",Cc.UV="uv";const Ec=Si(Cc,Cc.UV),wc=Si(Cc,Cc.SIZE),Mc=Si(Cc,Cc.COORDINATE),Bc=Si(Cc,Cc.VIEWPORT),Uc=Bc.zw,Fc=Mc.sub(Bc.xy),Pc=Fc.div(Uc),Ic=Ai((()=>(console.warn('TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.'),wc)),"vec2").once()(),Dc=Ai((()=>(console.warn('TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.'),Ec)),"vec2").once()(),Lc=Ai((()=>(console.warn('TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.'),Ec.flipY())),"vec2").once()(),Vc=new t;class Oc extends Cu{static get type(){return"ViewportTextureNode"}constructor(e=Ec,t=null,r=null){null===r&&((r=new w).minFilter=M),super(r,e,t),this.generateMipmaps=!1,this.isOutputTextureNode=!0,this.updateBeforeType=Rs.FRAME}updateBefore(e){const t=e.renderer;t.getDrawingBufferSize(Vc);const r=this.value;r.image.width===Vc.width&&r.image.height===Vc.height||(r.image.width=Vc.width,r.image.height=Vc.height,r.needsUpdate=!0);const s=r.generateMipmaps;r.generateMipmaps=this.generateMipmaps,t.copyFramebufferToTexture(r),r.generateMipmaps=s}clone(){const e=new this.constructor(this.uvNode,this.levelNode,this.value);return e.generateMipmaps=this.generateMipmaps,e}}const Gc=Ni(Oc),kc=Ni(Oc,null,null,{generateMipmaps:!0});let zc=null;class $c extends Oc{static get type(){return"ViewportDepthTextureNode"}constructor(e=Ec,t=null){null===zc&&(zc=new B),super(e,t,zc)}}const Hc=Ni($c);class Wc extends Ps{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===Wc.DEPTH_BASE?e.getFragDepth():super.generate(e)}setup({camera:e}){const{scope:t}=this,r=this.valueNode;let s=null;if(t===Wc.DEPTH_BASE)null!==r&&(s=Yc().assign(r));else if(t===Wc.DEPTH)s=e.isPerspectiveCamera?qc(al.z,Mu,Bu):jc(al.z,Mu,Bu);else if(t===Wc.LINEAR_DEPTH)if(null!==r)if(e.isPerspectiveCamera){const e=Kc(r,Mu,Bu);s=jc(e,Mu,Bu)}else s=r;else s=jc(al.z,Mu,Bu);return s}}Wc.DEPTH_BASE="depthBase",Wc.DEPTH="depth",Wc.LINEAR_DEPTH="linearDepth";const jc=(e,t,r)=>e.add(t).div(t.sub(r)),qc=(e,t,r)=>t.add(e).mul(r).div(r.sub(t).mul(e)),Kc=(e,t,r)=>t.mul(r).div(r.sub(t).mul(e).sub(r)),Xc=(e,t,r)=>{t=t.max(1e-6).toVar();const s=So(e.negate().div(t)),i=So(r.div(t));return s.div(i)},Yc=Ni(Wc,Wc.DEPTH_BASE),Qc=Si(Wc,Wc.DEPTH),Zc=Ni(Wc,Wc.LINEAR_DEPTH),Jc=Zc(Hc());Qc.assign=e=>Yc(e);const eh=Ni(class extends Ps{constructor(e){super("float"),this.name=e,this.isBuiltinNode=!0}generate(){return this.name}});class th extends Ps{static get type(){return"ClippingNode"}constructor(e=th.DEFAULT){super(),this.scope=e}setup(e){super.setup(e);const t=e.clippingContext,{intersectionPlanes:r,unionPlanes:s}=t;return this.hardwareClipping=e.material.hardwareClipping,this.scope===th.ALPHA_TO_COVERAGE?this.setupAlphaToCoverage(r,s):this.scope===th.HARDWARE?this.setupHardwareClipping(s,e):this.setupDefault(r,s)}setupAlphaToCoverage(e,t){return Ai((()=>{const r=Bi().toVar("distanceToPlane"),s=Bi().toVar("distanceToGradient"),i=Bi(1).toVar("clipOpacity"),n=t.length;if(!1===this.hardwareClipping&&n>0){const e=Fl(t);pc(n,(({i:t})=>{const n=e.element(t);r.assign(al.dot(n.xyz).negate().add(n.w)),s.assign(r.fwidth().div(2)),i.mulAssign(ya(s.negate(),s,r))}))}const o=e.length;if(o>0){const t=Fl(e),n=Bi(1).toVar("intersectionClipOpacity");pc(o,(({i:e})=>{const i=t.element(e);r.assign(al.dot(i.xyz).negate().add(i.w)),s.assign(r.fwidth().div(2)),n.mulAssign(ya(s.negate(),s,r).oneMinus())})),i.mulAssign(n.oneMinus())}dn.a.mulAssign(i),dn.a.equal(0).discard()}))()}setupDefault(e,t){return Ai((()=>{const r=t.length;if(!1===this.hardwareClipping&&r>0){const e=Fl(t);pc(r,(({i:t})=>{const r=e.element(t);al.dot(r.xyz).greaterThan(r.w).discard()}))}const s=e.length;if(s>0){const t=Fl(e),r=Pi(!0).toVar("clipped");pc(s,(({i:e})=>{const s=t.element(e);r.assign(al.dot(s.xyz).greaterThan(s.w).and(r))})),r.discard()}}))()}setupHardwareClipping(e,t){const r=e.length;return t.enableHardwareClipping(r),Ai((()=>{const s=Fl(e),i=eh(t.getClipDistance());pc(r,(({i:e})=>{const t=s.element(e),r=al.dot(t.xyz).sub(t.w).negate();i.element(e).assign(r)}))}))()}}th.ALPHA_TO_COVERAGE="alphaToCoverage",th.DEFAULT="default",th.HARDWARE="hardware";const rh=Ai((([e])=>Mo(Wn(1e4,Bo(Wn(17,e.x).add(Wn(.1,e.y)))).mul($n(.1,Lo(Bo(Wn(13,e.y).add(e.x)))))))),sh=Ai((([e])=>rh(Ii(rh(e.xy),e.z)))),ih=Ai((([e])=>{const t=Zo(Oo(zo(e.xyz)),Oo($o(e.xyz))),r=Bi(1).div(Bi(.05).mul(t)).toVar("pixScale"),s=Ii(vo(Co(So(r))),vo(Eo(So(r)))),i=Ii(sh(Co(s.x.mul(e.xyz))),sh(Co(s.y.mul(e.xyz)))),n=Mo(So(r)),o=$n(Wn(n.oneMinus(),i.x),Wn(n,i.y)),a=Qo(n,n.oneMinus()),u=Oi(o.mul(o).div(Wn(2,a).mul(Hn(1,a))),o.sub(Wn(.5,a)).div(Hn(1,a)),Hn(1,Hn(1,o).mul(Hn(1,o)).div(Wn(2,a).mul(Hn(1,a))))),l=o.lessThan(a.oneMinus()).select(o.lessThan(a).select(u.x,u.y),u.z);return ga(l,1e-6,1)})).setLayout({name:"getAlphaHashThreshold",type:"float",inputs:[{name:"position",type:"vec3"}]});class nh extends U{static get type(){return"NodeMaterial"}get type(){return this.constructor.type}set type(e){}constructor(){super(),this.isNodeMaterial=!0,this.fog=!0,this.lights=!1,this.hardwareClipping=!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.geometryNode=null,this.depthNode=null,this.shadowPositionNode=null,this.receivedShadowNode=null,this.castShadowNode=null,this.outputNode=null,this.mrtNode=null,this.fragmentNode=null,this.vertexNode=null}customProgramCacheKey(){return this.type+hs(this)}build(e){this.setup(e)}setupObserver(e){return new as(e)}setup(e){e.context.setupNormal=()=>this.setupNormal(e),e.context.setupPositionView=()=>this.setupPositionView(e),e.context.setupModelViewProjection=()=>this.setupModelViewProjection(e);const t=e.renderer,r=t.getRenderTarget();e.addStack();const s=this.vertexNode||this.setupVertex(e);let i;e.stack.outputNode=s,this.setupHardwareClipping(e),null!==this.geometryNode&&(e.stack.outputNode=e.stack.outputNode.bypass(this.geometryNode)),e.addFlow("vertex",e.removeStack()),e.addStack();const n=this.setupClipping(e);if(!0!==this.depthWrite&&!0!==this.depthTest||(null!==r?!0===r.depthBuffer&&this.setupDepth(e):!0===t.depth&&this.setupDepth(e)),null===this.fragmentNode){this.setupDiffuseColor(e),this.setupVariants(e);const s=this.setupLighting(e);null!==n&&e.stack.add(n);const o=$i(s,dn.a).max(0);if(i=this.setupOutput(e,o),En.assign(i),null!==this.outputNode&&(i=this.outputNode),null!==r){const e=t.getMRT(),r=this.mrtNode;null!==e?(i=e,null!==r&&(i=e.merge(r))):null!==r&&(i=r)}}else{let t=this.fragmentNode;!0!==t.isOutputStructNode&&(t=$i(t)),i=this.setupOutput(e,t)}e.stack.outputNode=i,e.addFlow("fragment",e.removeStack()),e.monitor=this.setupObserver(e)}setupClipping(e){if(null===e.clippingContext)return null;const{unionPlanes:t,intersectionPlanes:r}=e.clippingContext;let s=null;if(t.length>0||r.length>0){const t=e.renderer.samples;this.alphaToCoverage&&t>1?s=Ti(new th(th.ALPHA_TO_COVERAGE)):e.stack.add(Ti(new th))}return s}setupHardwareClipping(e){if(this.hardwareClipping=!1,null===e.clippingContext)return;const t=e.clippingContext.unionPlanes.length;t>0&&t<=8&&e.isAvailable("clipDistance")&&(e.stack.add(Ti(new th(th.HARDWARE))),this.hardwareClipping=!0)}setupDepth(e){const{renderer:t,camera:r}=e;let s=this.depthNode;if(null===s){const e=t.getMRT();e&&e.has("depth")?s=e.get("depth"):!0===t.logarithmicDepthBuffer&&(s=r.isPerspectiveCamera?Xc(al.z,Mu,Bu):jc(al.z,Mu,Bu))}null!==s&&Qc.assign(s).append()}setupPositionView(){return Zu.mul(sl).xyz}setupModelViewProjection(){return Uu.mul(al)}setupVertex(e){return e.addStack(),this.setupPosition(e),e.context.vertex=e.removeStack(),Xd}setupPosition(e){const{object:t,geometry:r}=e;if((r.morphAttributes.position||r.morphAttributes.normal||r.morphAttributes.color)&&xc(t).append(),!0===t.isSkinnedMesh&&cc(t).append(),this.displacementMap){const e=Ol("displacementMap","texture"),t=Ol("displacementScale","float"),r=Ol("displacementBias","float");sl.addAssign(pl.normalize().mul(e.x.mul(t).add(r)))}return t.isBatchedMesh&&uc(t).append(),t.isInstancedMesh&&t.instanceMatrix&&!0===t.instanceMatrix.isInstancedBufferAttribute&&oc(t).append(),null!==this.positionNode&&sl.assign(this.positionNode.context({isPositionNodeInput:!0})),sl}setupDiffuseColor({object:e,geometry:t}){let r=this.colorNode?$i(this.colorNode):hd;if(!0===this.vertexColors&&t.hasAttribute("color")&&(r=$i(r.xyz.mul(_u("color","vec3")),r.a)),e.instanceColor){r=ln("vec3","vInstanceColor").mul(r)}if(e.isBatchedMesh&&e._colorsTexture){r=ln("vec3","vBatchColor").mul(r)}dn.assign(r);const s=this.opacityNode?Bi(this.opacityNode):md;if(dn.a.assign(dn.a.mul(s)),null!==this.alphaTestNode||this.alphaTest>0){const e=null!==this.alphaTestNode?Bi(this.alphaTestNode):cd;dn.a.lessThanEqual(e).discard()}!0===this.alphaHash&&dn.a.lessThan(ih(sl)).discard(),!1===this.transparent&&this.blending===F&&!1===this.alphaToCoverage&&dn.a.assign(1)}setupVariants(){}setupOutgoingLight(){return!0===this.lights?Oi(0):dn.rgb}setupNormal(){return this.normalNode?Oi(this.normalNode):Nd}setupEnvironment(){let e=null;return this.envNode?e=this.envNode:this.envMap&&(e=this.envMap.isCubeTexture?Ol("envMap","cubeTexture"):Ol("envMap","texture")),e}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new Sc(jd)),t}setupLights(e){const t=[],r=this.setupEnvironment(e);r&&r.isLightingNode&&t.push(r);const s=this.setupLightMap(e);if(s&&s.isLightingNode&&t.push(s),null!==this.aoNode||e.material.aoMap){const e=null!==this.aoNode?this.aoNode:qd;t.push(new _c(e))}let i=this.lightsNode||e.lightsNode;return t.length>0&&(i=e.renderer.lighting.createNode([...i.getLights(),...t])),i}setupLightingModel(){}setupLighting(e){const{material:t}=e,{backdropNode:r,backdropAlphaNode:s,emissiveNode:i}=this,n=!0===this.lights||null!==this.lightsNode?this.setupLights(e):null;let o=this.setupOutgoingLight(e);if(n&&n.getScope().hasLights){const t=this.setupLightingModel(e);o=Nc(n,t,r,s)}else null!==r&&(o=Oi(null!==s?pa(o,r,s):r));return(i&&!0===i.isNode||t.emissive&&!0===t.emissive.isColor)&&(cn.assign(Oi(i||gd)),o=o.add(cn)),o}setupOutput(e,t){if(!0===this.fog){const r=e.fogNode;r&&(En.assign(t),t=$i(r))}return t}setDefaultValues(e){for(const t in e){const r=e[t];void 0===this[t]&&(this[t]=r,r&&r.clone&&(this[t]=r.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 r=U.prototype.toJSON.call(this,e),s=ps(this);r.inputNodes={};for(const{property:t,childNode:i}of s)r.inputNodes[t]=i.toJSON(e).uuid;function i(e){const t=[];for(const r in e){const s=e[r];delete s.metadata,t.push(s)}return t}if(t){const t=i(e.textures),s=i(e.images),n=i(e.nodes);t.length>0&&(r.textures=t),s.length>0&&(r.images=s),n.length>0&&(r.nodes=n)}return r}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.geometryNode=e.geometryNode,this.depthNode=e.depthNode,this.shadowPositionNode=e.shadowPositionNode,this.receivedShadowNode=e.receivedShadowNode,this.castShadowNode=e.castShadowNode,this.outputNode=e.outputNode,this.mrtNode=e.mrtNode,this.fragmentNode=e.fragmentNode,this.vertexNode=e.vertexNode,super.copy(e)}}const oh=new P;class ah extends nh{static get type(){return"LineBasicNodeMaterial"}constructor(e){super(),this.isLineBasicNodeMaterial=!0,this.setDefaultValues(oh),this.setValues(e)}}const uh=new I;class lh extends nh{static get type(){return"LineDashedNodeMaterial"}constructor(e){super(),this.isLineDashedNodeMaterial=!0,this.setDefaultValues(uh),this.dashOffset=0,this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.setValues(e)}setupVariants(){const e=this.offsetNode?Bi(this.offsetNode):$d,t=this.dashScaleNode?Bi(this.dashScaleNode):Od,r=this.dashSizeNode?Bi(this.dashSizeNode):Gd,s=this.gapSizeNode?Bi(this.gapSizeNode):kd;wn.assign(r),Mn.assign(s);const i=La(_u("lineDistance").mul(t));(e?i.add(e):i).mod(wn.add(Mn)).greaterThan(wn).discard()}}let dh=null;class ch extends Oc{static get type(){return"ViewportSharedTextureNode"}constructor(e=Ec,t=null){null===dh&&(dh=new w),super(e,t,dh)}updateReference(){return this}}const hh=Ni(ch),ph=new I;class gh extends nh{static get type(){return"Line2NodeMaterial"}constructor(e={}){super(),this.isLine2NodeMaterial=!0,this.setDefaultValues(ph),this.useColor=e.vertexColors,this.dashOffset=0,this.lineWidth=1,this.lineColorNode=null,this.offsetNode=null,this.dashScaleNode=null,this.dashSizeNode=null,this.gapSizeNode=null,this.blending=D,this._useDash=e.dashed,this._useAlphaToCoverage=!0,this._useWorldUnits=!1,this.setValues(e)}setup(e){const{renderer:t}=e,r=this._useAlphaToCoverage,s=this.useColor,i=this._useDash,n=this._useWorldUnits,o=Ai((({start:e,end:t})=>{const r=Uu.element(2).element(2),s=Uu.element(3).element(2).mul(-.5).div(r).sub(e.z).div(t.z.sub(e.z));return $i(pa(e.xyz,t.xyz,s),t.w)})).setLayout({name:"trimSegment",type:"vec4",inputs:[{name:"start",type:"vec4"},{name:"end",type:"vec4"}]});this.vertexNode=Ai((()=>{const e=_u("instanceStart"),t=_u("instanceEnd"),r=$i(Zu.mul($i(e,1))).toVar("start"),s=$i(Zu.mul($i(t,1))).toVar("end");if(i){const e=this.dashScaleNode?Bi(this.dashScaleNode):Od,t=this.offsetNode?Bi(this.offsetNode):$d,r=_u("instanceDistanceStart"),s=_u("instanceDistanceEnd");let i=rl.y.lessThan(.5).select(e.mul(r),e.mul(s));i=i.add(t),ln("float","lineDistance").assign(i)}n&&(ln("vec3","worldStart").assign(r.xyz),ln("vec3","worldEnd").assign(s.xyz));const a=Bc.z.div(Bc.w),u=Uu.element(2).element(3).equal(-1);Ei(u,(()=>{Ei(r.z.lessThan(0).and(s.z.greaterThan(0)),(()=>{s.assign(o({start:r,end:s}))})).ElseIf(s.z.lessThan(0).and(r.z.greaterThanEqual(0)),(()=>{r.assign(o({start:s,end:r}))}))}));const l=Uu.mul(r),d=Uu.mul(s),c=l.xyz.div(l.w),h=d.xyz.div(d.w),p=h.xy.sub(c.xy).toVar();p.x.assign(p.x.mul(a)),p.assign(p.normalize());const g=$i().toVar();if(n){const e=s.xyz.sub(r.xyz).normalize(),t=pa(r.xyz,s.xyz,.5).normalize(),n=e.cross(t).normalize(),o=e.cross(n),a=ln("vec4","worldPos");a.assign(rl.y.lessThan(.5).select(r,s));const u=zd.mul(.5);a.addAssign($i(rl.x.lessThan(0).select(n.mul(u),n.mul(u).negate()),0)),i||(a.addAssign($i(rl.y.lessThan(.5).select(e.mul(u).negate(),e.mul(u)),0)),a.addAssign($i(o.mul(u),0)),Ei(rl.y.greaterThan(1).or(rl.y.lessThan(0)),(()=>{a.subAssign($i(o.mul(2).mul(u),0))}))),g.assign(Uu.mul(a));const l=Oi().toVar();l.assign(rl.y.lessThan(.5).select(c,h)),g.z.assign(l.z.mul(g.w))}else{const e=Ii(p.y,p.x.negate()).toVar("offset");p.x.assign(p.x.div(a)),e.x.assign(e.x.div(a)),e.assign(rl.x.lessThan(0).select(e.negate(),e)),Ei(rl.y.lessThan(0),(()=>{e.assign(e.sub(p))})).ElseIf(rl.y.greaterThan(1),(()=>{e.assign(e.add(p))})),e.assign(e.mul(zd)),e.assign(e.div(Bc.w)),g.assign(rl.y.lessThan(.5).select(l,d)),e.assign(e.mul(g.w)),g.assign(g.add($i(e,0,0)))}return g}))();const a=Ai((({p1:e,p2:t,p3:r,p4:s})=>{const i=e.sub(r),n=s.sub(r),o=t.sub(e),a=i.dot(n),u=n.dot(o),l=i.dot(o),d=n.dot(n),c=o.dot(o).mul(d).sub(u.mul(u)),h=a.mul(u).sub(l.mul(d)).div(c).clamp(),p=a.add(u.mul(h)).div(d).clamp();return Ii(h,p)}));if(this.colorNode=Ai((()=>{const e=vu();if(i){const t=this.dashSizeNode?Bi(this.dashSizeNode):Gd,r=this.gapSizeNode?Bi(this.gapSizeNode):kd;wn.assign(t),Mn.assign(r);const s=ln("float","lineDistance");e.y.lessThan(-1).or(e.y.greaterThan(1)).discard(),s.mod(wn.add(Mn)).greaterThan(wn).discard()}const o=Bi(1).toVar("alpha");if(n){const e=ln("vec3","worldStart"),s=ln("vec3","worldEnd"),n=ln("vec4","worldPos").xyz.normalize().mul(1e5),u=s.sub(e),l=a({p1:e,p2:s,p3:Oi(0,0,0),p4:n}),d=e.add(u.mul(l.x)),c=n.mul(l.y),h=d.sub(c).length().div(zd);if(!i)if(r&&t.samples>1){const e=h.fwidth();o.assign(ya(e.negate().add(.5),e.add(.5),h).oneMinus())}else h.greaterThan(.5).discard()}else if(r&&t.samples>1){const t=e.x,r=e.y.greaterThan(0).select(e.y.sub(1),e.y.add(1)),s=t.mul(t).add(r.mul(r)),i=Bi(s.fwidth()).toVar("dlen");Ei(e.y.abs().greaterThan(1),(()=>{o.assign(ya(i.oneMinus(),i.add(1),s).oneMinus())}))}else Ei(e.y.abs().greaterThan(1),(()=>{const t=e.x,r=e.y.greaterThan(0).select(e.y.sub(1),e.y.add(1));t.mul(t).add(r.mul(r)).greaterThan(1).discard()}));let u;if(this.lineColorNode)u=this.lineColorNode;else if(s){const e=_u("instanceColorStart"),t=_u("instanceColorEnd");u=rl.y.lessThan(.5).select(e,t).mul(hd)}else u=hd;return $i(u,o)}))(),this.transparent){const e=this.opacityNode?Bi(this.opacityNode):md;this.outputNode=$i(this.colorNode.rgb.mul(e).add(hh().rgb.mul(e.oneMinus())),this.colorNode.a)}super.setup(e)}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 mh=e=>Ti(e).mul(.5).add(.5),fh=new L;class yh extends nh{static get type(){return"MeshNormalNodeMaterial"}constructor(e){super(),this.isMeshNormalNodeMaterial=!0,this.setDefaultValues(fh),this.setValues(e)}setupDiffuseColor(){const e=this.opacityNode?Bi(this.opacityNode):md;dn.assign($i(mh(yl),e))}}class bh extends Ls{static get type(){return"EquirectUVNode"}constructor(e=ol){super("vec2"),this.dirNode=e}setup(){const e=this.dirNode,t=e.z.atan(e.x).mul(1/(2*Math.PI)).add(.5),r=e.y.clamp(-1,1).asin().mul(1/Math.PI).add(.5);return Ii(t,r)}}const xh=Ni(bh);class Th extends V{constructor(e=1,t={}){super(e,t),this.isCubeRenderTarget=!0}fromEquirectangularTexture(e,t){const r=t.minFilter,s=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 i=new O(5,5,5),n=xh(ol),o=new nh;o.colorNode=Eu(t,n,0),o.side=T,o.blending=D;const a=new G(i,o),u=new k;u.add(a),t.minFilter===M&&(t.minFilter=z);const l=new $(1,10,this),d=e.getMRT();return e.setMRT(null),l.update(e,u),e.setMRT(d),t.minFilter=r,t.currentGenerateMipmaps=s,a.geometry.dispose(),a.material.dispose(),this}}const _h=new WeakMap;class vh extends Ls{static get type(){return"CubeMapNode"}constructor(e){super("vec3"),this.envNode=e,this._cubeTexture=null,this._cubeTextureNode=El();const t=new H;t.isRenderTargetTexture=!0,this._defaultTexture=t,this.updateBeforeType=Rs.RENDER}updateBefore(e){const{renderer:t,material:r}=e,s=this.envNode;if(s.isTextureNode||s.isMaterialReferenceNode){const e=s.isTextureNode?s.value:r[s.property];if(e&&e.isTexture){const r=e.mapping;if(r===W||r===j){if(_h.has(e)){const t=_h.get(e);Sh(t,e.mapping),this._cubeTexture=t}else{const r=e.image;if(function(e){return null!=e&&e.height>0}(r)){const s=new Th(r.height);s.fromEquirectangularTexture(t,e),Sh(s.texture,e.mapping),this._cubeTexture=s.texture,_h.set(e,s.texture),e.addEventListener("dispose",Nh)}else this._cubeTexture=this._defaultTexture}this._cubeTextureNode.value=this._cubeTexture}else this._cubeTextureNode=this.envNode}}}setup(e){return this.updateBefore(e),this._cubeTextureNode}}function Nh(e){const t=e.target;t.removeEventListener("dispose",Nh);const r=_h.get(t);void 0!==r&&(_h.delete(t),r.dispose())}function Sh(e,t){t===W?e.mapping=_:t===j&&(e.mapping=v)}const Ah=Ni(vh);class Rh extends Tc{static get type(){return"BasicEnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){e.context.environment=Ah(this.envNode)}}class Ch extends Tc{static get type(){return"BasicLightMapNode"}constructor(e=null){super(),this.lightMapNode=e}setup(e){const t=Bi(1/Math.PI);e.context.irradianceLightMap=this.lightMapNode.mul(t)}}class Eh{start(){}finish(){}direct(){}directRectArea(){}indirect(){}ambientOcclusion(){}}class wh extends Eh{constructor(){super()}indirect(e,t,r){const s=e.ambientOcclusion,i=e.reflectedLight,n=r.context.irradianceLightMap;i.indirectDiffuse.assign($i(0)),n?i.indirectDiffuse.addAssign(n):i.indirectDiffuse.addAssign($i(1,1,1,0)),i.indirectDiffuse.mulAssign(s),i.indirectDiffuse.mulAssign(dn.rgb)}finish(e,t,r){const s=r.material,i=e.outgoingLight,n=r.context.environment;if(n)switch(s.combine){case X:i.rgb.assign(pa(i.rgb,i.rgb.mul(n.rgb),xd.mul(Td)));break;case K:i.rgb.assign(pa(i.rgb,n.rgb,xd.mul(Td)));break;case q:i.rgb.addAssign(n.rgb.mul(xd.mul(Td)));break;default:console.warn("THREE.BasicLightingModel: Unsupported .combine value:",s.combine)}}}const Mh=new Y;class Bh extends nh{static get type(){return"MeshBasicNodeMaterial"}constructor(e){super(),this.isMeshBasicNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Mh),this.setValues(e)}setupNormal(){return ml}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new Rh(t):null}setupLightMap(e){let t=null;return e.material.lightMap&&(t=new Ch(jd)),t}setupOutgoingLight(){return dn.rgb}setupLightingModel(){return new wh}}const Uh=Ai((({f0:e,f90:t,dotVH:r})=>{const s=r.mul(-5.55473).sub(6.98316).mul(r).exp2();return e.mul(s.oneMinus()).add(t.mul(s))})),Fh=Ai((e=>e.diffuseColor.mul(1/Math.PI))),Ph=Ai((({dotNH:e})=>Cn.mul(Bi(.5)).add(1).mul(Bi(1/Math.PI)).mul(e.pow(Cn)))),Ih=Ai((({lightDirection:e})=>{const t=e.add(ul).normalize(),r=yl.dot(t).clamp(),s=ul.dot(t).clamp(),i=Uh({f0:An,f90:1,dotVH:s}),n=Bi(.25),o=Ph({dotNH:r});return i.mul(n).mul(o)}));class Dh extends wh{constructor(e=!0){super(),this.specular=e}direct({lightDirection:e,lightColor:t,reflectedLight:r}){const s=yl.dot(e).clamp().mul(t);r.directDiffuse.addAssign(s.mul(Fh({diffuseColor:dn.rgb}))),!0===this.specular&&r.directSpecular.addAssign(s.mul(Ih({lightDirection:e})).mul(xd))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:r}){r.indirectDiffuse.addAssign(t.mul(Fh({diffuseColor:dn}))),r.indirectDiffuse.mulAssign(e)}}const Lh=new Q;class Vh extends nh{static get type(){return"MeshLambertNodeMaterial"}constructor(e){super(),this.isMeshLambertNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Lh),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new Rh(t):null}setupLightingModel(){return new Dh(!1)}}const Oh=new Z;class Gh extends nh{static get type(){return"MeshPhongNodeMaterial"}constructor(e){super(),this.isMeshPhongNodeMaterial=!0,this.lights=!0,this.shininessNode=null,this.specularNode=null,this.setDefaultValues(Oh),this.setValues(e)}setupEnvironment(e){const t=super.setupEnvironment(e);return t?new Rh(t):null}setupLightingModel(){return new Dh}setupVariants(){const e=(this.shininessNode?Bi(this.shininessNode):pd).max(1e-4);Cn.assign(e);const t=this.specularNode||fd;An.assign(t)}copy(e){return this.shininessNode=e.shininessNode,this.specularNode=e.specularNode,super.copy(e)}}const kh=Ai((e=>{if(!1===e.geometry.hasAttribute("normal"))return Bi(0);const t=ml.dFdx().abs().max(ml.dFdy().abs());return t.x.max(t.y).max(t.z)})),zh=Ai((e=>{const{roughness:t}=e,r=kh();let s=t.max(.0525);return s=s.add(r),s=s.min(1),s})),$h=Ai((({alpha:e,dotNL:t,dotNV:r})=>{const s=e.pow2(),i=t.mul(s.add(s.oneMinus().mul(r.pow2())).sqrt()),n=r.mul(s.add(s.oneMinus().mul(t.pow2())).sqrt());return jn(.5,i.add(n).max(po))})).setLayout({name:"V_GGX_SmithCorrelated",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNL",type:"float"},{name:"dotNV",type:"float"}]}),Hh=Ai((({alphaT:e,alphaB:t,dotTV:r,dotBV:s,dotTL:i,dotBL:n,dotNV:o,dotNL:a})=>{const u=a.mul(Oi(e.mul(r),t.mul(s),o).length()),l=o.mul(Oi(e.mul(i),t.mul(n),a).length());return jn(.5,u.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"}]}),Wh=Ai((({alpha:e,dotNH:t})=>{const r=e.pow2(),s=t.pow2().mul(r.oneMinus()).oneMinus();return r.div(s.pow2()).mul(1/Math.PI)})).setLayout({name:"D_GGX",type:"float",inputs:[{name:"alpha",type:"float"},{name:"dotNH",type:"float"}]}),jh=Bi(1/Math.PI),qh=Ai((({alphaT:e,alphaB:t,dotNH:r,dotTH:s,dotBH:i})=>{const n=e.mul(t),o=Oi(t.mul(s),e.mul(i),n.mul(r)),a=o.dot(o),u=n.div(a);return jh.mul(n.mul(u.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"}]}),Kh=Ai((e=>{const{lightDirection:t,f0:r,f90:s,roughness:i,f:n,USE_IRIDESCENCE:o,USE_ANISOTROPY:a}=e,u=e.normalView||yl,l=i.pow2(),d=t.add(ul).normalize(),c=u.dot(t).clamp(),h=u.dot(ul).clamp(),p=u.dot(d).clamp(),g=ul.dot(d).clamp();let m,f,y=Uh({f0:r,f90:s,dotVH:g});if(yi(o)&&(y=bn.mix(y,n)),yi(a)){const e=Nn.dot(t),r=Nn.dot(ul),s=Nn.dot(d),i=Sn.dot(t),n=Sn.dot(ul),o=Sn.dot(d);m=Hh({alphaT:_n,alphaB:l,dotTV:r,dotBV:n,dotTL:e,dotBL:i,dotNV:h,dotNL:c}),f=qh({alphaT:_n,alphaB:l,dotNH:p,dotTH:s,dotBH:o})}else m=$h({alpha:l,dotNL:c,dotNV:h}),f=Wh({alpha:l,dotNH:p});return y.mul(m).mul(f)})),Xh=Ai((({roughness:e,dotNV:t})=>{const r=$i(-1,-.0275,-.572,.022),s=$i(1,.0425,1.04,-.04),i=e.mul(r).add(s),n=i.x.mul(i.x).min(t.mul(-9.28).exp2()).mul(i.x).add(i.y);return Ii(-1.04,1.04).mul(n).add(i.zw)})).setLayout({name:"DFGApprox",type:"vec2",inputs:[{name:"roughness",type:"float"},{name:"dotNV",type:"vec3"}]}),Yh=Ai((e=>{const{dotNV:t,specularColor:r,specularF90:s,roughness:i}=e,n=Xh({dotNV:t,roughness:i});return r.mul(n.x).add(s.mul(n.y))})),Qh=Ai((({f:e,f90:t,dotVH:r})=>{const s=r.oneMinus().saturate(),i=s.mul(s),n=s.mul(i,i).clamp(0,.9999);return e.sub(Oi(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"}]}),Zh=Ai((({roughness:e,dotNH:t})=>{const r=e.pow2(),s=Bi(1).div(r),i=t.pow2().oneMinus().max(.0078125);return Bi(2).add(s).mul(i.pow(s.mul(.5))).div(2*Math.PI)})).setLayout({name:"D_Charlie",type:"float",inputs:[{name:"roughness",type:"float"},{name:"dotNH",type:"float"}]}),Jh=Ai((({dotNV:e,dotNL:t})=>Bi(1).div(Bi(4).mul(t.add(e).sub(t.mul(e)))))).setLayout({name:"V_Neubelt",type:"float",inputs:[{name:"dotNV",type:"float"},{name:"dotNL",type:"float"}]}),ep=Ai((({lightDirection:e})=>{const t=e.add(ul).normalize(),r=yl.dot(e).clamp(),s=yl.dot(ul).clamp(),i=yl.dot(t).clamp(),n=Zh({roughness:yn,dotNH:i}),o=Jh({dotNV:s,dotNL:r});return fn.mul(n).mul(o)})),tp=Ai((({N:e,V:t,roughness:r})=>{const s=e.dot(t).saturate(),i=Ii(r,s.oneMinus().sqrt());return i.assign(i.mul(.984375).add(.0078125)),i})).setLayout({name:"LTC_Uv",type:"vec2",inputs:[{name:"N",type:"vec3"},{name:"V",type:"vec3"},{name:"roughness",type:"float"}]}),rp=Ai((({f:e})=>{const t=e.length();return Zo(t.mul(t).add(e.z).div(t.add(1)),0)})).setLayout({name:"LTC_ClippedSphereFormFactor",type:"float",inputs:[{name:"f",type:"vec3"}]}),sp=Ai((({v1:e,v2:t})=>{const r=e.dot(t),s=r.abs().toVar(),i=s.mul(.0145206).add(.4965155).mul(s).add(.8543985).toVar(),n=s.add(4.1616724).mul(s).add(3.417594).toVar(),o=i.div(n),a=r.greaterThan(0).select(o,Zo(r.mul(r).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"}]}),ip=Ai((({N:e,V:t,P:r,mInv:s,p0:i,p1:n,p2:o,p3:a})=>{const u=n.sub(i).toVar(),l=a.sub(i).toVar(),d=u.cross(l),c=Oi().toVar();return Ei(d.dot(r.sub(i)).greaterThanEqual(0),(()=>{const u=t.sub(e.mul(t.dot(e))).normalize(),l=e.cross(u).negate(),d=s.mul(Ki(u,l,e).transpose()).toVar(),h=d.mul(i.sub(r)).normalize().toVar(),p=d.mul(n.sub(r)).normalize().toVar(),g=d.mul(o.sub(r)).normalize().toVar(),m=d.mul(a.sub(r)).normalize().toVar(),f=Oi(0).toVar();f.addAssign(sp({v1:h,v2:p})),f.addAssign(sp({v1:p,v2:g})),f.addAssign(sp({v1:g,v2:m})),f.addAssign(sp({v1:m,v2:h})),c.assign(Oi(rp({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"}]}),np=1/6,op=e=>Wn(np,Wn(e,Wn(e,e.negate().add(3)).sub(3)).add(1)),ap=e=>Wn(np,Wn(e,Wn(e,Wn(3,e).sub(6))).add(4)),up=e=>Wn(np,Wn(e,Wn(e,Wn(-3,e).add(3)).add(3)).add(1)),lp=e=>Wn(np,oa(e,3)),dp=e=>op(e).add(ap(e)),cp=e=>up(e).add(lp(e)),hp=e=>$n(-1,ap(e).div(op(e).add(ap(e)))),pp=e=>$n(1,lp(e).div(up(e).add(lp(e)))),gp=(e,t,r)=>{const s=e.uvNode,i=Wn(s,t.zw).add(.5),n=Co(i),o=Mo(i),a=dp(o.x),u=cp(o.x),l=hp(o.x),d=pp(o.x),c=hp(o.y),h=pp(o.y),p=Ii(n.x.add(l),n.y.add(c)).sub(.5).mul(t.xy),g=Ii(n.x.add(d),n.y.add(c)).sub(.5).mul(t.xy),m=Ii(n.x.add(l),n.y.add(h)).sub(.5).mul(t.xy),f=Ii(n.x.add(d),n.y.add(h)).sub(.5).mul(t.xy),y=dp(o.y).mul($n(a.mul(e.sample(p).level(r)),u.mul(e.sample(g).level(r)))),b=cp(o.y).mul($n(a.mul(e.sample(m).level(r)),u.mul(e.sample(f).level(r))));return y.add(b)},mp=Ai((([e,t=Bi(3)])=>{const r=Ii(e.size(Ui(t))),s=Ii(e.size(Ui(t.add(1)))),i=jn(1,r),n=jn(1,s),o=gp(e,$i(i,r),Co(t)),a=gp(e,$i(n,s),Eo(t));return Mo(t).mix(o,a)})),fp=Ai((([e,t,r,s,i])=>{const n=Oi(fa(t.negate(),wo(e),jn(1,s))),o=Oi(Oo(i[0].xyz),Oo(i[1].xyz),Oo(i[2].xyz));return wo(n).mul(r.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"}]}),yp=Ai((([e,t])=>e.mul(ga(t.mul(2).sub(2),0,1)))).setLayout({name:"applyIorToRoughness",type:"float",inputs:[{name:"roughness",type:"float"},{name:"ior",type:"float"}]}),bp=kc(),xp=kc(),Tp=Ai((([e,t,r],{material:s})=>{const i=(s.side===T?bp:xp).sample(e),n=So(wc.x).mul(yp(t,r));return mp(i,n)})),_p=Ai((([e,t,r])=>(Ei(r.notEqual(0),(()=>{const s=No(t).negate().div(r);return _o(s.negate().mul(e))})),Oi(1)))).setLayout({name:"volumeAttenuation",type:"vec3",inputs:[{name:"transmissionDistance",type:"float"},{name:"attenuationColor",type:"vec3"},{name:"attenuationDistance",type:"float"}]}),vp=Ai((([e,t,r,s,i,n,o,a,u,l,d,c,h,p,g])=>{let m,f;if(g){m=$i().toVar(),f=Oi().toVar();const i=d.sub(1).mul(g.mul(.025)),n=Oi(d.sub(i),d,d.add(i));pc({start:0,end:3},(({i:i})=>{const d=n.element(i),g=fp(e,t,c,d,a),y=o.add(g),b=l.mul(u.mul($i(y,1))),x=Ii(b.xy.div(b.w)).toVar();x.addAssign(1),x.divAssign(2),x.assign(Ii(x.x,x.y.oneMinus()));const T=Tp(x,r,d);m.element(i).assign(T.element(i)),m.a.addAssign(T.a),f.element(i).assign(s.element(i).mul(_p(Oo(g),h,p).element(i)))})),m.a.divAssign(3)}else{const i=fp(e,t,c,d,a),n=o.add(i),g=l.mul(u.mul($i(n,1))),y=Ii(g.xy.div(g.w)).toVar();y.addAssign(1),y.divAssign(2),y.assign(Ii(y.x,y.y.oneMinus())),m=Tp(y,r,d),f=s.mul(_p(Oo(i),h,p))}const y=f.rgb.mul(m.rgb),b=e.dot(t).clamp(),x=Oi(Yh({dotNV:b,specularColor:i,specularF90:n,roughness:r})),T=f.r.add(f.g,f.b).div(3);return $i(x.oneMinus().mul(y),m.a.oneMinus().mul(T).oneMinus())})),Np=Ki(3.2404542,-.969266,.0556434,-1.5371385,1.8760108,-.2040259,-.4985314,.041556,1.0572252),Sp=(e,t)=>e.sub(t).div(e.add(t)).pow2(),Ap=Ai((({outsideIOR:e,eta2:t,cosTheta1:r,thinFilmThickness:s,baseF0:i})=>{const n=pa(e,t,ya(0,.03,s)),o=e.div(n).pow2().mul(r.pow2().oneMinus()).oneMinus();Ei(o.lessThan(0),(()=>Oi(1)));const a=o.sqrt(),u=Sp(n,e),l=Uh({f0:u,f90:1,dotVH:r}),d=l.oneMinus(),c=n.lessThan(e).select(Math.PI,0),h=Bi(Math.PI).sub(c),p=(e=>{const t=e.sqrt();return Oi(1).add(t).div(Oi(1).sub(t))})(i.clamp(0,.9999)),g=Sp(p,n.toVec3()),m=Uh({f0:g,f90:1,dotVH:a}),f=Oi(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(s,a,2),b=Oi(h).add(f),x=l.mul(m).clamp(1e-5,.9999),T=x.sqrt(),_=d.pow2().mul(m).div(Oi(1).sub(x)),v=l.add(_).toVar(),N=_.sub(d).toVar();return pc({start:1,end:2,condition:"<=",name:"m"},(({m:e})=>{N.mulAssign(T);const t=((e,t)=>{const r=e.mul(2*Math.PI*1e-9),s=Oi(54856e-17,44201e-17,52481e-17),i=Oi(1681e3,1795300,2208400),n=Oi(43278e5,93046e5,66121e5),o=Bi(9747e-17*Math.sqrt(2*Math.PI*45282e5)).mul(r.mul(2239900).add(t.x).cos()).mul(r.pow2().mul(-45282e5).exp());let a=s.mul(n.mul(2*Math.PI).sqrt()).mul(i.mul(r).add(t).cos()).mul(r.pow2().negate().mul(n).exp());return a=Oi(a.x.add(o),a.y,a.z).div(1.0685e-7),Np.mul(a)})(Bi(e).mul(y),Bi(e).mul(b)).mul(2);v.addAssign(N.mul(t))})),v.max(Oi(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"}]}),Rp=Ai((({normal:e,viewDir:t,roughness:r})=>{const s=e.dot(t).saturate(),i=r.pow2(),n=Ra(r.lessThan(.25),Bi(-339.2).mul(i).add(Bi(161.4).mul(r)).sub(25.9),Bi(-8.48).mul(i).add(Bi(14.3).mul(r)).sub(9.95)),o=Ra(r.lessThan(.25),Bi(44).mul(i).sub(Bi(23.7).mul(r)).add(3.26),Bi(1.97).mul(i).sub(Bi(3.27).mul(r)).add(.72));return Ra(r.lessThan(.25),0,Bi(.1).mul(r).sub(.025)).add(n.mul(s).add(o).exp()).mul(1/Math.PI).saturate()})),Cp=Oi(.04),Ep=Bi(1);class wp extends Eh{constructor(e=!1,t=!1,r=!1,s=!1,i=!1,n=!1){super(),this.clearcoat=e,this.sheen=t,this.iridescence=r,this.anisotropy=s,this.transmission=i,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=Oi().toVar("clearcoatRadiance"),this.clearcoatSpecularDirect=Oi().toVar("clearcoatSpecularDirect"),this.clearcoatSpecularIndirect=Oi().toVar("clearcoatSpecularIndirect")),!0===this.sheen&&(this.sheenSpecularDirect=Oi().toVar("sheenSpecularDirect"),this.sheenSpecularIndirect=Oi().toVar("sheenSpecularIndirect")),!0===this.iridescence){const e=yl.dot(ul).clamp();this.iridescenceFresnel=Ap({outsideIOR:Bi(1),eta2:xn,cosTheta1:e,thinFilmThickness:Tn,baseF0:An}),this.iridescenceF0=Qh({f:this.iridescenceFresnel,f90:1,dotVH:e})}if(!0===this.transmission){const t=nl,r=Lu.sub(nl).normalize(),s=bl;e.backdrop=vp(s,r,hn,dn,An,Rn,t,ju,Pu,Uu,Un,Pn,Dn,In,this.dispersion?Ln:null),e.backdropAlpha=Fn,dn.a.mulAssign(pa(1,e.backdrop.a,Fn))}}computeMultiscattering(e,t,r){const s=yl.dot(ul).clamp(),i=Xh({roughness:hn,dotNV:s}),n=(this.iridescenceF0?bn.mix(An,this.iridescenceF0):An).mul(i.x).add(r.mul(i.y)),o=i.x.add(i.y).oneMinus(),a=An.add(An.oneMinus().mul(.047619)),u=n.mul(a).div(o.mul(a).oneMinus());e.addAssign(n),t.addAssign(u.mul(o))}direct({lightDirection:e,lightColor:t,reflectedLight:r}){const s=yl.dot(e).clamp().mul(t);if(!0===this.sheen&&this.sheenSpecularDirect.addAssign(s.mul(ep({lightDirection:e}))),!0===this.clearcoat){const r=xl.dot(e).clamp().mul(t);this.clearcoatSpecularDirect.addAssign(r.mul(Kh({lightDirection:e,f0:Cp,f90:Ep,roughness:mn,normalView:xl})))}r.directDiffuse.addAssign(s.mul(Fh({diffuseColor:dn.rgb}))),r.directSpecular.addAssign(s.mul(Kh({lightDirection:e,f0:An,f90:1,roughness:hn,iridescence:this.iridescence,f:this.iridescenceFresnel,USE_IRIDESCENCE:this.iridescence,USE_ANISOTROPY:this.anisotropy})))}directRectArea({lightColor:e,lightPosition:t,halfWidth:r,halfHeight:s,reflectedLight:i,ltc_1:n,ltc_2:o}){const a=t.add(r).sub(s),u=t.sub(r).sub(s),l=t.sub(r).add(s),d=t.add(r).add(s),c=yl,h=ul,p=al.toVar(),g=tp({N:c,V:h,roughness:hn}),m=n.sample(g).toVar(),f=o.sample(g).toVar(),y=Ki(Oi(m.x,0,m.y),Oi(0,1,0),Oi(m.z,0,m.w)).toVar(),b=An.mul(f.x).add(An.oneMinus().mul(f.y)).toVar();i.directSpecular.addAssign(e.mul(b).mul(ip({N:c,V:h,P:p,mInv:y,p0:a,p1:u,p2:l,p3:d}))),i.directDiffuse.addAssign(e.mul(dn).mul(ip({N:c,V:h,P:p,mInv:Ki(1,0,0,0,1,0,0,0,1),p0:a,p1:u,p2:l,p3:d})))}indirect(e,t,r){this.indirectDiffuse(e,t,r),this.indirectSpecular(e,t,r),this.ambientOcclusion(e,t,r)}indirectDiffuse({irradiance:e,reflectedLight:t}){t.indirectDiffuse.addAssign(e.mul(Fh({diffuseColor:dn})))}indirectSpecular({radiance:e,iblIrradiance:t,reflectedLight:r}){if(!0===this.sheen&&this.sheenSpecularIndirect.addAssign(t.mul(fn,Rp({normal:yl,viewDir:ul,roughness:yn}))),!0===this.clearcoat){const e=xl.dot(ul).clamp(),t=Yh({dotNV:e,specularColor:Cp,specularF90:Ep,roughness:mn});this.clearcoatSpecularIndirect.addAssign(this.clearcoatRadiance.mul(t))}const s=Oi().toVar("singleScattering"),i=Oi().toVar("multiScattering"),n=t.mul(1/Math.PI);this.computeMultiscattering(s,i,Rn);const o=s.add(i),a=dn.mul(o.r.max(o.g).max(o.b).oneMinus());r.indirectSpecular.addAssign(e.mul(s)),r.indirectSpecular.addAssign(i.mul(n)),r.indirectDiffuse.addAssign(a.mul(n))}ambientOcclusion({ambientOcclusion:e,reflectedLight:t}){const r=yl.dot(ul).clamp().add(e),s=hn.mul(-16).oneMinus().negate().exp2(),i=e.sub(r.pow(s).oneMinus()).clamp();!0===this.clearcoat&&this.clearcoatSpecularIndirect.mulAssign(e),!0===this.sheen&&this.sheenSpecularIndirect.mulAssign(e),t.indirectDiffuse.mulAssign(e),t.indirectSpecular.mulAssign(i)}finish(e){const{outgoingLight:t}=e;if(!0===this.clearcoat){const e=xl.dot(ul).clamp(),r=Uh({dotVH:e,f0:Cp,f90:Ep}),s=t.mul(gn.mul(r).oneMinus()).add(this.clearcoatSpecularDirect.add(this.clearcoatSpecularIndirect).mul(gn));t.assign(s)}if(!0===this.sheen){const e=fn.r.max(fn.g).max(fn.b).mul(.157).oneMinus(),r=t.mul(e).add(this.sheenSpecularDirect,this.sheenSpecularIndirect);t.assign(r)}}}const Mp=Bi(1),Bp=Bi(-2),Up=Bi(.8),Fp=Bi(-1),Pp=Bi(.4),Ip=Bi(2),Dp=Bi(.305),Lp=Bi(3),Vp=Bi(.21),Op=Bi(4),Gp=Bi(4),kp=Bi(16),zp=Ai((([e])=>{const t=Oi(Lo(e)).toVar(),r=Bi(-1).toVar();return Ei(t.x.greaterThan(t.z),(()=>{Ei(t.x.greaterThan(t.y),(()=>{r.assign(Ra(e.x.greaterThan(0),0,3))})).Else((()=>{r.assign(Ra(e.y.greaterThan(0),1,4))}))})).Else((()=>{Ei(t.z.greaterThan(t.y),(()=>{r.assign(Ra(e.z.greaterThan(0),2,5))})).Else((()=>{r.assign(Ra(e.y.greaterThan(0),1,4))}))})),r})).setLayout({name:"getFace",type:"float",inputs:[{name:"direction",type:"vec3"}]}),$p=Ai((([e,t])=>{const r=Ii().toVar();return Ei(t.equal(0),(()=>{r.assign(Ii(e.z,e.y).div(Lo(e.x)))})).ElseIf(t.equal(1),(()=>{r.assign(Ii(e.x.negate(),e.z.negate()).div(Lo(e.y)))})).ElseIf(t.equal(2),(()=>{r.assign(Ii(e.x.negate(),e.y).div(Lo(e.z)))})).ElseIf(t.equal(3),(()=>{r.assign(Ii(e.z.negate(),e.y).div(Lo(e.x)))})).ElseIf(t.equal(4),(()=>{r.assign(Ii(e.x.negate(),e.z).div(Lo(e.y)))})).Else((()=>{r.assign(Ii(e.x,e.y).div(Lo(e.z)))})),Wn(.5,r.add(1))})).setLayout({name:"getUV",type:"vec2",inputs:[{name:"direction",type:"vec3"},{name:"face",type:"float"}]}),Hp=Ai((([e])=>{const t=Bi(0).toVar();return Ei(e.greaterThanEqual(Up),(()=>{t.assign(Mp.sub(e).mul(Fp.sub(Bp)).div(Mp.sub(Up)).add(Bp))})).ElseIf(e.greaterThanEqual(Pp),(()=>{t.assign(Up.sub(e).mul(Ip.sub(Fp)).div(Up.sub(Pp)).add(Fp))})).ElseIf(e.greaterThanEqual(Dp),(()=>{t.assign(Pp.sub(e).mul(Lp.sub(Ip)).div(Pp.sub(Dp)).add(Ip))})).ElseIf(e.greaterThanEqual(Vp),(()=>{t.assign(Dp.sub(e).mul(Op.sub(Lp)).div(Dp.sub(Vp)).add(Lp))})).Else((()=>{t.assign(Bi(-2).mul(So(Wn(1.16,e))))})),t})).setLayout({name:"roughnessToMip",type:"float",inputs:[{name:"roughness",type:"float"}]}),Wp=Ai((([e,t])=>{const r=e.toVar();r.assign(Wn(2,r).sub(1));const s=Oi(r,1).toVar();return Ei(t.equal(0),(()=>{s.assign(s.zyx)})).ElseIf(t.equal(1),(()=>{s.assign(s.xzy),s.xz.mulAssign(-1)})).ElseIf(t.equal(2),(()=>{s.x.mulAssign(-1)})).ElseIf(t.equal(3),(()=>{s.assign(s.zyx),s.xz.mulAssign(-1)})).ElseIf(t.equal(4),(()=>{s.assign(s.xzy),s.xy.mulAssign(-1)})).ElseIf(t.equal(5),(()=>{s.z.mulAssign(-1)})),s})).setLayout({name:"getDirection",type:"vec3",inputs:[{name:"uv",type:"vec2"},{name:"face",type:"float"}]}),jp=Ai((([e,t,r,s,i,n])=>{const o=Bi(r),a=Oi(t),u=ga(Hp(o),Bp,n),l=Mo(u),d=Co(u),c=Oi(qp(e,a,d,s,i,n)).toVar();return Ei(l.notEqual(0),(()=>{const t=Oi(qp(e,a,d.add(1),s,i,n)).toVar();c.assign(pa(c,t,l))})),c})),qp=Ai((([e,t,r,s,i,n])=>{const o=Bi(r).toVar(),a=Oi(t),u=Bi(zp(a)).toVar(),l=Bi(Zo(Gp.sub(o),0)).toVar();o.assign(Zo(o,Gp));const d=Bi(vo(o)).toVar(),c=Ii($p(a,u).mul(d.sub(2)).add(1)).toVar();return Ei(u.greaterThan(2),(()=>{c.y.addAssign(d),u.subAssign(3)})),c.x.addAssign(u.mul(d)),c.x.addAssign(l.mul(Wn(3,kp))),c.y.addAssign(Wn(4,vo(n).sub(d))),c.x.mulAssign(s),c.y.mulAssign(i),e.sample(c).grad(Ii(),Ii())})),Kp=Ai((({envMap:e,mipInt:t,outputDirection:r,theta:s,axis:i,CUBEUV_TEXEL_WIDTH:n,CUBEUV_TEXEL_HEIGHT:o,CUBEUV_MAX_MIP:a})=>{const u=Uo(s),l=r.mul(u).add(i.cross(r).mul(Bo(s))).add(i.mul(i.dot(r).mul(u.oneMinus())));return qp(e,l,t,n,o,a)})),Xp=Ai((({n:e,latitudinal:t,poleAxis:r,outputDirection:s,weights:i,samples:n,dTheta:o,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c})=>{const h=Oi(Ra(t,r,na(r,s))).toVar();Ei(yo(h.equals(Oi(0))),(()=>{h.assign(Oi(s.z,0,s.x.negate()))})),h.assign(wo(h));const p=Oi().toVar();return p.addAssign(i.element(Ui(0)).mul(Kp({theta:0,axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c}))),pc({start:Ui(1),end:e},(({i:e})=>{Ei(e.greaterThanEqual(n),(()=>{gc()}));const t=Bi(o.mul(Bi(e))).toVar();p.addAssign(i.element(e).mul(Kp({theta:t.mul(-1),axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c}))),p.addAssign(i.element(e).mul(Kp({theta:t,axis:h,outputDirection:s,mipInt:a,envMap:u,CUBEUV_TEXEL_WIDTH:l,CUBEUV_TEXEL_HEIGHT:d,CUBEUV_MAX_MIP:c})))})),$i(p,1)}));let Yp=null;const Qp=new WeakMap;function Zp(e){let t=Qp.get(e);if((void 0!==t?t.pmremVersion:-1)!==e.pmremVersion){const r=e.image;if(e.isCubeTexture){if(!function(e){if(null==e)return!1;let t=0;const r=6;for(let s=0;s0}(r))return null;t=Yp.fromEquirectangular(e,t)}t.pmremVersion=e.pmremVersion,Qp.set(e,t)}return t.texture}class Jp extends Ls{static get type(){return"PMREMNode"}constructor(e,t=null,r=null){super("vec3"),this._value=e,this._pmrem=null,this.uvNode=t,this.levelNode=r,this._generator=null;const s=new J;s.isRenderTargetTexture=!0,this._texture=Eu(s),this._width=on(0),this._height=on(0),this._maxMip=on(0),this.updateBeforeType=Rs.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,r=1/e;return{texelWidth:1/(3*Math.max(Math.pow(2,t),112)),texelHeight:r,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,r=this._value;t!==r.pmremVersion&&(e=!0===r.isPMREMTexture?r:Zp(r),null!==e&&(this._pmrem=e,this.updateFromTexture(e)))}setup(e){null===Yp&&(Yp=e.createPMREMGenerator()),this.updateBefore(e);let t=this.uvNode;null===t&&e.context.getUV&&(t=e.context.getUV(this));const r=this.value;e.renderer.coordinateSystem===u&&!0!==r.isPMREMTexture&&!0===r.isRenderTargetTexture&&(t=Oi(t.x.negate(),t.yz)),t=Oi(t.x,t.y.negate(),t.z);let s=this.levelNode;return null===s&&e.context.getTextureLevel&&(s=e.context.getTextureLevel(this)),jp(this._texture,t,s,this._width,this._height,this._maxMip)}}const eg=Ni(Jp),tg=new WeakMap;class rg extends Tc{static get type(){return"EnvironmentNode"}constructor(e=null){super(),this.envNode=e}setup(e){const{material:t}=e;let r=this.envNode;if(r.isTextureNode||r.isMaterialReferenceNode){const e=r.isTextureNode?r.value:t[r.property];let s=tg.get(e);void 0===s&&(s=eg(e),tg.set(e,s)),r=s}const s=t.envMap?Dl("envMapIntensity","float",e.material):Dl("environmentIntensity","float",e.scene),i=!0===t.useAnisotropy||t.anisotropy>0?td:yl,n=r.context(sg(hn,i)).mul(s),o=r.context(ig(bl)).mul(Math.PI).mul(s),a=lu(n),u=lu(o);e.context.radiance.addAssign(a),e.context.iblIrradiance.addAssign(u);const l=e.context.lightingModel.clearcoatRadiance;if(l){const e=r.context(sg(mn,xl)).mul(s),t=lu(e);l.addAssign(t)}}}const sg=(e,t)=>{let r=null;return{getUV:()=>(null===r&&(r=ul.negate().reflect(t),r=e.mul(e).mix(r,t).normalize(),r=r.transformDirection(Pu)),r),getTextureLevel:()=>e}},ig=e=>({getUV:()=>e,getTextureLevel:()=>Bi(1)}),ng=new ee;class og extends nh{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(ng),this.setValues(e)}setupEnvironment(e){let t=super.setupEnvironment(e);return null===t&&e.environmentNode&&(t=e.environmentNode),t?new rg(t):null}setupLightingModel(){return new wp}setupSpecular(){const e=pa(Oi(.04),dn.rgb,pn);An.assign(e),Rn.assign(1)}setupVariants(){const e=this.metalnessNode?Bi(this.metalnessNode):vd;pn.assign(e);let t=this.roughnessNode?Bi(this.roughnessNode):_d;t=zh({roughness:t}),hn.assign(t),this.setupSpecular(),dn.assign($i(dn.rgb.mul(e.oneMinus()),dn.a))}copy(e){return this.emissiveNode=e.emissiveNode,this.metalnessNode=e.metalnessNode,this.roughnessNode=e.roughnessNode,super.copy(e)}}const ag=new te;class ug extends og{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(ag),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?Bi(this.iorNode):Dd;Un.assign(e),An.assign(pa(Qo(aa(Un.sub(1).div(Un.add(1))).mul(bd),Oi(1)).mul(yd),dn.rgb,pn)),Rn.assign(pa(yd,1,pn))}setupLightingModel(){return new wp(this.useClearcoat,this.useSheen,this.useIridescence,this.useAnisotropy,this.useTransmission,this.useDispersion)}setupVariants(e){if(super.setupVariants(e),this.useClearcoat){const e=this.clearcoatNode?Bi(this.clearcoatNode):Sd,t=this.clearcoatRoughnessNode?Bi(this.clearcoatRoughnessNode):Ad;gn.assign(e),mn.assign(zh({roughness:t}))}if(this.useSheen){const e=this.sheenNode?Oi(this.sheenNode):Ed,t=this.sheenRoughnessNode?Bi(this.sheenRoughnessNode):wd;fn.assign(e),yn.assign(t)}if(this.useIridescence){const e=this.iridescenceNode?Bi(this.iridescenceNode):Bd,t=this.iridescenceIORNode?Bi(this.iridescenceIORNode):Ud,r=this.iridescenceThicknessNode?Bi(this.iridescenceThicknessNode):Fd;bn.assign(e),xn.assign(t),Tn.assign(r)}if(this.useAnisotropy){const e=(this.anisotropyNode?Ii(this.anisotropyNode):Md).toVar();vn.assign(e.length()),Ei(vn.equal(0),(()=>{e.assign(Ii(1,0))})).Else((()=>{e.divAssign(Ii(vn)),vn.assign(vn.saturate())})),_n.assign(vn.pow2().mix(hn.pow2(),1)),Nn.assign(Jl[0].mul(e.x).add(Jl[1].mul(e.y))),Sn.assign(Jl[1].mul(e.x).sub(Jl[0].mul(e.y)))}if(this.useTransmission){const e=this.transmissionNode?Bi(this.transmissionNode):Pd,t=this.thicknessNode?Bi(this.thicknessNode):Id,r=this.attenuationDistanceNode?Bi(this.attenuationDistanceNode):Ld,s=this.attenuationColorNode?Oi(this.attenuationColorNode):Vd;if(Fn.assign(e),Pn.assign(t),In.assign(r),Dn.assign(s),this.useDispersion){const e=this.dispersionNode?Bi(this.dispersionNode):Wd;Ln.assign(e)}}}setupClearcoatNormal(){return this.clearcoatNormalNode?Oi(this.clearcoatNormalNode):Rd}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 lg extends wp{constructor(e=!1,t=!1,r=!1,s=!1,i=!1,n=!1,o=!1){super(e,t,r,s,i,n),this.useSSS=o}direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i){if(!0===this.useSSS){const s=i.material,{thicknessColorNode:n,thicknessDistortionNode:o,thicknessAmbientNode:a,thicknessAttenuationNode:u,thicknessPowerNode:l,thicknessScaleNode:d}=s,c=e.add(yl.mul(o)).normalize(),h=Bi(ul.dot(c.negate()).saturate().pow(l).mul(d)),p=Oi(h.add(a).mul(n));r.directDiffuse.addAssign(p.mul(u.mul(t)))}super.direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i)}}class dg extends ug{static get type(){return"MeshSSSNodeMaterial"}constructor(e){super(e),this.thicknessColorNode=null,this.thicknessDistortionNode=Bi(.1),this.thicknessAmbientNode=Bi(0),this.thicknessAttenuationNode=Bi(.1),this.thicknessPowerNode=Bi(2),this.thicknessScaleNode=Bi(10)}get useSSS(){return null!==this.thicknessColorNode}setupLightingModel(){return new lg(this.useClearcoat,this.useSheen,this.useIridescence,this.useAnisotropy,this.useTransmission,this.useDispersion,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 cg=Ai((({normal:e,lightDirection:t,builder:r})=>{const s=e.dot(t),i=Ii(s.mul(.5).add(.5),0);if(r.material.gradientMap){const e=Ol("gradientMap","texture").context({getUV:()=>i});return Oi(e.r)}{const e=i.fwidth().mul(.5);return pa(Oi(.7),Oi(1),ya(Bi(.7).sub(e.x),Bi(.7).add(e.x),i.x))}}));class hg extends Eh{direct({lightDirection:e,lightColor:t,reflectedLight:r},s,i){const n=cg({normal:hl,lightDirection:e,builder:i}).mul(t);r.directDiffuse.addAssign(n.mul(Fh({diffuseColor:dn.rgb})))}indirect({ambientOcclusion:e,irradiance:t,reflectedLight:r}){r.indirectDiffuse.addAssign(t.mul(Fh({diffuseColor:dn}))),r.indirectDiffuse.mulAssign(e)}}const pg=new re;class gg extends nh{static get type(){return"MeshToonNodeMaterial"}constructor(e){super(),this.isMeshToonNodeMaterial=!0,this.lights=!0,this.setDefaultValues(pg),this.setValues(e)}setupLightingModel(){return new hg}}class mg extends Ls{static get type(){return"MatcapUVNode"}constructor(){super("vec2")}setup(){const e=Oi(ul.z,0,ul.x.negate()).normalize(),t=ul.cross(e);return Ii(e.dot(yl),t.dot(yl)).mul(.495).add(.5)}}const fg=Si(mg),yg=new se;class bg extends nh{static get type(){return"MeshMatcapNodeMaterial"}constructor(e){super(),this.isMeshMatcapNodeMaterial=!0,this.setDefaultValues(yg),this.setValues(e)}setupVariants(e){const t=fg;let r;r=e.material.matcap?Ol("matcap","texture").context({getUV:()=>t}):Oi(pa(.2,.8,t.y)),dn.rgb.mulAssign(r.rgb)}}class xg extends Ls{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:r}=this;if("vec2"===this.getNodeType(e)){const e=t.cos(),s=t.sin();return qi(e,s,s.negate(),e).mul(r)}{const e=t,s=Xi($i(1,0,0,0),$i(0,Uo(e.x),Bo(e.x).negate(),0),$i(0,Bo(e.x),Uo(e.x),0),$i(0,0,0,1)),i=Xi($i(Uo(e.y),0,Bo(e.y),0),$i(0,1,0,0),$i(Bo(e.y).negate(),0,Uo(e.y),0),$i(0,0,0,1)),n=Xi($i(Uo(e.z),Bo(e.z).negate(),0,0),$i(Bo(e.z),Uo(e.z),0,0),$i(0,0,1,0),$i(0,0,0,1));return s.mul(i).mul(n).mul($i(r,1)).xyz}}}const Tg=Ni(xg),_g=new ie;class vg extends nh{static get type(){return"SpriteNodeMaterial"}constructor(e){super(),this.isSpriteNodeMaterial=!0,this._useSizeAttenuation=!0,this.positionNode=null,this.rotationNode=null,this.scaleNode=null,this.setDefaultValues(_g),this.setValues(e)}setupPositionView(e){const{object:t,camera:r}=e,s=this.sizeAttenuation,{positionNode:i,rotationNode:n,scaleNode:o}=this,a=Zu.mul(Oi(i||0));let u=Ii(ju[0].xyz.length(),ju[1].xyz.length());if(null!==o&&(u=u.mul(Bi(o))),!1===s)if(r.isPerspectiveCamera)u=u.mul(a.z.negate());else{const e=Bi(2).div(Uu.element(1).element(1));u=u.mul(e.mul(2))}let l=rl.xy;if(t.center&&!0===t.center.isVector2){const e=((e,t,r)=>Ti(new Xa(e,t,r)))("center","vec2",t);l=l.sub(e.sub(.5))}l=l.mul(u);const d=Bi(n||Cd),c=Tg(l,d);return $i(a.xy.add(c),a.zw)}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)}}const Ng=new ne;class Sg extends vg{static get type(){return"PointsNodeMaterial"}constructor(e){super(),this.sizeNode=null,this.isPointsNodeMaterial=!0,this.setDefaultValues(Ng),this.setValues(e)}setupPositionView(){const{positionNode:e}=this;return Zu.mul(Oi(e||sl)).xyz}setupVertex(e){const t=super.setupVertex(e);if(!0!==e.material.isNodeMaterial)return t;const{rotationNode:r,scaleNode:s,sizeNode:i}=this,n=rl.xy.toVar(),o=Bc.z.div(Bc.w);if(r&&r.isNode){const e=Bi(r);n.assign(Tg(n,e))}let a=null!==i?Ii(i):Hd;return!0===this.sizeAttenuation&&(a=a.mul(a.div(al.z.negate()))),s&&s.isNode&&(a=a.mul(Ii(s))),n.mulAssign(a.mul(2)),n.assign(n.div(Bc.z)),n.y.assign(n.y.mul(o)),n.assign(n.mul(t.w)),t.addAssign($i(n,0,0)),t}get alphaToCoverage(){return this._useAlphaToCoverage}set alphaToCoverage(e){this._useAlphaToCoverage!==e&&(this._useAlphaToCoverage=e,this.needsUpdate=!0)}}class Ag extends Eh{constructor(){super(),this.shadowNode=Bi(1).toVar("shadowMask")}direct({shadowMask:e}){this.shadowNode.mulAssign(e)}finish(e){dn.a.mulAssign(this.shadowNode.oneMinus()),e.outgoingLight.rgb.assign(dn.rgb)}}const Rg=new oe;class Cg extends nh{static get type(){return"ShadowNodeMaterial"}constructor(e){super(),this.isShadowNodeMaterial=!0,this.lights=!0,this.setDefaultValues(Rg),this.setValues(e)}setupLightingModel(){return new Ag}}const Eg=Ai((({texture:e,uv:t})=>{const r=1e-4,s=Oi().toVar();return Ei(t.x.lessThan(r),(()=>{s.assign(Oi(1,0,0))})).ElseIf(t.y.lessThan(r),(()=>{s.assign(Oi(0,1,0))})).ElseIf(t.z.lessThan(r),(()=>{s.assign(Oi(0,0,1))})).ElseIf(t.x.greaterThan(.9999),(()=>{s.assign(Oi(-1,0,0))})).ElseIf(t.y.greaterThan(.9999),(()=>{s.assign(Oi(0,-1,0))})).ElseIf(t.z.greaterThan(.9999),(()=>{s.assign(Oi(0,0,-1))})).Else((()=>{const r=.01,i=e.sample(t.add(Oi(-.01,0,0))).r.sub(e.sample(t.add(Oi(r,0,0))).r),n=e.sample(t.add(Oi(0,-.01,0))).r.sub(e.sample(t.add(Oi(0,r,0))).r),o=e.sample(t.add(Oi(0,0,-.01))).r.sub(e.sample(t.add(Oi(0,0,r))).r);s.assign(Oi(i,n,o))})),s.normalize()}));class wg extends Cu{static get type(){return"Texture3DNode"}constructor(e,t=null,r=null){super(e,t,r),this.isTexture3DNode=!0}getInputType(){return"texture3D"}getDefaultUV(){return Oi(.5,.5,.5)}setUpdateMatrix(){}setupUV(e,t){const r=this.value;return!e.isFlipY()||!0!==r.isRenderTargetTexture&&!0!==r.isFramebufferTexture||(t=this.sampler?t.flipY():t.setY(Ui(Su(this,this.levelNode).y).sub(t.y).sub(1))),t}generateUV(e,t){return t.build(e,"vec3")}normal(e){return Eg({texture:this,uv:e})}}const Mg=Ni(wg);class Bg extends nh{static get type(){return"VolumeNodeMaterial"}constructor(t){super(),this.isVolumeNodeMaterial=!0,this.base=new e(16777215),this.map=null,this.steps=100,this.testNode=null,this.setValues(t)}setup(e){const t=Mg(this.map,null,0),r=Ai((({orig:e,dir:t})=>{const r=Oi(-.5),s=Oi(.5),i=t.reciprocal(),n=r.sub(e).mul(i),o=s.sub(e).mul(i),a=Qo(n,o),u=Zo(n,o),l=Zo(a.x,Zo(a.y,a.z)),d=Qo(u.x,Qo(u.y,u.z));return Ii(l,d)}));this.fragmentNode=Ai((()=>{const e=La(Oi(Qu.mul($i(Lu,1)))),s=La(rl.sub(e)).normalize(),i=Ii(r({orig:e,dir:s})).toVar();i.x.greaterThan(i.y).discard(),i.assign(Ii(Zo(i.x,0),i.y));const n=Oi(e.add(i.x.mul(s))).toVar(),o=Oi(s.abs().reciprocal()).toVar(),a=Bi(Qo(o.x,Qo(o.y,o.z))).toVar("delta");a.divAssign(Ol("steps","float"));const u=$i(Ol("base","color"),0).toVar();return pc({type:"float",start:i.x,end:i.y,update:"+= delta"},(()=>{const e=un("float","d").assign(t.sample(n.add(.5)).r);null!==this.testNode?this.testNode({map:t,mapValue:e,probe:n,finalColor:u}).append():(u.a.assign(1),gc()),n.addAssign(s.mul(a))})),u.a.equal(0).discard(),$i(u)}))(),super.setup(e)}}class Ug{constructor(e,t){this.nodes=e,this.info=t,this._context=self,this._animationLoop=null,this._requestId=null}start(){const e=(t,r)=>{this._requestId=this._context.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,r)};e()}stop(){this._context.cancelAnimationFrame(this._requestId),this._requestId=null}setAnimationLoop(e){this._animationLoop=e}setContext(e){this._context=e}dispose(){this.stop()}}class Fg{constructor(){this.weakMap=new WeakMap}get(e){let t=this.weakMap;for(let r=0;r{this.dispose()},this.material.addEventListener("dispose",this.onMaterialDispose)}updateClipping(e){this.clippingContext=e}get clippingNeedsUpdate(){return null!==this.clippingContext&&this.clippingContext.cacheKey!==this.clippingContextCacheKey&&(this.clippingContextCacheKey=this.clippingContext.cacheKey,!0)}get hardwareClippingPlanes(){return!0===this.material.hardwareClipping?this.clippingContext.unionClippingCount: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)}getIndirect(){return this._geometries.getIndirect(this)}getChainArray(){return[this.object,this.material,this.context,this.lightsNode]}setGeometry(e){this.geometry=e,this.attributes=null}getAttributes(){if(null!==this.attributes)return this.attributes;const e=this.getNodeBuilderState().nodeAttributes,t=this.geometry,r=[],s=new Set;for(const i of e){const e=i.node&&i.node.attribute?i.node.attribute:t.getAttribute(i.name);if(void 0===e)continue;r.push(e);const n=e.isInterleavedBufferAttribute?e.data:e;s.add(n)}return this.attributes=r,this.vertexBuffers=Array.from(s.values()),r}getVertexBuffers(){return null===this.vertexBuffers&&this.getAttributes(),this.vertexBuffers}getDrawParameters(){const{object:e,material:t,geometry:r,group:s,drawRange:i}=this,n=this.drawParams||(this.drawParams={vertexCount:0,firstVertex:0,instanceCount:0,firstInstance:0}),o=this.getIndex(),a=null!==o,u=r.isInstancedBufferGeometry?r.instanceCount:e.count>1?e.count:1;if(0===u)return null;if(n.instanceCount=u,!0===e.isBatchedMesh)return n;let l=1;!0!==t.wireframe||e.isPoints||e.isLineSegments||e.isLine||e.isLineLoop||(l=2);let d=i.start*l,c=(i.start+i.count)*l;null!==s&&(d=Math.max(d,s.start*l),c=Math.min(c,(s.start+s.count)*l));const h=r.attributes.position;let p=1/0;a?p=o.count:null!=h&&(p=h.count),d=Math.max(d,0),c=Math.min(c,p);const g=c-d;return g<0||g===1/0?null:(n.vertexCount=g,n.firstVertex=d,n)}getGeometryCacheKey(){const{geometry:e}=this;let t="";for(const r of Object.keys(e.attributes).sort()){const s=e.attributes[r];t+=r+",",s.data&&(t+=s.data.stride+","),s.offset&&(t+=s.offset+","),s.itemSize&&(t+=s.itemSize+","),s.normalized&&(t+="n,")}for(const r of Object.keys(e.morphAttributes).sort()){const s=e.morphAttributes[r];t+="morph-"+r+",";for(let e=0,r=s.length;e1&&(r+=e.uuid+","),r+=e.receiveShadow+",",ls(r)}get needsGeometryUpdate(){return this.geometry.id!==this.object.geometry.id}get needsUpdate(){return this.initialNodesCacheKey!==this.getDynamicCacheKey()||this.clippingNeedsUpdate}getDynamicCacheKey(){let e=0;return!0!==this.material.isShadowPassMaterial&&(e=this._nodes.getCacheKey(this.scene,this.lightsNode)),this.object.receiveShadow&&(e+=1),e}getCacheKey(){return this.getMaterialCacheKey()+this.getDynamicCacheKey()}dispose(){this.material.removeEventListener("dispose",this.onMaterialDispose),this.onDispose()}}const Dg=[];class Lg{constructor(e,t,r,s,i,n){this.renderer=e,this.nodes=t,this.geometries=r,this.pipelines=s,this.bindings=i,this.info=n,this.chainMaps={}}get(e,t,r,s,i,n,o,a){const u=this.getChainMap(a);Dg[0]=e,Dg[1]=t,Dg[2]=n,Dg[3]=i;let l=u.get(Dg);return void 0===l?(l=this.createRenderObject(this.nodes,this.geometries,this.renderer,e,t,r,s,i,n,o,a),u.set(Dg,l)):(l.updateClipping(o),l.needsGeometryUpdate&&l.setGeometry(e.geometry),(l.version!==t.version||l.needsUpdate)&&(l.initialCacheKey!==l.getCacheKey()?(l.dispose(),l=this.get(e,t,r,s,i,n,o,a)):l.version=t.version)),Dg.length=0,l}getChainMap(e="default"){return this.chainMaps[e]||(this.chainMaps[e]=new Fg)}dispose(){this.chainMaps={}}createRenderObject(e,t,r,s,i,n,o,a,u,l,d){const c=this.getChainMap(d),h=new Ig(e,t,r,s,i,n,o,a,u,l);return h.onDispose=()=>{this.pipelines.delete(h),this.bindings.delete(h),this.nodes.delete(h),c.delete(h.getChainArray())},h}}class Vg{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=null;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 Og=1,Gg=2,kg=3,zg=4,$g=16;class Hg extends Vg{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 r=this.get(e);if(void 0===r.version)t===Og?this.backend.createAttribute(e):t===Gg?this.backend.createIndexAttribute(e):t===kg?this.backend.createStorageAttribute(e):t===zg&&this.backend.createIndirectStorageAttribute(e),r.version=this._getBufferAttribute(e).version;else{const t=this._getBufferAttribute(e);(r.version=0;--t)if(e[t]>=65535)return!0;return!1}(t)?ae:ue)(t,1);return i.version=Wg(e),i}class qg extends Vg{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 r=()=>{this.info.memory.geometries--;const s=t.index,i=e.getAttributes();null!==s&&this.attributes.delete(s);for(const e of i)this.attributes.delete(e);const n=this.wireframes.get(t);void 0!==n&&this.attributes.delete(n),t.removeEventListener("dispose",r)};t.addEventListener("dispose",r)}updateAttributes(e){const t=e.getAttributes();for(const e of t)e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute?this.updateAttribute(e,kg):this.updateAttribute(e,Og);const r=this.getIndex(e);null!==r&&this.updateAttribute(r,Gg);const s=e.geometry.indirect;null!==s&&this.updateAttribute(s,zg)}updateAttribute(e,t){const r=this.info.render.calls;e.isInterleavedBufferAttribute?void 0===this.attributeCall.get(e)?(this.attributes.update(e,t),this.attributeCall.set(e,r)):this.attributeCall.get(e.data)!==r&&(this.attributes.update(e,t),this.attributeCall.set(e.data,r),this.attributeCall.set(e,r)):this.attributeCall.get(e)!==r&&(this.attributes.update(e,t),this.attributeCall.set(e,r))}getIndirect(e){return e.geometry.indirect}getIndex(e){const{geometry:t,material:r}=e;let s=t.index;if(!0===r.wireframe){const e=this.wireframes;let r=e.get(t);void 0===r?(r=jg(t),e.set(t,r)):r.version!==Wg(t)&&(this.attributes.delete(r),r=jg(t),e.set(t,r)),s=r}return s}}class Kg{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,r){this.render.drawCalls++,e.isMesh||e.isSprite?this.render.triangles+=r*(t/3):e.isPoints?this.render.points+=r*t:e.isLineSegments?this.render.lines+=r*(t/2):e.isLine?this.render.lines+=r*(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 Xg{constructor(e){this.cacheKey=e,this.usedTimes=0}}class Yg extends Xg{constructor(e,t,r){super(e),this.vertexProgram=t,this.fragmentProgram=r}}class Qg extends Xg{constructor(e,t){super(e),this.computeProgram=t,this.isComputePipeline=!0}}let Zg=0;class Jg{constructor(e,t,r,s=null,i=null){this.id=Zg++,this.code=e,this.stage=t,this.name=r,this.transforms=s,this.attributes=i,this.usedTimes=0}}class em extends Vg{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:r}=this,s=this.get(e);if(this._needsComputeUpdate(e)){const i=s.pipeline;i&&(i.usedTimes--,i.computeProgram.usedTimes--);const n=this.nodes.getForCompute(e);let o=this.programs.compute.get(n.computeShader);void 0===o&&(i&&0===i.computeProgram.usedTimes&&this._releaseProgram(i.computeProgram),o=new Jg(n.computeShader,"compute",e.name,n.transforms,n.nodeAttributes),this.programs.compute.set(n.computeShader,o),r.createProgram(o));const a=this._getComputeCacheKey(e,o);let u=this.caches.get(a);void 0===u&&(i&&0===i.usedTimes&&this._releasePipeline(i),u=this._getComputePipeline(e,o,a,t)),u.usedTimes++,o.usedTimes++,s.version=e.version,s.pipeline=u}return s.pipeline}getForRender(e,t=null){const{backend:r}=this,s=this.get(e);if(this._needsRenderUpdate(e)){const i=s.pipeline;i&&(i.usedTimes--,i.vertexProgram.usedTimes--,i.fragmentProgram.usedTimes--);const n=e.getNodeBuilderState(),o=e.material?e.material.name:"";let a=this.programs.vertex.get(n.vertexShader);void 0===a&&(i&&0===i.vertexProgram.usedTimes&&this._releaseProgram(i.vertexProgram),a=new Jg(n.vertexShader,"vertex",o),this.programs.vertex.set(n.vertexShader,a),r.createProgram(a));let u=this.programs.fragment.get(n.fragmentShader);void 0===u&&(i&&0===i.fragmentProgram.usedTimes&&this._releaseProgram(i.fragmentProgram),u=new Jg(n.fragmentShader,"fragment",o),this.programs.fragment.set(n.fragmentShader,u),r.createProgram(u));const l=this._getRenderCacheKey(e,a,u);let d=this.caches.get(l);void 0===d?(i&&0===i.usedTimes&&this._releasePipeline(i),d=this._getRenderPipeline(e,a,u,l,t)):e.pipeline=d,d.usedTimes++,a.usedTimes++,u.usedTimes++,s.pipeline=d}return s.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,r,s){r=r||this._getComputeCacheKey(e,t);let i=this.caches.get(r);return void 0===i&&(i=new Qg(r,t),this.caches.set(r,i),this.backend.createComputePipeline(i,s)),i}_getRenderPipeline(e,t,r,s,i){s=s||this._getRenderCacheKey(e,t,r);let n=this.caches.get(s);return void 0===n&&(n=new Yg(s,t,r),this.caches.set(s,n),e.pipeline=n,this.backend.createRenderPipeline(e,i)),n}_getComputeCacheKey(e,t){return e.id+","+t.id}_getRenderCacheKey(e,t,r){return t.id+","+r.id+","+this.backend.getRenderCacheKey(e)}_releasePipeline(e){this.caches.delete(e.cacheKey)}_releaseProgram(e){const t=e.code,r=e.stage;this.programs[r].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 tm extends Vg{constructor(e,t,r,s,i,n){super(),this.backend=e,this.textures=r,this.pipelines=i,this.attributes=s,this.nodes=t,this.info=n,this.pipelines.bindings=this}getForRender(e){const t=e.getBindings();for(const e of t){const r=this.get(e);void 0===r.bindGroup&&(this._init(e),this.backend.createBindings(e,t,0),r.bindGroup=e)}return t}getForCompute(e){const t=this.nodes.getForCompute(e).bindings;for(const e of t){const r=this.get(e);void 0===r.bindGroup&&(this._init(e),this.backend.createBindings(e,t,0),r.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,r=e.isIndirectStorageBufferAttribute?zg:kg;this.attributes.update(e,r)}}_update(e,t){const{backend:r}=this;let s=!1,i=!0,n=0,o=0;for(const t of e.bindings){if(t.isNodeUniformsGroup){if(!1===this.nodes.updateGroup(t))continue}if(t.isUniformBuffer){t.update()&&r.updateBinding(t)}else if(t.isSampler)t.update();else if(t.isSampledTexture){const e=this.textures.get(t.texture);t.needsBindingsUpdate(e.generation)&&(s=!0);const a=t.update(),u=t.texture;a&&this.textures.updateTexture(u);const l=r.get(u);if(void 0!==l.externalTexture||e.isDefaultTexture?i=!1:(n=10*n+u.id,o+=u.version),!0===r.isWebGPUBackend&&void 0===l.texture&&void 0===l.externalTexture&&(console.error("Bindings._update: binding should be available:",t,a,u,t.textureNode.value,s),this.textures.updateTexture(u),s=!0),!0===u.isStorageTexture){const e=this.get(u);!0===t.store?e.needsMipmap=!0:this.textures.needsMipmaps(u)&&!0===e.needsMipmap&&(this.backend.generateMipmaps(u),e.needsMipmap=!1)}}}!0===s&&this.backend.updateBindings(e,t,i?n:0,o)}}function rm(e,t){return e.groupOrder!==t.groupOrder?e.groupOrder-t.groupOrder:e.renderOrder!==t.renderOrder?e.renderOrder-t.renderOrder:e.material.id!==t.material.id?e.material.id-t.material.id:e.z!==t.z?e.z-t.z:e.id-t.id}function sm(e,t){return e.groupOrder!==t.groupOrder?e.groupOrder-t.groupOrder:e.renderOrder!==t.renderOrder?e.renderOrder-t.renderOrder:e.z!==t.z?t.z-e.z:e.id-t.id}function im(e){return(e.transmission>0||e.transmissionNode)&&e.side===le&&!1===e.forceSinglePass}class nm{constructor(e,t,r){this.renderItems=[],this.renderItemsIndex=0,this.opaque=[],this.transparentDoublePass=[],this.transparent=[],this.bundles=[],this.lightsNode=e.getNode(t,r),this.lightsArray=[],this.scene=t,this.camera=r,this.occlusionQueryCount=0}begin(){return this.renderItemsIndex=0,this.opaque.length=0,this.transparentDoublePass.length=0,this.transparent.length=0,this.bundles.length=0,this.lightsArray.length=0,this.occlusionQueryCount=0,this}getNextRenderItem(e,t,r,s,i,n,o){let a=this.renderItems[this.renderItemsIndex];return void 0===a?(a={id:e.id,object:e,geometry:t,material:r,groupOrder:s,renderOrder:e.renderOrder,z:i,group:n,clippingContext:o},this.renderItems[this.renderItemsIndex]=a):(a.id=e.id,a.object=e,a.geometry=t,a.material=r,a.groupOrder=s,a.renderOrder=e.renderOrder,a.z=i,a.group=n,a.clippingContext=o),this.renderItemsIndex++,a}push(e,t,r,s,i,n,o){const a=this.getNextRenderItem(e,t,r,s,i,n,o);!0===e.occlusionTest&&this.occlusionQueryCount++,!0===r.transparent||r.transmission>0?(im(r)&&this.transparentDoublePass.push(a),this.transparent.push(a)):this.opaque.push(a)}unshift(e,t,r,s,i,n,o){const a=this.getNextRenderItem(e,t,r,s,i,n,o);!0===r.transparent||r.transmission>0?(im(r)&&this.transparentDoublePass.unshift(a),this.transparent.unshift(a)):this.opaque.unshift(a)}pushBundle(e){this.bundles.push(e)}pushLight(e){this.lightsArray.push(e)}sort(e,t){this.opaque.length>1&&this.opaque.sort(e||rm),this.transparentDoublePass.length>1&&this.transparentDoublePass.sort(t||sm),this.transparent.length>1&&this.transparent.sort(t||sm)}finish(){this.lightsNode.setLights(this.lightsArray);for(let e=this.renderItemsIndex,t=this.renderItems.length;e>t,u=o.height>>t;let l=e.depthTexture||i[t];const d=!0===e.depthBuffer||!0===e.stencilBuffer;let c=!1;void 0===l&&d&&(l=new B,l.format=e.stencilBuffer?ce:he,l.type=e.stencilBuffer?pe:b,l.image.width=a,l.image.height=u,i[t]=l),r.width===o.width&&o.height===r.height||(c=!0,l&&(l.needsUpdate=!0,l.image.width=a,l.image.height=u)),r.width=o.width,r.height=o.height,r.textures=n,r.depthTexture=l||null,r.depth=e.depthBuffer,r.stencil=e.stencilBuffer,r.renderTarget=e,r.sampleCount!==s&&(c=!0,l&&(l.needsUpdate=!0),r.sampleCount=s);const h={sampleCount:s};for(let e=0;e{e.removeEventListener("dispose",t);for(let e=0;e0){const s=e.image;if(void 0===s)console.warn("THREE.Renderer: Texture marked for update but image is undefined.");else if(!1===s.complete)console.warn("THREE.Renderer: Texture marked for update but image is incomplete.");else{if(e.images){const r=[];for(const t of e.images)r.push(t);t.images=r}else t.image=s;void 0!==r.isDefaultTexture&&!0!==r.isDefaultTexture||(i.createTexture(e,t),r.isDefaultTexture=!1,r.generation=e.version),!0===e.source.dataReady&&i.updateTexture(e,t),t.needsMipmaps&&0===e.mipmaps.length&&i.generateMipmaps(e)}}else i.createDefaultTexture(e),r.isDefaultTexture=!0,r.generation=e.version}if(!0!==r.initialized){r.initialized=!0,r.generation=e.version,this.info.memory.textures++;const t=()=>{e.removeEventListener("dispose",t),this._destroyTexture(e),this.info.memory.textures--};e.addEventListener("dispose",t)}r.version=e.version}getSize(e,t=mm){let r=e.images?e.images[0]:e.image;return r?(void 0!==r.image&&(r=r.image),t.width=r.width||1,t.height=r.height||1,t.depth=e.isCubeTexture?6:r.depth||1):t.width=t.height=t.depth=1,t}getMipLevels(e,t,r){let s;return s=e.isCompressedTexture?e.mipmaps?e.mipmaps.length:1:Math.floor(Math.log2(Math.max(t,r)))+1,s}needsMipmaps(e){return this.isEnvironmentTexture(e)||!0===e.isCompressedTexture||e.generateMipmaps}isEnvironmentTexture(e){const t=e.mapping;return t===W||t===j||t===_||t===v}_destroyTexture(e){this.backend.destroySampler(e),this.backend.destroyTexture(e),this.delete(e)}}class ym extends e{constructor(e,t,r,s=1){super(e,t,r),this.a=s}set(e,t,r,s=1){return this.a=s,super.set(e,t,r)}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)}}class bm extends an{static get type(){return"ParameterNode"}constructor(e,t=null){super(e,t),this.isParameterNode=!0}getHash(){return this.uuid}generate(){return this.name}}class xm extends Ps{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 r=new xi(t);return this._currentCond=Ra(e,r),this.add(this._currentCond)}ElseIf(e,t){const r=new xi(t),s=Ra(e,r);return this._currentCond.elseNode=s,this._currentCond=s,this}Else(e){return this._currentCond.elseNode=new xi(e),this}build(e,...t){const r=Ci();Ri(this);for(const t of this.nodes)t.build(e,"void");return Ri(r),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 Tm=Ni(xm);class _m extends Ps{static get type(){return"OutputStructNode"}constructor(...e){super(),this.members=e,this.isOutputStructNode=!0}setup(e){super.setup(e);const t=this.members,r=[];for(let s=0;s{const t=e.toUint().mul(747796405).add(2891336453),r=t.shiftRight(t.shiftRight(28).add(4)).bitXor(t).mul(277803737);return r.shiftRight(22).bitXor(r).toFloat().mul(1/2**32)})),Cm=(e,t)=>oa(Wn(4,e.mul(Hn(1,e))),t),Em=Ai((([e])=>e.fract().sub(.5).abs())).setLayout({name:"tri",type:"float",inputs:[{name:"x",type:"float"}]}),wm=Ai((([e])=>Oi(Em(e.z.add(Em(e.y.mul(1)))),Em(e.z.add(Em(e.x.mul(1)))),Em(e.y.add(Em(e.x.mul(1))))))).setLayout({name:"tri3",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),Mm=Ai((([e,t,r])=>{const s=Oi(e).toVar(),i=Bi(1.4).toVar(),n=Bi(0).toVar(),o=Oi(s).toVar();return pc({start:Bi(0),end:Bi(3),type:"float",condition:"<="},(()=>{const e=Oi(wm(o.mul(2))).toVar();s.addAssign(e.add(r.mul(Bi(.1).mul(t)))),o.mulAssign(1.8),i.mulAssign(1.5),s.mulAssign(1.2);const a=Bi(Em(s.z.add(Em(s.x.add(Em(s.y)))))).toVar();n.addAssign(a.div(i)),o.addAssign(.14)})),n})).setLayout({name:"triNoise3D",type:"float",inputs:[{name:"position",type:"vec3"},{name:"speed",type:"float"},{name:"time",type:"float"}]});class Bm extends Ps{static get type(){return"FunctionOverloadingNode"}constructor(e=[],...t){super(),this.functionNodes=e,this.parametersNodes=t,this._candidateFnCall=null,this.global=!0}getNodeType(){return this.functionNodes[0].shaderNode.layout.type}setup(e){const t=this.parametersNodes;let r=this._candidateFnCall;if(null===r){let s=null,i=-1;for(const r of this.functionNodes){const n=r.shaderNode.layout;if(null===n)throw new Error("FunctionOverloadingNode: FunctionNode must be a layout.");const o=n.inputs;if(t.length===o.length){let n=0;for(let r=0;ri&&(s=r,i=n)}}this._candidateFnCall=r=s(...t)}return r}}const Um=Ni(Bm),Fm=e=>(...t)=>Um(e,...t),Pm=on(0).setGroup(rn).onRenderUpdate((e=>e.time)),Im=on(0).setGroup(rn).onRenderUpdate((e=>e.deltaTime)),Dm=on(0,"uint").setGroup(rn).onRenderUpdate((e=>e.frameId)),Lm=Ai((([e,t,r=Ii(.5)])=>Tg(e.sub(r),t).add(r))),Vm=Ai((([e,t,r=Ii(.5)])=>{const s=e.sub(r),i=s.dot(s),n=i.mul(i).mul(t);return e.add(s.mul(n))})),Om=Ai((({position:e=null,horizontal:t=!0,vertical:r=!1})=>{let s;null!==e?(s=ju.toVar(),s[3][0]=e.x,s[3][1]=e.y,s[3][2]=e.z):s=ju;const i=Pu.mul(s);return yi(t)&&(i[0][0]=ju[0].length(),i[0][1]=0,i[0][2]=0),yi(r)&&(i[1][0]=0,i[1][1]=ju[1].length(),i[1][2]=0),i[2][0]=0,i[2][1]=0,i[2][2]=1,Uu.mul(i).mul(sl)})),Gm=Ai((([e=null])=>{const t=Zc();return Zc(Hc(e)).sub(t).lessThan(0).select(Ec,e)}));class km extends Ps{static get type(){return"SpriteSheetUVNode"}constructor(e,t=vu(),r=Bi(0)){super("vec2"),this.countNode=e,this.uvNode=t,this.frameNode=r}setup(){const{frameNode:e,uvNode:t,countNode:r}=this,{width:s,height:i}=r,n=e.mod(s.mul(i)).floor(),o=n.mod(s),a=i.sub(n.add(1).div(s).ceil()),u=r.reciprocal(),l=Ii(o,a);return t.add(l).mul(u)}}const zm=Ni(km);class $m extends Ps{static get type(){return"TriplanarTexturesNode"}constructor(e,t=null,r=null,s=Bi(1),i=sl,n=pl){super("vec4"),this.textureXNode=e,this.textureYNode=t,this.textureZNode=r,this.scaleNode=s,this.positionNode=i,this.normalNode=n}setup(){const{textureXNode:e,textureYNode:t,textureZNode:r,scaleNode:s,positionNode:i,normalNode:n}=this;let o=n.abs().normalize();o=o.div(o.dot(Oi(1)));const a=i.yz.mul(s),u=i.zx.mul(s),l=i.xy.mul(s),d=e.value,c=null!==t?t.value:d,h=null!==r?r.value:d,p=Eu(d,a).mul(o.x),g=Eu(c,u).mul(o.y),m=Eu(h,l).mul(o.z);return $n(p,g,m)}}const Hm=Ni($m),Wm=new fe,jm=new r,qm=new r,Km=new r,Xm=new n,Ym=new r(0,0,-1),Qm=new s,Zm=new r,Jm=new r,ef=new s,tf=new t,rf=new me,sf=Ec.flipX();rf.depthTexture=new B(1,1);let nf=!1;class of extends Cu{static get type(){return"ReflectorNode"}constructor(e={}){super(e.defaultTexture||rf.texture,sf),this._reflectorBaseNode=e.reflector||new af(this,e),this._depthNode=null,this.setUpdateMatrix(!1)}get reflector(){return this._reflectorBaseNode}get target(){return this._reflectorBaseNode.target}getDepthNode(){if(null===this._depthNode){if(!0!==this._reflectorBaseNode.depth)throw new Error("THREE.ReflectorNode: Depth node can only be requested when the reflector is created with { depth: true }. ");this._depthNode=Ti(new of({defaultTexture:rf.depthTexture,reflector:this._reflectorBaseNode}))}return this._depthNode}setup(e){return e.object.isQuadMesh||this._reflectorBaseNode.build(e),super.setup(e)}clone(){const e=new this.constructor(this.reflectorNode);return e._reflectorBaseNode=this._reflectorBaseNode,e}}class af extends Ps{static get type(){return"ReflectorBaseNode"}constructor(e,t={}){super();const{target:r=new ye,resolution:s=1,generateMipmaps:i=!1,bounces:n=!0,depth:o=!1}=t;this.textureNode=e,this.target=r,this.resolution=s,this.generateMipmaps=i,this.bounces=n,this.depth=o,this.updateBeforeType=n?Rs.RENDER:Rs.FRAME,this.virtualCameras=new WeakMap,this.renderTargets=new WeakMap}_updateResolution(e,t){const r=this.resolution;t.getDrawingBufferSize(tf),e.setSize(Math.round(tf.width*r),Math.round(tf.height*r))}setup(e){return this._updateResolution(rf,e.renderer),super.setup(e)}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 me(0,0,{type:be}),!0===this.generateMipmaps&&(t.texture.minFilter=xe,t.texture.generateMipmaps=!0),!0===this.depth&&(t.depthTexture=new B),this.renderTargets.set(e,t)),t}updateBefore(e){if(!1===this.bounces&&nf)return!1;nf=!0;const{scene:t,camera:r,renderer:s,material:i}=e,{target:n}=this,o=this.getVirtualCamera(r),a=this.getRenderTarget(o);if(s.getDrawingBufferSize(tf),this._updateResolution(a,s),qm.setFromMatrixPosition(n.matrixWorld),Km.setFromMatrixPosition(r.matrixWorld),Xm.extractRotation(n.matrixWorld),jm.set(0,0,1),jm.applyMatrix4(Xm),Zm.subVectors(qm,Km),Zm.dot(jm)>0)return;Zm.reflect(jm).negate(),Zm.add(qm),Xm.extractRotation(r.matrixWorld),Ym.set(0,0,-1),Ym.applyMatrix4(Xm),Ym.add(Km),Jm.subVectors(qm,Ym),Jm.reflect(jm).negate(),Jm.add(qm),o.coordinateSystem=r.coordinateSystem,o.position.copy(Zm),o.up.set(0,1,0),o.up.applyMatrix4(Xm),o.up.reflect(jm),o.lookAt(Jm),o.near=r.near,o.far=r.far,o.updateMatrixWorld(),o.projectionMatrix.copy(r.projectionMatrix),Wm.setFromNormalAndCoplanarPoint(jm,qm),Wm.applyMatrix4(o.matrixWorldInverse),Qm.set(Wm.normal.x,Wm.normal.y,Wm.normal.z,Wm.constant);const u=o.projectionMatrix;ef.x=(Math.sign(Qm.x)+u.elements[8])/u.elements[0],ef.y=(Math.sign(Qm.y)+u.elements[9])/u.elements[5],ef.z=-1,ef.w=(1+u.elements[10])/u.elements[14],Qm.multiplyScalar(1/Qm.dot(ef));u.elements[2]=Qm.x,u.elements[6]=Qm.y,u.elements[10]=s.coordinateSystem===l?Qm.z-0:Qm.z+1-0,u.elements[14]=Qm.w,this.textureNode.value=a.texture,!0===this.depth&&(this.textureNode.getDepthNode().value=a.depthTexture),i.visible=!1;const d=s.getRenderTarget(),c=s.getMRT(),h=s.autoClear;s.setMRT(null),s.setRenderTarget(a),s.autoClear=!0,s.render(t,o),s.setMRT(c),s.setRenderTarget(d),s.autoClear=h,i.visible=!0,nf=!1}}const uf=new Te(-1,1,1,-1,0,1);class lf extends _e{constructor(e=!1){super();const t=!1===e?[0,-1,0,1,2,1]:[0,2,0,0,2,0];this.setAttribute("position",new ve([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new ve(t,2))}}const df=new lf;class cf extends G{constructor(e=null){super(df,e),this.camera=uf,this.isQuadMesh=!0}async renderAsync(e){return e.renderAsync(this,uf)}render(e){e.render(this,uf)}}const hf=new t;class pf extends Cu{static get type(){return"RTTNode"}constructor(e,t=null,r=null,s={type:be}){const i=new me(t,r,s);super(i.texture,vu()),this.node=e,this.width=t,this.height=r,this.pixelRatio=1,this.renderTarget=i,this.textureNeedsUpdate=!0,this.autoUpdate=!0,this._rttNode=null,this._quadMesh=new cf(new nh),this.updateBeforeType=Rs.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 r=e*this.pixelRatio,s=t*this.pixelRatio;this.renderTarget.setSize(r,s),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(hf);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 Cu(this.value,this.uvNode,this.levelNode);return e.sampler=this.sampler,e.referenceNode=this,e}}const gf=(e,...t)=>Ti(new pf(Ti(e),...t)),mf=Ai((([e,t,r],s)=>{let i;s.renderer.coordinateSystem===l?(e=Ii(e.x,e.y.oneMinus()).mul(2).sub(1),i=$i(Oi(e,t),1)):i=$i(Oi(e.x,e.y.oneMinus(),t).mul(2).sub(1),1);const n=$i(r.mul(i));return n.xyz.div(n.w)})),ff=Ai((([e,t])=>{const r=t.mul($i(e,1)),s=r.xy.div(r.w).mul(.5).add(.5).toVar();return Ii(s.x,s.y.oneMinus())})),yf=Ai((([e,t,r])=>{const s=Su(wu(t)),i=Di(e.mul(s)).toVar(),n=wu(t,i).toVar(),o=wu(t,i.sub(Di(2,0))).toVar(),a=wu(t,i.sub(Di(1,0))).toVar(),u=wu(t,i.add(Di(1,0))).toVar(),l=wu(t,i.add(Di(2,0))).toVar(),d=wu(t,i.add(Di(0,2))).toVar(),c=wu(t,i.add(Di(0,1))).toVar(),h=wu(t,i.sub(Di(0,1))).toVar(),p=wu(t,i.sub(Di(0,2))).toVar(),g=Lo(Hn(Bi(2).mul(a).sub(o),n)).toVar(),m=Lo(Hn(Bi(2).mul(u).sub(l),n)).toVar(),f=Lo(Hn(Bi(2).mul(c).sub(d),n)).toVar(),y=Lo(Hn(Bi(2).mul(h).sub(p),n)).toVar(),b=mf(e,n,r).toVar(),x=g.lessThan(m).select(b.sub(mf(e.sub(Ii(Bi(1).div(s.x),0)),a,r)),b.negate().add(mf(e.add(Ii(Bi(1).div(s.x),0)),u,r))),T=f.lessThan(y).select(b.sub(mf(e.add(Ii(0,Bi(1).div(s.y))),c,r)),b.negate().add(mf(e.sub(Ii(0,Bi(1).div(s.y))),h,r)));return wo(na(x,T))}));class bf extends R{constructor(e,t,r=Float32Array){super(ArrayBuffer.isView(e)?e:new r(e*t),t),this.isStorageInstancedBufferAttribute=!0}}class xf extends Ne{constructor(e,t,r=Float32Array){super(ArrayBuffer.isView(e)?e:new r(e*t),t),this.isStorageBufferAttribute=!0}}class Tf extends Is{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.isPBO&&e.setupPBO(this.node),super.setup(e)}generate(e,t){let r;const s=e.context.assign;if(r=!1===e.isAvailable("storageBuffer")?!0!==this.node.isPBO||!0===s||!this.node.value.isInstancedBufferAttribute&&"compute"===e.shaderStage?this.node.build(e):e.generatePBO(this):super.generate(e),!0!==s){const s=this.getNodeType(e);r=e.format(r,s,t)}return r}}const _f=Ni(Tf);class vf extends wl{static get type(){return"StorageBufferNode"}constructor(e,t=null,r=0){null===t&&(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute)&&(t=fs(e.itemSize),r=e.count),super(e,t,r),this.isStorageBufferNode=!0,this.access=Es.READ_WRITE,this.isAtomic=!1,this.isPBO=!1,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 this.value.isIndirectStorageBufferAttribute?"indirectStorageBuffer":"storageBuffer"}element(e){return _f(this,e)}setPBO(e){return this.isPBO=e,this}getPBO(){return this.isPBO}setAccess(e){return this.access=e,this}toReadOnly(){return this.setAccess(Es.READ_ONLY)}setAtomic(e){return this.isAtomic=e,this}toAtomic(){return this.setAtomic(!0)}getAttributeData(){return null===this._attribute&&(this._attribute=ru(this.value),this._varying=La(this._attribute)),{attribute:this._attribute,varying:this._varying}}getNodeType(e){if(e.isAvailable("storageBuffer")||e.isAvailable("indirectStorageBuffer"))return super.getNodeType(e);const{attribute:t}=this.getAttributeData();return t.getNodeType(e)}generate(e){if(e.isAvailable("storageBuffer")||e.isAvailable("indirectStorageBuffer"))return super.generate(e);const{attribute:t,varying:r}=this.getAttributeData(),s=r.build(e);return e.registerTransform(s,t),s}}const Nf=(e,t=null,r=0)=>Ti(new vf(e,t,r));class Sf extends Tu{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 r;return r=!0===e.hasGeometryAttribute(t)?super.generate(e):e.generateConst(this.nodeType,new s(1,1,1,1)),r}serialize(e){super.serialize(e),e.index=this.index}deserialize(e){super.deserialize(e),this.index=e.index}}class Af extends Ps{static get type(){return"PointUVNode"}constructor(){super("vec2"),this.isPointUVNode=!0}generate(){return"vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )"}}const Rf=Si(Af),Cf=new Ae,Ef=new n;class wf extends Ps{static get type(){return"SceneNode"}constructor(e=wf.BACKGROUND_BLURRINESS,t=null){super(),this.scope=e,this.scene=t}setup(e){const t=this.scope,r=null!==this.scene?this.scene:e.scene;let s;return t===wf.BACKGROUND_BLURRINESS?s=Dl("backgroundBlurriness","float",r):t===wf.BACKGROUND_INTENSITY?s=Dl("backgroundIntensity","float",r):t===wf.BACKGROUND_ROTATION?s=on("mat4").label("backgroundRotation").setGroup(rn).onRenderUpdate((()=>{const e=r.background;return null!==e&&e.isTexture&&e.mapping!==Se?(Cf.copy(r.backgroundRotation),Cf.x*=-1,Cf.y*=-1,Cf.z*=-1,Ef.makeRotationFromEuler(Cf)):Ef.identity(),Ef})):console.error("THREE.SceneNode: Unknown scope:",t),s}}wf.BACKGROUND_BLURRINESS="backgroundBlurriness",wf.BACKGROUND_INTENSITY="backgroundIntensity",wf.BACKGROUND_ROTATION="backgroundRotation";const Mf=Si(wf,wf.BACKGROUND_BLURRINESS),Bf=Si(wf,wf.BACKGROUND_INTENSITY),Uf=Si(wf,wf.BACKGROUND_ROTATION);class Ff extends Cu{static get type(){return"StorageTextureNode"}constructor(e,t,r=null){super(e,t),this.storeNode=r,this.isStorageTextureNode=!0,this.access=Es.WRITE_ONLY}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 r;return r=null!==this.storeNode?this.generateStore(e):super.generate(e,t),r}toReadWrite(){return this.setAccess(Es.READ_WRITE)}toReadOnly(){return this.setAccess(Es.READ_ONLY)}toWriteOnly(){return this.setAccess(Es.WRITE_ONLY)}generateStore(e){const t=e.getNodeProperties(this),{uvNode:r,storeNode:s}=t,i=super.generate(e,"property"),n=r.build(e,"uvec2"),o=s.build(e,"vec4"),a=e.generateTextureStore(e,i,n,o);e.addLineFlowCode(a,this)}}const Pf=Ni(Ff);class If extends Il{static get type(){return"UserDataNode"}constructor(e,t,r=null){super(e,t,r),this.userData=r}updateReference(e){return this.reference=null!==this.userData?this.userData:e.object.userData,this.reference}}const Df=new WeakMap;class Lf extends Ls{static get type(){return"VelocityNode"}constructor(){super("vec2"),this.projectionMatrix=null,this.updateType=Rs.OBJECT,this.updateAfterType=Rs.OBJECT,this.previousModelWorldMatrix=on(new n),this.previousProjectionMatrix=on(new n).setGroup(rn),this.previousCameraViewMatrix=on(new n)}setProjectionMatrix(e){this.projectionMatrix=e}update({frameId:e,camera:t,object:r}){const s=Of(r);this.previousModelWorldMatrix.value.copy(s);const i=Vf(t);i.frameId!==e&&(i.frameId=e,void 0===i.previousProjectionMatrix?(i.previousProjectionMatrix=new n,i.previousCameraViewMatrix=new n,i.currentProjectionMatrix=new n,i.currentCameraViewMatrix=new n,i.previousProjectionMatrix.copy(this.projectionMatrix||t.projectionMatrix),i.previousCameraViewMatrix.copy(t.matrixWorldInverse)):(i.previousProjectionMatrix.copy(i.currentProjectionMatrix),i.previousCameraViewMatrix.copy(i.currentCameraViewMatrix)),i.currentProjectionMatrix.copy(this.projectionMatrix||t.projectionMatrix),i.currentCameraViewMatrix.copy(t.matrixWorldInverse),this.previousProjectionMatrix.value.copy(i.previousProjectionMatrix),this.previousCameraViewMatrix.value.copy(i.previousCameraViewMatrix))}updateAfter({object:e}){Of(e).copy(e.matrixWorld)}setup(){const e=null===this.projectionMatrix?Uu:on(this.projectionMatrix),t=this.previousCameraViewMatrix.mul(this.previousModelWorldMatrix),r=e.mul(Zu).mul(sl),s=this.previousProjectionMatrix.mul(t).mul(il),i=r.xy.div(r.w),n=s.xy.div(s.w);return Hn(i,n)}}function Vf(e){let t=Df.get(e);return void 0===t&&(t={},Df.set(e,t)),t}function Of(e,t=0){const r=Vf(e);let s=r[t];return void 0===s&&(r[t]=s=new n),s}const Gf=Si(Lf),kf=Ai((([e,t])=>Qo(1,e.oneMinus().div(t)).oneMinus())).setLayout({name:"blendBurn",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),zf=Ai((([e,t])=>Qo(e.div(t.oneMinus()),1))).setLayout({name:"blendDodge",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),$f=Ai((([e,t])=>e.oneMinus().mul(t.oneMinus()).oneMinus())).setLayout({name:"blendScreen",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Hf=Ai((([e,t])=>pa(e.mul(2).mul(t),e.oneMinus().mul(2).mul(t.oneMinus()).oneMinus(),ea(.5,e)))).setLayout({name:"blendOverlay",type:"vec3",inputs:[{name:"base",type:"vec3"},{name:"blend",type:"vec3"}]}),Wf=Ai((([e,t])=>{const r=t.a.add(e.a.mul(t.a.oneMinus()));return $i(t.rgb.mul(t.a).add(e.rgb.mul(e.a).mul(t.a.oneMinus())).div(r),r)})).setLayout({name:"blendColor",type:"vec4",inputs:[{name:"base",type:"vec4"},{name:"blend",type:"vec4"}]}),jf=Ai((([e])=>Yf(e.rgb))),qf=Ai((([e,t=Bi(1)])=>t.mix(Yf(e.rgb),e.rgb))),Kf=Ai((([e,t=Bi(1)])=>{const r=$n(e.r,e.g,e.b).div(3),s=e.r.max(e.g.max(e.b)),i=s.sub(r).mul(t).mul(-3);return pa(e.rgb,s,i)})),Xf=Ai((([e,t=Bi(1)])=>{const r=Oi(.57735,.57735,.57735),s=t.cos();return Oi(e.rgb.mul(s).add(r.cross(e.rgb).mul(t.sin()).add(r.mul(ia(r,e.rgb).mul(s.oneMinus())))))})),Yf=(e,t=Oi(d.getLuminanceCoefficients(new r)))=>ia(e,t),Qf=Ai((([e,t=Oi(1),s=Oi(0),i=Oi(1),n=Bi(1),o=Oi(d.getLuminanceCoefficients(new r,Re))])=>{const a=e.rgb.dot(Oi(o)),u=Zo(e.rgb.mul(t).add(s),0).toVar(),l=u.pow(i).toVar();return Ei(u.r.greaterThan(0),(()=>{u.r.assign(l.r)})),Ei(u.g.greaterThan(0),(()=>{u.g.assign(l.g)})),Ei(u.b.greaterThan(0),(()=>{u.b.assign(l.b)})),u.assign(a.add(u.sub(a).mul(n))),$i(u.rgb,e.a)}));class Zf extends Ls{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 Jf=Ni(Zf),ey=new t;class ty extends Cu{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 ry extends ty{static get type(){return"PassMultipleTextureNode"}constructor(e,t,r=!1){super(e,null),this.textureName=t,this.previousTexture=r}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 sy extends Ls{static get type(){return"PassNode"}constructor(e,t,r,s={}){super("vec4"),this.scope=e,this.scene=t,this.camera=r,this.options=s,this._pixelRatio=1,this._width=1,this._height=1;const i=new B;i.isRenderTargetTexture=!0,i.name="depth";const n=new me(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:be,...s});n.texture.name="output",n.depthTexture=i,this.renderTarget=n,this._textures={output:n.texture,depth:i},this._textureNodes={},this._linearDepthNodes={},this._viewZNodes={},this._previousTextures={},this._previousTextureNodes={},this._cameraNear=on(0),this._cameraFar=on(0),this._mrt=null,this.isPassNode=!0,this.updateBeforeType=Rs.FRAME}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.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(),this._previousTextures[e]=t),t}toggleTexture(e){const t=this._previousTextures[e];if(void 0!==t){const r=this._textures[e],s=this.renderTarget.textures.indexOf(r);this.renderTarget.textures[s]=t,this._textures[e]=t,this._previousTextures[e]=r,this._textureNodes[e].updateTexture(),this._previousTextureNodes[e].updateTexture()}}getTextureNode(e="output"){let t=this._textureNodes[e];return void 0===t&&(t=Ti(new ry(this,e)),t.updateTexture(),this._textureNodes[e]=t),t}getPreviousTextureNode(e="output"){let t=this._previousTextureNodes[e];return void 0===t&&(void 0===this._textureNodes[e]&&this.getTextureNode(e),t=Ti(new ry(this,e,!0)),t.updateTexture(),this._previousTextureNodes[e]=t),t}getViewZNode(e="depth"){let t=this._viewZNodes[e];if(void 0===t){const r=this._cameraNear,s=this._cameraFar;this._viewZNodes[e]=t=Kc(this.getTextureNode(e),r,s)}return t}getLinearDepthNode(e="depth"){let t=this._linearDepthNodes[e];if(void 0===t){const r=this._cameraNear,s=this._cameraFar,i=this.getViewZNode(e);this._linearDepthNodes[e]=t=jc(i,r,s)}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.scope===sy.COLOR?this.getTextureNode():this.getLinearDepthNode()}updateBefore(e){const{renderer:t}=e,{scene:r,camera:s}=this;this._pixelRatio=t.getPixelRatio();const i=t.getSize(ey);this.setSize(i.width,i.height);const n=t.getRenderTarget(),o=t.getMRT();this._cameraNear.value=s.near,this._cameraFar.value=s.far;for(const e in this._previousTextures)this.toggleTexture(e);t.setRenderTarget(this.renderTarget),t.setMRT(this._mrt),t.render(r,s),t.setRenderTarget(n),t.setMRT(o)}setSize(e,t){this._width=e,this._height=t;const r=this._width*this._pixelRatio,s=this._height*this._pixelRatio;this.renderTarget.setSize(r,s)}setPixelRatio(e){this._pixelRatio=e,this.setSize(this._width,this._height)}dispose(){this.renderTarget.dispose()}}sy.COLOR="color",sy.DEPTH="depth";class iy extends sy{static get type(){return"ToonOutlinePassNode"}constructor(e,t,r,s,i){super(sy.COLOR,e,t),this.colorNode=r,this.thicknessNode=s,this.alphaNode=i,this._materialCache=new WeakMap}updateBefore(e){const{renderer:t}=e,r=t.getRenderObjectFunction();t.setRenderObjectFunction(((e,r,s,i,n,o,a,u)=>{if((n.isMeshToonMaterial||n.isMeshToonNodeMaterial)&&!1===n.wireframe){const l=this._getOutlineMaterial(n);t.renderObject(e,r,s,i,l,o,a,u)}t.renderObject(e,r,s,i,n,o,a,u)})),super.updateBefore(e),t.setRenderObjectFunction(r)}_createMaterial(){const e=new nh;e.isMeshToonOutlineMaterial=!0,e.name="Toon_Outline",e.side=T;const t=pl.negate(),r=Uu.mul(Zu),s=Bi(1),i=r.mul($i(sl,1)),n=r.mul($i(sl.add(t),1)),o=wo(i.sub(n));return e.vertexNode=i.add(o.mul(this.thicknessNode).mul(i.w).mul(s)),e.colorNode=$i(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 ny=Ai((([e,t])=>e.mul(t).clamp())).setLayout({name:"linearToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),oy=Ai((([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"}]}),ay=Ai((([e,t])=>{const r=(e=(e=e.mul(t)).sub(.004).max(0)).mul(e.mul(6.2).add(.5)),s=e.mul(e.mul(6.2).add(1.7)).add(.06);return r.div(s).pow(2.2)})).setLayout({name:"cineonToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),uy=Ai((([e])=>{const t=e.mul(e.add(.0245786)).sub(90537e-9),r=e.mul(e.add(.432951).mul(.983729)).add(.238081);return t.div(r)})),ly=Ai((([e,t])=>{const r=Ki(.59719,.35458,.04823,.076,.90834,.01566,.0284,.13383,.83777),s=Ki(1.60475,-.53108,-.07367,-.10208,1.10813,-.00605,-.00327,-.07276,1.07602);return e=e.mul(t).div(.6),e=r.mul(e),e=uy(e),(e=s.mul(e)).clamp()})).setLayout({name:"acesFilmicToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),dy=Ki(Oi(1.6605,-.1246,-.0182),Oi(-.5876,1.1329,-.1006),Oi(-.0728,-.0083,1.1187)),cy=Ki(Oi(.6274,.0691,.0164),Oi(.3293,.9195,.088),Oi(.0433,.0113,.8956)),hy=Ai((([e])=>{const t=Oi(e).toVar(),r=Oi(t.mul(t)).toVar(),s=Oi(r.mul(r)).toVar();return Bi(15.5).mul(s.mul(r)).sub(Wn(40.14,s.mul(t))).add(Wn(31.96,s).sub(Wn(6.868,r.mul(t))).add(Wn(.4298,r).add(Wn(.1191,t).sub(.00232))))})),py=Ai((([e,t])=>{const r=Oi(e).toVar(),s=Ki(Oi(.856627153315983,.137318972929847,.11189821299995),Oi(.0951212405381588,.761241990602591,.0767994186031903),Oi(.0482516061458583,.101439036467562,.811302368396859)),i=Ki(Oi(1.1271005818144368,-.1413297634984383,-.14132976349843826),Oi(-.11060664309660323,1.157823702216272,-.11060664309660294),Oi(-.016493938717834573,-.016493938717834257,1.2519364065950405)),n=Bi(-12.47393),o=Bi(4.026069);return r.mulAssign(t),r.assign(cy.mul(r)),r.assign(s.mul(r)),r.assign(Zo(r,1e-10)),r.assign(So(r)),r.assign(r.sub(n).div(o.sub(n))),r.assign(ga(r,0,1)),r.assign(hy(r)),r.assign(i.mul(r)),r.assign(oa(Zo(Oi(0),r),Oi(2.2))),r.assign(dy.mul(r)),r.assign(ga(r,0,1)),r})).setLayout({name:"agxToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]}),gy=Ai((([e,t])=>{const r=Bi(.76),s=Bi(.15);e=e.mul(t);const i=Qo(e.r,Qo(e.g,e.b)),n=Ra(i.lessThan(.08),i.sub(Wn(6.25,i.mul(i))),.04);e.subAssign(n);const o=Zo(e.r,Zo(e.g,e.b));Ei(o.lessThan(r),(()=>e));const a=Hn(1,r),u=Hn(1,a.mul(a).div(o.add(a.sub(r))));e.mulAssign(u.div(o));const l=Hn(1,jn(1,s.mul(o.sub(u)).add(1)));return pa(e,Oi(u),l)})).setLayout({name:"neutralToneMapping",type:"vec3",inputs:[{name:"color",type:"vec3"},{name:"exposure",type:"float"}]});class my extends Ps{static get type(){return"CodeNode"}constructor(e="",t=[],r=""){super("code"),this.isCodeNode=!0,this.code=e,this.includes=t,this.language=r}isGlobal(){return!0}setIncludes(e){return this.includes=e,this}getIncludes(){return this.includes}generate(e){const t=this.getIncludes(e);for(const r of t)r.build(e);const r=e.getCodeFromNode(this,this.getNodeType(e));return r.code=this.code,r.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 fy=Ni(my);class yy extends my{static get type(){return"FunctionNode"}constructor(e="",t=[],r=""){super(e,t,r)}getNodeType(e){return this.getNodeFunction(e).type}getInputs(e){return this.getNodeFunction(e).inputs}getNodeFunction(e){const t=e.getDataFromNode(this);let r=t.nodeFunction;return void 0===r&&(r=e.parser.parseFunction(this.code),t.nodeFunction=r),r}generate(e,t){super.generate(e);const r=this.getNodeFunction(e),s=r.name,i=r.type,n=e.getCodeFromNode(this,i);""!==s&&(n.name=s);const o=e.getPropertyName(n),a=this.getNodeFunction(e).getCode(o);return n.code=a+"\n","property"===t?o:e.format(`${o}()`,i,t)}}const by=(e,t=[],r="")=>{for(let e=0;es.call(...e);return i.functionNode=s,i};class xy extends Ps{static get type(){return"ScriptableValueNode"}constructor(e=null){super(),this._value=e,this._cache=null,this.inputType=null,this.outputType=null,this.events=new o,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:Bi()}serialize(e){super.serialize(e),null!==this.value?"ArrayBuffer"===this.inputType?e.value=vs(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?Ns(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 Ty=Ni(xy);class _y extends Map{get(e,t=null,...r){if(this.has(e))return super.get(e);if(null!==t){const s=t(...r);return this.set(e,s),s}}}class vy{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 Ny=new _y;class Sy extends Ps{static get type(){return"ScriptableNode"}constructor(e=null,t={}){super(),this.codeNode=e,this.parameters=t,this._local=new _y,this._output=Ty(),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 r=this._outputs;return void 0===r[e]?r[e]=Ty(t):r[e].value=t,this}getOutput(e){return this._outputs[e]}getParameter(e){return this.parameters[e]}setParameter(e,t){const r=this.parameters;return t&&t.isScriptableNode?(this.deleteParameter(e),r[e]=t,r[e].getDefaultOutput().events.addEventListener("refresh",this.onRefresh)):t&&t.isScriptableValueNode?(this.deleteParameter(e),r[e]=t,r[e].events.addEventListener("refresh",this.onRefresh)):void 0===r[e]?(r[e]=Ty(t),r[e].events.addEventListener("refresh",this.onRefresh)):r[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 r=this.getObject()[e];if("function"==typeof r)return r(...t)}async callAsync(e,...t){const r=this.getObject()[e];if("function"==typeof r)return"AsyncFunction"===r.constructor.name?await r(...t):r(...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 vy(this),t=Ny.get("THREE"),r=Ny.get("TSL"),s=this.getMethod(),i=[e,this._local,Ny,()=>this.refresh(),(e,t)=>this.setOutput(e,t),t,r];this._object=s(...i);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:Bi()}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+" };",r="var "+e+"; var output = {};\n"+this.codeNode.code+t;return this._method=new Function(...["parameters","local","global","refresh","setOutput","THREE","TSL"],r),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=[ls(this.source),this.getDefaultOutputNode().getCacheKey(e)];for(const r in this.parameters)t.push(this.parameters[r].getCacheKey(e));return ds(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 Ay=Ni(Sy);function Ry(e){let t;const r=e.context.getViewZ;return void 0!==r&&(t=r(this)),(t||al.z).negate()}const Cy=Ai((([e,t],r)=>{const s=Ry(r);return ya(e,t,s)})),Ey=Ai((([e],t)=>{const r=Ry(t);return e.mul(e,r,r).negate().exp().oneMinus()})),wy=Ai((([e,t])=>$i(t.toFloat().mix(En.rgb,e.toVec3()),En.a)));let My=null,By=null;class Uy extends Ps{static get type(){return"RangeNode"}constructor(e=Bi(),t=Bi()){super(),this.minNode=e,this.maxNode=t}getVectorLength(e){const t=e.getTypeLength(xs(this.minNode.value)),r=e.getTypeLength(xs(this.maxNode.value));return t>r?t:r}getNodeType(e){return e.object.count>1?e.getTypeFromLength(this.getVectorLength(e)):"float"}setup(e){const t=e.object;let r=null;if(t.count>1){const i=this.minNode.value,n=this.maxNode.value,o=e.getTypeLength(xs(i)),u=e.getTypeLength(xs(n));My=My||new s,By=By||new s,My.setScalar(0),By.setScalar(0),1===o?My.setScalar(i):i.isColor?My.set(i.r,i.g,i.b,1):My.set(i.x,i.y,i.z||0,i.w||0),1===u?By.setScalar(n):n.isColor?By.set(n.r,n.g,n.b,1):By.set(n.x,n.y,n.z||0,n.w||0);const l=4,d=l*t.count,c=new Float32Array(d);for(let e=0;eTi(new Py(e,t)),Dy=Iy("numWorkgroups","uvec3"),Ly=Iy("workgroupId","uvec3"),Vy=Iy("globalId","uvec3"),Oy=Iy("localId","uvec3"),Gy=Iy("subgroupSize","uint");const ky=Ni(class extends Ps{constructor(e){super(),this.scope=e}generate(e){const{scope:t}=this,{renderer:r}=e;!0===r.backend.isWebGLBackend?e.addFlowCode(`\t// ${t}Barrier \n`):e.addLineFlowCode(`${t}Barrier()`,this)}});class zy extends Is{constructor(e,t){super(e,t),this.isWorkgroupInfoElementNode=!0}generate(e,t){let r;const s=e.context.assign;if(r=super.generate(e),!0!==s){const s=this.getNodeType(e);r=e.format(r,s,t)}return r}}class $y extends Ps{constructor(e,t,r=0){super(t),this.bufferType=t,this.bufferCount=r,this.isWorkgroupInfoNode=!0,this.elementType=t,this.scope=e}label(e){return this.name=e,this}setScope(e){return this.scope=e,this}getElementType(){return this.elementType}getInputType(){return`${this.scope}Array`}element(e){return Ti(new zy(this,e))}generate(e){return e.getScopedArray(this.name||`${this.scope}Array_${this.id}`,this.scope.toLowerCase(),this.bufferType,this.bufferCount)}}class Hy extends Ls{static get type(){return"AtomicFunctionNode"}constructor(e,t,r,s=null){super("uint"),this.method=e,this.pointerNode=t,this.valueNode=r,this.storeNode=s}getInputType(e){return this.pointerNode.getNodeType(e)}getNodeType(e){return this.getInputType(e)}generate(e){const t=this.method,r=this.getNodeType(e),s=this.getInputType(e),i=this.pointerNode,n=this.valueNode,o=[];o.push(`&${i.build(e,s)}`),o.push(n.build(e,s));const a=`${e.getMethod(t,r)}( ${o.join(", ")} )`;if(null!==this.storeNode){const t=this.storeNode.build(e,s);e.addLineFlowCode(`${t} = ${a}`,this)}else e.addLineFlowCode(a,this)}}Hy.ATOMIC_LOAD="atomicLoad",Hy.ATOMIC_STORE="atomicStore",Hy.ATOMIC_ADD="atomicAdd",Hy.ATOMIC_SUB="atomicSub",Hy.ATOMIC_MAX="atomicMax",Hy.ATOMIC_MIN="atomicMin",Hy.ATOMIC_AND="atomicAnd",Hy.ATOMIC_OR="atomicOr",Hy.ATOMIC_XOR="atomicXor";const Wy=Ni(Hy),jy=(e,t,r,s=null)=>{const i=Wy(e,t,r,s);return i.append(),i};let qy;function Ky(e){qy=qy||new WeakMap;let t=qy.get(e);return void 0===t&&qy.set(e,t={}),t}function Xy(e){const t=Ky(e);return t.shadowMatrix||(t.shadowMatrix=on("mat4").setGroup(rn).onRenderUpdate((()=>(!0!==e.castShadow&&e.shadow.updateMatrices(e),e.shadow.matrix))))}function Yy(e){const t=Ky(e);if(void 0===t.projectionUV){const r=Xy(e).mul(nl);t.projectionUV=r.xyz.div(r.w)}return t.projectionUV}function Qy(e){const t=Ky(e);return t.position||(t.position=on(new r).setGroup(rn).onRenderUpdate(((t,r)=>r.value.setFromMatrixPosition(e.matrixWorld))))}function Zy(e){const t=Ky(e);return t.targetPosition||(t.targetPosition=on(new r).setGroup(rn).onRenderUpdate(((t,r)=>r.value.setFromMatrixPosition(e.target.matrixWorld))))}function Jy(e){const t=Ky(e);return t.viewPosition||(t.viewPosition=on(new r).setGroup(rn).onRenderUpdate((({camera:t},s)=>{s.value=s.value||new r,s.value.setFromMatrixPosition(e.matrixWorld),s.value.applyMatrix4(t.matrixWorldInverse)})))}const eb=e=>Pu.transformDirection(Qy(e).sub(Zy(e))),tb=(e,t)=>{for(const r of t)if(r.isAnalyticLightNode&&r.light.id===e)return r;return null},rb=new WeakMap;class sb extends Ps{static get type(){return"LightsNode"}constructor(){super("vec3"),this.totalDiffuseNode=Oi().toVar("totalDiffuse"),this.totalSpecularNode=Oi().toVar("totalSpecular"),this.outgoingLightNode=Oi().toVar("outgoingLight"),this._lights=[],this._lightNodes=null,this._lightNodesHash=null,this.global=!0}customCacheKey(){const e=[],t=this._lights;for(let r=0;re.sort(((e,t)=>e.id-t.id)))(this._lights),i=e.renderer.library;for(const e of s)if(e.isNode)t.push(Ti(e));else{let s=null;if(null!==r&&(s=tb(e.id,r)),null===s){const r=i.getLightNodeClass(e.constructor);if(null===r){console.warn(`LightsNode.setupNodeLights: Light node not found for ${e.constructor.name}`);continue}let s=null;rb.has(e)?s=rb.get(e):(s=Ti(new r(e)),rb.set(e,s)),t.push(s)}}this._lightNodes=t}setupLights(e,t){for(const r of t)r.build(e)}setup(e){null===this._lightNodes&&this.setupLightsNode(e);const t=e.context,r=t.lightingModel;let s=this.outgoingLightNode;if(r){const{_lightNodes:i,totalDiffuseNode:n,totalSpecularNode:o}=this;t.outgoingLight=s;const a=e.addStack();e.getDataFromNode(this).nodes=a.nodes,r.start(t,a,e),this.setupLights(e,i),r.indirect(t,a,e);const{backdrop:u,backdropAlpha:l}=t,{directDiffuse:d,directSpecular:c,indirectDiffuse:h,indirectSpecular:p}=t.reflectedLight;let g=d.add(h);null!==u&&(g=Oi(null!==l?l.mix(g,u):u),t.material.transparent=!0),n.assign(g),o.assign(c.add(p)),s.assign(n.add(o)),r.finish(t,a,e),s=s.bypass(e.removeStack())}return s}setLights(e){return this._lights=e,this._lightNodes=null,this._lightNodesHash=null,this}getLights(){return this._lights}get hasLights(){return this._lights.length>0}}class ib extends Ps{static get type(){return"ShadowBaseNode"}constructor(e){super(),this.light=e,this.updateBeforeType=Rs.RENDER,this.isShadowBaseNode=!0}setupShadowPosition({material:e}){nb.assign(e.shadowPositionNode||nl)}dispose(){this.updateBeforeType=Rs.NONE}}const nb=Oi().toVar("shadowPositionWorld");function ob(t,r={}){return r.toneMapping=t.toneMapping,r.toneMappingExposure=t.toneMappingExposure,r.outputColorSpace=t.outputColorSpace,r.renderTarget=t.getRenderTarget(),r.activeCubeFace=t.getActiveCubeFace(),r.activeMipmapLevel=t.getActiveMipmapLevel(),r.renderObjectFunction=t.getRenderObjectFunction(),r.pixelRatio=t.getPixelRatio(),r.mrt=t.getMRT(),r.clearColor=t.getClearColor(r.clearColor||new e),r.clearAlpha=t.getClearAlpha(),r.autoClear=t.autoClear,r.scissorTest=t.getScissorTest(),r}function ab(e,t){return t=ob(e,t),e.setMRT(null),e.setRenderObjectFunction(null),e.setClearColor(0,1),e.autoClear=!0,t}function ub(e,t){e.toneMapping=t.toneMapping,e.toneMappingExposure=t.toneMappingExposure,e.outputColorSpace=t.outputColorSpace,e.setRenderTarget(t.renderTarget,t.activeCubeFace,t.activeMipmapLevel),e.setRenderObjectFunction(t.renderObjectFunction),e.setPixelRatio(t.pixelRatio),e.setMRT(t.mrt),e.setClearColor(t.clearColor,t.clearAlpha),e.autoClear=t.autoClear,e.setScissorTest(t.scissorTest)}function lb(e,t={}){return t.background=e.background,t.backgroundNode=e.backgroundNode,t.overrideMaterial=e.overrideMaterial,t}function db(e,t){return t=lb(e,t),e.background=null,e.backgroundNode=null,e.overrideMaterial=null,t}function cb(e,t){e.background=t.background,e.backgroundNode=t.backgroundNode,e.overrideMaterial=t.overrideMaterial}function hb(e,t,r){return r=db(t,r=ab(e,r))}function pb(e,t,r){ub(e,r),cb(t,r)}var gb=Object.freeze({__proto__:null,resetRendererAndSceneState:hb,resetRendererState:ab,resetSceneState:db,restoreRendererAndSceneState:pb,restoreRendererState:ub,restoreSceneState:cb,saveRendererAndSceneState:function(e,t,r={}){return r=lb(t,r=ob(e,r))},saveRendererState:ob,saveSceneState:lb});const mb=new WeakMap,fb=Ai((([e,t,r])=>{let s=nl.sub(e).length();return s=s.sub(t).div(r.sub(t)),s=s.saturate(),s})),yb=e=>{let t=mb.get(e);if(void 0===t){const r=e.isPointLight?(e=>{const t=e.shadow.camera,r=Dl("near","float",t).setGroup(rn),s=Dl("far","float",t).setGroup(rn),i=ku(e);return fb(i,r,s)})(e):null;t=new nh,t.colorNode=$i(0,0,0,1),t.depthNode=r,t.isShadowPassMaterial=!0,t.name="ShadowMaterial",t.fog=!1,mb.set(e,t)}return t},bb=Ai((({depthTexture:e,shadowCoord:t})=>Eu(e,t.xy).compare(t.z))),xb=Ai((({depthTexture:e,shadowCoord:t,shadow:r})=>{const s=(t,r)=>Eu(e,t).compare(r),i=Dl("mapSize","vec2",r).setGroup(rn),n=Dl("radius","float",r).setGroup(rn),o=Ii(1).div(i),a=o.x.negate().mul(n),u=o.y.negate().mul(n),l=o.x.mul(n),d=o.y.mul(n),c=a.div(2),h=u.div(2),p=l.div(2),g=d.div(2);return $n(s(t.xy.add(Ii(a,u)),t.z),s(t.xy.add(Ii(0,u)),t.z),s(t.xy.add(Ii(l,u)),t.z),s(t.xy.add(Ii(c,h)),t.z),s(t.xy.add(Ii(0,h)),t.z),s(t.xy.add(Ii(p,h)),t.z),s(t.xy.add(Ii(a,0)),t.z),s(t.xy.add(Ii(c,0)),t.z),s(t.xy,t.z),s(t.xy.add(Ii(p,0)),t.z),s(t.xy.add(Ii(l,0)),t.z),s(t.xy.add(Ii(c,g)),t.z),s(t.xy.add(Ii(0,g)),t.z),s(t.xy.add(Ii(p,g)),t.z),s(t.xy.add(Ii(a,d)),t.z),s(t.xy.add(Ii(0,d)),t.z),s(t.xy.add(Ii(l,d)),t.z)).mul(1/17)})),Tb=Ai((({depthTexture:e,shadowCoord:t,shadow:r})=>{const s=(t,r)=>Eu(e,t).compare(r),i=Dl("mapSize","vec2",r).setGroup(rn),n=Ii(1).div(i),o=n.x,a=n.y,u=t.xy,l=Mo(u.mul(i).add(.5));return u.subAssign(l.mul(n)),$n(s(u,t.z),s(u.add(Ii(o,0)),t.z),s(u.add(Ii(0,a)),t.z),s(u.add(n),t.z),pa(s(u.add(Ii(o.negate(),0)),t.z),s(u.add(Ii(o.mul(2),0)),t.z),l.x),pa(s(u.add(Ii(o.negate(),a)),t.z),s(u.add(Ii(o.mul(2),a)),t.z),l.x),pa(s(u.add(Ii(0,a.negate())),t.z),s(u.add(Ii(0,a.mul(2))),t.z),l.y),pa(s(u.add(Ii(o,a.negate())),t.z),s(u.add(Ii(o,a.mul(2))),t.z),l.y),pa(pa(s(u.add(Ii(o.negate(),a.negate())),t.z),s(u.add(Ii(o.mul(2),a.negate())),t.z),l.x),pa(s(u.add(Ii(o.negate(),a.mul(2))),t.z),s(u.add(Ii(o.mul(2),a.mul(2))),t.z),l.x),l.y)).mul(1/9)})),_b=Ai((({depthTexture:e,shadowCoord:t})=>{const r=Bi(1).toVar(),s=Eu(e).sample(t.xy).rg,i=ea(t.z,s.x);return Ei(i.notEqual(Bi(1)),(()=>{const e=t.z.sub(s.x),n=Zo(0,s.y.mul(s.y));let o=n.div(n.add(e.mul(e)));o=ga(Hn(o,.3).div(.95-.3)),r.assign(ga(Zo(i,o)))})),r})),vb=Ai((({samples:e,radius:t,size:r,shadowPass:s})=>{const i=Bi(0).toVar(),n=Bi(0).toVar(),o=e.lessThanEqual(Bi(1)).select(Bi(0),Bi(2).div(e.sub(1))),a=e.lessThanEqual(Bi(1)).select(Bi(0),Bi(-1));pc({start:Ui(0),end:Ui(e),type:"int",condition:"<"},(({i:e})=>{const u=a.add(Bi(e).mul(o)),l=s.sample($n(Mc.xy,Ii(0,u).mul(t)).div(r)).x;i.addAssign(l),n.addAssign(l.mul(l))})),i.divAssign(e),n.divAssign(e);const u=Ao(n.sub(i.mul(i)));return Ii(i,u)})),Nb=Ai((({samples:e,radius:t,size:r,shadowPass:s})=>{const i=Bi(0).toVar(),n=Bi(0).toVar(),o=e.lessThanEqual(Bi(1)).select(Bi(0),Bi(2).div(e.sub(1))),a=e.lessThanEqual(Bi(1)).select(Bi(0),Bi(-1));pc({start:Ui(0),end:Ui(e),type:"int",condition:"<"},(({i:e})=>{const u=a.add(Bi(e).mul(o)),l=s.sample($n(Mc.xy,Ii(u,0).mul(t)).div(r));i.addAssign(l.x),n.addAssign($n(l.y.mul(l.y),l.x.mul(l.x)))})),i.divAssign(e),n.divAssign(e);const u=Ao(n.sub(i.mul(i)));return Ii(i,u)})),Sb=[bb,xb,Tb,_b];let Ab;const Rb=new cf;class Cb extends ib{static get type(){return"ShadowNode"}constructor(e,t=null){super(e),this.shadow=t||e.shadow,this.shadowMap=null,this.vsmShadowMapVertical=null,this.vsmShadowMapHorizontal=null,this.vsmMaterialVertical=null,this.vsmMaterialHorizontal=null,this._node=null,this.isShadowNode=!0}setupShadowFilter(e,{filterFn:t,depthTexture:r,shadowCoord:s,shadow:i}){const n=s.x.greaterThanEqual(0).and(s.x.lessThanEqual(1)).and(s.y.greaterThanEqual(0)).and(s.y.lessThanEqual(1)).and(s.z.lessThanEqual(1)),o=t({depthTexture:r,shadowCoord:s,shadow:i});return n.select(o,Bi(1))}setupShadowCoord(e,t){const{shadow:r}=this,{renderer:s}=e,i=Dl("bias","float",r).setGroup(rn);let n,o=t;if(r.camera.isOrthographicCamera||!0!==s.logarithmicDepthBuffer)o=o.xyz.div(o.w),n=o.z,s.coordinateSystem===l&&(n=n.mul(2).sub(1));else{const e=o.w;o=o.xy.div(e);const t=Dl("near","float",r.camera).setGroup(rn),s=Dl("far","float",r.camera).setGroup(rn);n=Xc(e.negate(),t,s)}return o=Oi(o.x,o.y.oneMinus(),n.add(i)),o}getShadowFilterFn(e){return Sb[e]}setupShadow(e){const{renderer:t}=e,{light:r,shadow:s}=this,i=t.shadowMap.type,n=new B(s.mapSize.width,s.mapSize.height);n.compareFunction=Ce;const o=e.createRenderTarget(s.mapSize.width,s.mapSize.height);if(o.depthTexture=n,s.camera.updateProjectionMatrix(),i===Ee){n.compareFunction=null,this.vsmShadowMapVertical=e.createRenderTarget(s.mapSize.width,s.mapSize.height,{format:we,type:be}),this.vsmShadowMapHorizontal=e.createRenderTarget(s.mapSize.width,s.mapSize.height,{format:we,type:be});const t=Eu(n),r=Eu(this.vsmShadowMapVertical.texture),i=Dl("blurSamples","float",s).setGroup(rn),o=Dl("radius","float",s).setGroup(rn),a=Dl("mapSize","vec2",s).setGroup(rn);let u=this.vsmMaterialVertical||(this.vsmMaterialVertical=new nh);u.fragmentNode=vb({samples:i,radius:o,size:a,shadowPass:t}).context(e.getSharedContext()),u.name="VSMVertical",u=this.vsmMaterialHorizontal||(this.vsmMaterialHorizontal=new nh),u.fragmentNode=Nb({samples:i,radius:o,size:a,shadowPass:r}).context(e.getSharedContext()),u.name="VSMHorizontal"}const a=Dl("intensity","float",s).setGroup(rn),u=Dl("normalBias","float",s).setGroup(rn),l=Xy(r).mul(nb.add(bl.mul(u))),d=this.setupShadowCoord(e,l),c=s.filterNode||this.getShadowFilterFn(t.shadowMap.type)||null;if(null===c)throw new Error("THREE.WebGPURenderer: Shadow map type not supported yet.");const h=i===Ee?this.vsmShadowMapHorizontal.texture:n,p=this.setupShadowFilter(e,{filterFn:c,shadowTexture:o.texture,depthTexture:h,shadowCoord:d,shadow:s}),g=Eu(o.texture,d),m=pa(1,p.rgb.mix(g,1),a.mul(g.a)).toVar();return this.shadowMap=o,this.shadow.map=o,m}setup(e){if(!1!==e.renderer.shadowMap.enabled)return Ai((()=>{let t=this._node;return this.setupShadowPosition(e),null===t&&(this._node=t=this.setupShadow(e)),e.material.shadowNode&&console.warn('THREE.NodeMaterial: ".shadowNode" is deprecated. Use ".castShadowNode" instead.'),e.material.receivedShadowNode&&(t=e.material.receivedShadowNode(t)),t}))()}renderShadow(e){const{shadow:t,shadowMap:r,light:s}=this,{renderer:i,scene:n}=e;t.updateMatrices(s),r.setSize(t.mapSize.width,t.mapSize.height),i.render(n,t.camera)}updateShadow(e){const{shadowMap:t,light:r,shadow:s}=this,{renderer:i,scene:n,camera:o}=e,a=i.shadowMap.type,u=t.depthTexture.version;this._depthVersionCached=u,s.camera.layers.mask=o.layers.mask;const l=i.getRenderObjectFunction(),d=i.getMRT(),c=!!d&&d.has("velocity");Ab=hb(i,n,Ab),n.overrideMaterial=yb(r),i.setRenderObjectFunction(((e,t,r,n,u,l,...d)=>{(!0===e.castShadow||e.receiveShadow&&a===Ee)&&(c&&(_s(e).useVelocity=!0),e.onBeforeShadow(i,e,o,s.camera,n,t.overrideMaterial,l),i.renderObject(e,t,r,n,u,l,...d),e.onAfterShadow(i,e,o,s.camera,n,t.overrideMaterial,l))})),i.setRenderTarget(t),this.renderShadow(e),i.setRenderObjectFunction(l),!0!==r.isPointLight&&a===Ee&&this.vsmPass(i),pb(i,n,Ab)}vsmPass(e){const{shadow:t}=this;this.vsmShadowMapVertical.setSize(t.mapSize.width,t.mapSize.height),this.vsmShadowMapHorizontal.setSize(t.mapSize.width,t.mapSize.height),e.setRenderTarget(this.vsmShadowMapVertical),Rb.material=this.vsmMaterialVertical,Rb.render(e),e.setRenderTarget(this.vsmShadowMapHorizontal),Rb.material=this.vsmMaterialHorizontal,Rb.render(e)}dispose(){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),super.dispose()}updateBefore(e){const{shadow:t}=this;(t.needsUpdate||t.autoUpdate)&&(this.updateShadow(e),this.shadowMap.depthTexture.version===this._depthVersionCached&&(t.needsUpdate=!1))}}const Eb=(e,t)=>Ti(new Cb(e,t));class wb extends Tc{static get type(){return"AnalyticLightNode"}constructor(t=null){super(),this.light=t,this.color=new e,this.colorNode=t&&t.colorNode||on(this.color).setGroup(rn),this.baseColorNode=null,this.shadowNode=null,this.shadowColorNode=null,this.isAnalyticLightNode=!0,this.updateType=Rs.FRAME}customCacheKey(){return cs(this.light.id,this.light.castShadow?1:0)}getHash(){return this.light.uuid}setupShadowNode(){return Eb(this.light)}setupShadow(e){const{renderer:t}=e;if(!1===t.shadowMap.enabled)return;let r=this.shadowColorNode;if(null===r){const t=this.light.shadow.shadowNode;let s;s=void 0!==t?Ti(t):this.setupShadowNode(e),this.shadowNode=s,this.shadowColorNode=r=this.colorNode.mul(s),this.baseColorNode=this.colorNode}this.colorNode=r}setup(e){this.colorNode=this.baseColorNode||this.colorNode,this.light.castShadow?e.object.receiveShadow&&this.setupShadow(e):null!==this.shadowNode&&(this.shadowNode.dispose(),this.shadowNode=null,this.shadowColorNode=null)}update(){const{light:e}=this;this.color.copy(e.color).multiplyScalar(e.intensity)}}const Mb=Ai((e=>{const{lightDistance:t,cutoffDistance:r,decayExponent:s}=e,i=t.pow(s).max(.01).reciprocal();return r.greaterThan(0).select(i.mul(t.div(r).pow4().oneMinus().clamp().pow2()),i)})),Bb=new e,Ub=Ai((([e,t])=>{const r=e.toVar(),s=Lo(r),i=jn(1,Zo(s.x,Zo(s.y,s.z)));s.mulAssign(i),r.mulAssign(i.mul(t.mul(2).oneMinus()));const n=Ii(r.xy).toVar(),o=t.mul(1.5).oneMinus();return Ei(s.z.greaterThanEqual(o),(()=>{Ei(r.z.greaterThan(0),(()=>{n.x.assign(Hn(4,r.x))}))})).ElseIf(s.x.greaterThanEqual(o),(()=>{const e=Vo(r.x);n.x.assign(r.z.mul(e).add(e.mul(2)))})).ElseIf(s.y.greaterThanEqual(o),(()=>{const e=Vo(r.y);n.x.assign(r.x.add(e.mul(2)).add(2)),n.y.assign(r.z.mul(e).sub(2))})),Ii(.125,.25).mul(n).add(Ii(.375,.75)).flipY()})).setLayout({name:"cubeToUV",type:"vec2",inputs:[{name:"pos",type:"vec3"},{name:"texelSizeY",type:"float"}]}),Fb=Ai((({depthTexture:e,bd3D:t,dp:r,texelSize:s})=>Eu(e,Ub(t,s.y)).compare(r))),Pb=Ai((({depthTexture:e,bd3D:t,dp:r,texelSize:s,shadow:i})=>{const n=Dl("radius","float",i).setGroup(rn),o=Ii(-1,1).mul(n).mul(s.y);return Eu(e,Ub(t.add(o.xyy),s.y)).compare(r).add(Eu(e,Ub(t.add(o.yyy),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.xyx),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.yyx),s.y)).compare(r)).add(Eu(e,Ub(t,s.y)).compare(r)).add(Eu(e,Ub(t.add(o.xxy),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.yxy),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.xxx),s.y)).compare(r)).add(Eu(e,Ub(t.add(o.yxx),s.y)).compare(r)).mul(1/9)})),Ib=Ai((({filterFn:e,depthTexture:t,shadowCoord:r,shadow:s})=>{const i=r.xyz.toVar(),n=i.length(),o=on("float").setGroup(rn).onRenderUpdate((()=>s.camera.near)),a=on("float").setGroup(rn).onRenderUpdate((()=>s.camera.far)),u=Dl("bias","float",s).setGroup(rn),l=on(s.mapSize).setGroup(rn),d=Bi(1).toVar();return Ei(n.sub(a).lessThanEqual(0).and(n.sub(o).greaterThanEqual(0)),(()=>{const r=n.sub(o).div(a.sub(o)).toVar();r.addAssign(u);const c=i.normalize(),h=Ii(1).div(l.mul(Ii(4,2)));d.assign(e({depthTexture:t,bd3D:c,dp:r,texelSize:h,shadow:s}))})),d})),Db=new s,Lb=new t,Vb=new t;class Ob extends Cb{static get type(){return"PointShadowNode"}constructor(e,t=null){super(e,t)}getShadowFilterFn(e){return e===Me?Fb:Pb}setupShadowCoord(e,t){return t}setupShadowFilter(e,{filterFn:t,shadowTexture:r,depthTexture:s,shadowCoord:i,shadow:n}){return Ib({filterFn:t,shadowTexture:r,depthTexture:s,shadowCoord:i,shadow:n})}renderShadow(e){const{shadow:t,shadowMap:r,light:s}=this,{renderer:i,scene:n}=e,o=t.getFrameExtents();Vb.copy(t.mapSize),Vb.multiply(o),r.setSize(Vb.width,Vb.height),Lb.copy(t.mapSize);const a=i.autoClear,u=i.getClearColor(Bb),l=i.getClearAlpha();i.autoClear=!1,i.setClearColor(t.clearColor,t.clearAlpha),i.clear();const d=t.getViewportCount();for(let e=0;e{const n=i.context.lightingModel,o=t.sub(al),a=o.normalize(),u=o.length(),l=Mb({lightDistance:u,cutoffDistance:r,decayExponent:s}),d=e.mul(l),c=i.context.reflectedLight;n.direct({lightDirection:a,lightColor:d,reflectedLight:c},i.stack,i)}));class kb extends wb{static get type(){return"PointLightNode"}constructor(e=null){super(e),this.cutoffDistanceNode=on(0).setGroup(rn),this.decayExponentNode=on(2).setGroup(rn)}update(e){const{light:t}=this;super.update(e),this.cutoffDistanceNode.value=t.distance,this.decayExponentNode.value=t.decay}setupShadowNode(){return((e,t)=>Ti(new Ob(e,t)))(this.light)}setup(e){super.setup(e),Gb({color:this.colorNode,lightViewPosition:Jy(this.light),cutoffDistance:this.cutoffDistanceNode,decayExponent:this.decayExponentNode}).append()}}const zb=Ai((([e=t()])=>{const t=e.mul(2),r=t.x.floor(),s=t.y.floor();return r.add(s).mod(2).sign()})),$b=Ai((([e=vu()],{renderer:t,material:r})=>{const s=Bi(1).toVar(),i=ha(e.mul(2).sub(1));if(r.alphaToCoverage&&t.samples>1){const e=Bi(i.fwidth()).toVar();s.assign(ya(e.oneMinus(),e.add(1),i).oneMinus())}else i.greaterThan(1).discard();return s})),Hb=Ai((([e,t,r])=>{const s=Bi(r).toVar(),i=Bi(t).toVar(),n=Pi(e).toVar();return Ra(n,i,s)})).setLayout({name:"mx_select",type:"float",inputs:[{name:"b",type:"bool"},{name:"t",type:"float"},{name:"f",type:"float"}]}),Wb=Ai((([e,t])=>{const r=Pi(t).toVar(),s=Bi(e).toVar();return Ra(r,s.negate(),s)})).setLayout({name:"mx_negate_if",type:"float",inputs:[{name:"val",type:"float"},{name:"b",type:"bool"}]}),jb=Ai((([e])=>{const t=Bi(e).toVar();return Ui(Co(t))})).setLayout({name:"mx_floor",type:"int",inputs:[{name:"x",type:"float"}]}),qb=Ai((([e,t])=>{const r=Bi(e).toVar();return t.assign(jb(r)),r.sub(Bi(t))})),Kb=Fm([Ai((([e,t,r,s,i,n])=>{const o=Bi(n).toVar(),a=Bi(i).toVar(),u=Bi(s).toVar(),l=Bi(r).toVar(),d=Bi(t).toVar(),c=Bi(e).toVar(),h=Bi(Hn(1,a)).toVar();return Hn(1,o).mul(c.mul(h).add(d.mul(a))).add(o.mul(l.mul(h).add(u.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"}]}),Ai((([e,t,r,s,i,n])=>{const o=Bi(n).toVar(),a=Bi(i).toVar(),u=Oi(s).toVar(),l=Oi(r).toVar(),d=Oi(t).toVar(),c=Oi(e).toVar(),h=Bi(Hn(1,a)).toVar();return Hn(1,o).mul(c.mul(h).add(d.mul(a))).add(o.mul(l.mul(h).add(u.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"}]})]),Xb=Fm([Ai((([e,t,r,s,i,n,o,a,u,l,d])=>{const c=Bi(d).toVar(),h=Bi(l).toVar(),p=Bi(u).toVar(),g=Bi(a).toVar(),m=Bi(o).toVar(),f=Bi(n).toVar(),y=Bi(i).toVar(),b=Bi(s).toVar(),x=Bi(r).toVar(),T=Bi(t).toVar(),_=Bi(e).toVar(),v=Bi(Hn(1,p)).toVar(),N=Bi(Hn(1,h)).toVar();return Bi(Hn(1,c)).toVar().mul(N.mul(_.mul(v).add(T.mul(p))).add(h.mul(x.mul(v).add(b.mul(p))))).add(c.mul(N.mul(y.mul(v).add(f.mul(p))).add(h.mul(m.mul(v).add(g.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"}]}),Ai((([e,t,r,s,i,n,o,a,u,l,d])=>{const c=Bi(d).toVar(),h=Bi(l).toVar(),p=Bi(u).toVar(),g=Oi(a).toVar(),m=Oi(o).toVar(),f=Oi(n).toVar(),y=Oi(i).toVar(),b=Oi(s).toVar(),x=Oi(r).toVar(),T=Oi(t).toVar(),_=Oi(e).toVar(),v=Bi(Hn(1,p)).toVar(),N=Bi(Hn(1,h)).toVar();return Bi(Hn(1,c)).toVar().mul(N.mul(_.mul(v).add(T.mul(p))).add(h.mul(x.mul(v).add(b.mul(p))))).add(c.mul(N.mul(y.mul(v).add(f.mul(p))).add(h.mul(m.mul(v).add(g.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"}]})]),Yb=Ai((([e,t,r])=>{const s=Bi(r).toVar(),i=Bi(t).toVar(),n=Fi(e).toVar(),o=Fi(n.bitAnd(Fi(7))).toVar(),a=Bi(Hb(o.lessThan(Fi(4)),i,s)).toVar(),u=Bi(Wn(2,Hb(o.lessThan(Fi(4)),s,i))).toVar();return Wb(a,Pi(o.bitAnd(Fi(1)))).add(Wb(u,Pi(o.bitAnd(Fi(2)))))})).setLayout({name:"mx_gradient_float_0",type:"float",inputs:[{name:"hash",type:"uint"},{name:"x",type:"float"},{name:"y",type:"float"}]}),Qb=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Bi(t).toVar(),a=Fi(e).toVar(),u=Fi(a.bitAnd(Fi(15))).toVar(),l=Bi(Hb(u.lessThan(Fi(8)),o,n)).toVar(),d=Bi(Hb(u.lessThan(Fi(4)),n,Hb(u.equal(Fi(12)).or(u.equal(Fi(14))),o,i))).toVar();return Wb(l,Pi(u.bitAnd(Fi(1)))).add(Wb(d,Pi(u.bitAnd(Fi(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"}]}),Zb=Fm([Yb,Qb]),Jb=Ai((([e,t,r])=>{const s=Bi(r).toVar(),i=Bi(t).toVar(),n=ki(e).toVar();return Oi(Zb(n.x,i,s),Zb(n.y,i,s),Zb(n.z,i,s))})).setLayout({name:"mx_gradient_vec3_0",type:"vec3",inputs:[{name:"hash",type:"uvec3"},{name:"x",type:"float"},{name:"y",type:"float"}]}),ex=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Bi(t).toVar(),a=ki(e).toVar();return Oi(Zb(a.x,o,n,i),Zb(a.y,o,n,i),Zb(a.z,o,n,i))})).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"}]}),tx=Fm([Jb,ex]),rx=Ai((([e])=>{const t=Bi(e).toVar();return Wn(.6616,t)})).setLayout({name:"mx_gradient_scale2d_0",type:"float",inputs:[{name:"v",type:"float"}]}),sx=Ai((([e])=>{const t=Bi(e).toVar();return Wn(.982,t)})).setLayout({name:"mx_gradient_scale3d_0",type:"float",inputs:[{name:"v",type:"float"}]}),ix=Fm([rx,Ai((([e])=>{const t=Oi(e).toVar();return Wn(.6616,t)})).setLayout({name:"mx_gradient_scale2d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),nx=Fm([sx,Ai((([e])=>{const t=Oi(e).toVar();return Wn(.982,t)})).setLayout({name:"mx_gradient_scale3d_1",type:"vec3",inputs:[{name:"v",type:"vec3"}]})]),ox=Ai((([e,t])=>{const r=Ui(t).toVar(),s=Fi(e).toVar();return s.shiftLeft(r).bitOr(s.shiftRight(Ui(32).sub(r)))})).setLayout({name:"mx_rotl32",type:"uint",inputs:[{name:"x",type:"uint"},{name:"k",type:"int"}]}),ax=Ai((([e,t,r])=>{e.subAssign(r),e.bitXorAssign(ox(r,Ui(4))),r.addAssign(t),t.subAssign(e),t.bitXorAssign(ox(e,Ui(6))),e.addAssign(r),r.subAssign(t),r.bitXorAssign(ox(t,Ui(8))),t.addAssign(e),e.subAssign(r),e.bitXorAssign(ox(r,Ui(16))),r.addAssign(t),t.subAssign(e),t.bitXorAssign(ox(e,Ui(19))),e.addAssign(r),r.subAssign(t),r.bitXorAssign(ox(t,Ui(4))),t.addAssign(e)})),ux=Ai((([e,t,r])=>{const s=Fi(r).toVar(),i=Fi(t).toVar(),n=Fi(e).toVar();return s.bitXorAssign(i),s.subAssign(ox(i,Ui(14))),n.bitXorAssign(s),n.subAssign(ox(s,Ui(11))),i.bitXorAssign(n),i.subAssign(ox(n,Ui(25))),s.bitXorAssign(i),s.subAssign(ox(i,Ui(16))),n.bitXorAssign(s),n.subAssign(ox(s,Ui(4))),i.bitXorAssign(n),i.subAssign(ox(n,Ui(14))),s.bitXorAssign(i),s.subAssign(ox(i,Ui(24))),s})).setLayout({name:"mx_bjfinal",type:"uint",inputs:[{name:"a",type:"uint"},{name:"b",type:"uint"},{name:"c",type:"uint"}]}),lx=Ai((([e])=>{const t=Fi(e).toVar();return Bi(t).div(Bi(Fi(Ui(4294967295))))})).setLayout({name:"mx_bits_to_01",type:"float",inputs:[{name:"bits",type:"uint"}]}),dx=Ai((([e])=>{const t=Bi(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"}]}),cx=Fm([Ai((([e])=>{const t=Ui(e).toVar(),r=Fi(Fi(1)).toVar(),s=Fi(Fi(Ui(3735928559)).add(r.shiftLeft(Fi(2))).add(Fi(13))).toVar();return ux(s.add(Fi(t)),s,s)})).setLayout({name:"mx_hash_int_0",type:"uint",inputs:[{name:"x",type:"int"}]}),Ai((([e,t])=>{const r=Ui(t).toVar(),s=Ui(e).toVar(),i=Fi(Fi(2)).toVar(),n=Fi().toVar(),o=Fi().toVar(),a=Fi().toVar();return n.assign(o.assign(a.assign(Fi(Ui(3735928559)).add(i.shiftLeft(Fi(2))).add(Fi(13))))),n.addAssign(Fi(s)),o.addAssign(Fi(r)),ux(n,o,a)})).setLayout({name:"mx_hash_int_1",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Ui(t).toVar(),n=Ui(e).toVar(),o=Fi(Fi(3)).toVar(),a=Fi().toVar(),u=Fi().toVar(),l=Fi().toVar();return a.assign(u.assign(l.assign(Fi(Ui(3735928559)).add(o.shiftLeft(Fi(2))).add(Fi(13))))),a.addAssign(Fi(n)),u.addAssign(Fi(i)),l.addAssign(Fi(s)),ux(a,u,l)})).setLayout({name:"mx_hash_int_2",type:"uint",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]}),Ai((([e,t,r,s])=>{const i=Ui(s).toVar(),n=Ui(r).toVar(),o=Ui(t).toVar(),a=Ui(e).toVar(),u=Fi(Fi(4)).toVar(),l=Fi().toVar(),d=Fi().toVar(),c=Fi().toVar();return l.assign(d.assign(c.assign(Fi(Ui(3735928559)).add(u.shiftLeft(Fi(2))).add(Fi(13))))),l.addAssign(Fi(a)),d.addAssign(Fi(o)),c.addAssign(Fi(n)),ax(l,d,c),l.addAssign(Fi(i)),ux(l,d,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"}]}),Ai((([e,t,r,s,i])=>{const n=Ui(i).toVar(),o=Ui(s).toVar(),a=Ui(r).toVar(),u=Ui(t).toVar(),l=Ui(e).toVar(),d=Fi(Fi(5)).toVar(),c=Fi().toVar(),h=Fi().toVar(),p=Fi().toVar();return c.assign(h.assign(p.assign(Fi(Ui(3735928559)).add(d.shiftLeft(Fi(2))).add(Fi(13))))),c.addAssign(Fi(l)),h.addAssign(Fi(u)),p.addAssign(Fi(a)),ax(c,h,p),c.addAssign(Fi(o)),h.addAssign(Fi(n)),ux(c,h,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"}]})]),hx=Fm([Ai((([e,t])=>{const r=Ui(t).toVar(),s=Ui(e).toVar(),i=Fi(cx(s,r)).toVar(),n=ki().toVar();return n.x.assign(i.bitAnd(Ui(255))),n.y.assign(i.shiftRight(Ui(8)).bitAnd(Ui(255))),n.z.assign(i.shiftRight(Ui(16)).bitAnd(Ui(255))),n})).setLayout({name:"mx_hash_vec3_0",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"}]}),Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Ui(t).toVar(),n=Ui(e).toVar(),o=Fi(cx(n,i,s)).toVar(),a=ki().toVar();return a.x.assign(o.bitAnd(Ui(255))),a.y.assign(o.shiftRight(Ui(8)).bitAnd(Ui(255))),a.z.assign(o.shiftRight(Ui(16)).bitAnd(Ui(255))),a})).setLayout({name:"mx_hash_vec3_1",type:"uvec3",inputs:[{name:"x",type:"int"},{name:"y",type:"int"},{name:"z",type:"int"}]})]),px=Fm([Ai((([e])=>{const t=Ii(e).toVar(),r=Ui().toVar(),s=Ui().toVar(),i=Bi(qb(t.x,r)).toVar(),n=Bi(qb(t.y,s)).toVar(),o=Bi(dx(i)).toVar(),a=Bi(dx(n)).toVar(),u=Bi(Kb(Zb(cx(r,s),i,n),Zb(cx(r.add(Ui(1)),s),i.sub(1),n),Zb(cx(r,s.add(Ui(1))),i,n.sub(1)),Zb(cx(r.add(Ui(1)),s.add(Ui(1))),i.sub(1),n.sub(1)),o,a)).toVar();return ix(u)})).setLayout({name:"mx_perlin_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"}]}),Ai((([e])=>{const t=Oi(e).toVar(),r=Ui().toVar(),s=Ui().toVar(),i=Ui().toVar(),n=Bi(qb(t.x,r)).toVar(),o=Bi(qb(t.y,s)).toVar(),a=Bi(qb(t.z,i)).toVar(),u=Bi(dx(n)).toVar(),l=Bi(dx(o)).toVar(),d=Bi(dx(a)).toVar(),c=Bi(Xb(Zb(cx(r,s,i),n,o,a),Zb(cx(r.add(Ui(1)),s,i),n.sub(1),o,a),Zb(cx(r,s.add(Ui(1)),i),n,o.sub(1),a),Zb(cx(r.add(Ui(1)),s.add(Ui(1)),i),n.sub(1),o.sub(1),a),Zb(cx(r,s,i.add(Ui(1))),n,o,a.sub(1)),Zb(cx(r.add(Ui(1)),s,i.add(Ui(1))),n.sub(1),o,a.sub(1)),Zb(cx(r,s.add(Ui(1)),i.add(Ui(1))),n,o.sub(1),a.sub(1)),Zb(cx(r.add(Ui(1)),s.add(Ui(1)),i.add(Ui(1))),n.sub(1),o.sub(1),a.sub(1)),u,l,d)).toVar();return nx(c)})).setLayout({name:"mx_perlin_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"}]})]),gx=Fm([Ai((([e])=>{const t=Ii(e).toVar(),r=Ui().toVar(),s=Ui().toVar(),i=Bi(qb(t.x,r)).toVar(),n=Bi(qb(t.y,s)).toVar(),o=Bi(dx(i)).toVar(),a=Bi(dx(n)).toVar(),u=Oi(Kb(tx(hx(r,s),i,n),tx(hx(r.add(Ui(1)),s),i.sub(1),n),tx(hx(r,s.add(Ui(1))),i,n.sub(1)),tx(hx(r.add(Ui(1)),s.add(Ui(1))),i.sub(1),n.sub(1)),o,a)).toVar();return ix(u)})).setLayout({name:"mx_perlin_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),Ai((([e])=>{const t=Oi(e).toVar(),r=Ui().toVar(),s=Ui().toVar(),i=Ui().toVar(),n=Bi(qb(t.x,r)).toVar(),o=Bi(qb(t.y,s)).toVar(),a=Bi(qb(t.z,i)).toVar(),u=Bi(dx(n)).toVar(),l=Bi(dx(o)).toVar(),d=Bi(dx(a)).toVar(),c=Oi(Xb(tx(hx(r,s,i),n,o,a),tx(hx(r.add(Ui(1)),s,i),n.sub(1),o,a),tx(hx(r,s.add(Ui(1)),i),n,o.sub(1),a),tx(hx(r.add(Ui(1)),s.add(Ui(1)),i),n.sub(1),o.sub(1),a),tx(hx(r,s,i.add(Ui(1))),n,o,a.sub(1)),tx(hx(r.add(Ui(1)),s,i.add(Ui(1))),n.sub(1),o,a.sub(1)),tx(hx(r,s.add(Ui(1)),i.add(Ui(1))),n,o.sub(1),a.sub(1)),tx(hx(r.add(Ui(1)),s.add(Ui(1)),i.add(Ui(1))),n.sub(1),o.sub(1),a.sub(1)),u,l,d)).toVar();return nx(c)})).setLayout({name:"mx_perlin_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"}]})]),mx=Fm([Ai((([e])=>{const t=Bi(e).toVar(),r=Ui(jb(t)).toVar();return lx(cx(r))})).setLayout({name:"mx_cell_noise_float_0",type:"float",inputs:[{name:"p",type:"float"}]}),Ai((([e])=>{const t=Ii(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar();return lx(cx(r,s))})).setLayout({name:"mx_cell_noise_float_1",type:"float",inputs:[{name:"p",type:"vec2"}]}),Ai((([e])=>{const t=Oi(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar(),i=Ui(jb(t.z)).toVar();return lx(cx(r,s,i))})).setLayout({name:"mx_cell_noise_float_2",type:"float",inputs:[{name:"p",type:"vec3"}]}),Ai((([e])=>{const t=$i(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar(),i=Ui(jb(t.z)).toVar(),n=Ui(jb(t.w)).toVar();return lx(cx(r,s,i,n))})).setLayout({name:"mx_cell_noise_float_3",type:"float",inputs:[{name:"p",type:"vec4"}]})]),fx=Fm([Ai((([e])=>{const t=Bi(e).toVar(),r=Ui(jb(t)).toVar();return Oi(lx(cx(r,Ui(0))),lx(cx(r,Ui(1))),lx(cx(r,Ui(2))))})).setLayout({name:"mx_cell_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"float"}]}),Ai((([e])=>{const t=Ii(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar();return Oi(lx(cx(r,s,Ui(0))),lx(cx(r,s,Ui(1))),lx(cx(r,s,Ui(2))))})).setLayout({name:"mx_cell_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec2"}]}),Ai((([e])=>{const t=Oi(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar(),i=Ui(jb(t.z)).toVar();return Oi(lx(cx(r,s,i,Ui(0))),lx(cx(r,s,i,Ui(1))),lx(cx(r,s,i,Ui(2))))})).setLayout({name:"mx_cell_noise_vec3_2",type:"vec3",inputs:[{name:"p",type:"vec3"}]}),Ai((([e])=>{const t=$i(e).toVar(),r=Ui(jb(t.x)).toVar(),s=Ui(jb(t.y)).toVar(),i=Ui(jb(t.z)).toVar(),n=Ui(jb(t.w)).toVar();return Oi(lx(cx(r,s,i,n,Ui(0))),lx(cx(r,s,i,n,Ui(1))),lx(cx(r,s,i,n,Ui(2))))})).setLayout({name:"mx_cell_noise_vec3_3",type:"vec3",inputs:[{name:"p",type:"vec4"}]})]),yx=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Ui(t).toVar(),a=Oi(e).toVar(),u=Bi(0).toVar(),l=Bi(1).toVar();return pc(o,(()=>{u.addAssign(l.mul(px(a))),l.mulAssign(i),a.mulAssign(n)})),u})).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"}]}),bx=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Ui(t).toVar(),a=Oi(e).toVar(),u=Oi(0).toVar(),l=Bi(1).toVar();return pc(o,(()=>{u.addAssign(l.mul(gx(a))),l.mulAssign(i),a.mulAssign(n)})),u})).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"}]}),xx=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Ui(t).toVar(),a=Oi(e).toVar();return Ii(yx(a,o,n,i),yx(a.add(Oi(Ui(19),Ui(193),Ui(17))),o,n,i))})).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"}]}),Tx=Ai((([e,t,r,s])=>{const i=Bi(s).toVar(),n=Bi(r).toVar(),o=Ui(t).toVar(),a=Oi(e).toVar(),u=Oi(bx(a,o,n,i)).toVar(),l=Bi(yx(a.add(Oi(Ui(19),Ui(193),Ui(17))),o,n,i)).toVar();return $i(u,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"}]}),_x=Fm([Ai((([e,t,r,s,i,n,o])=>{const a=Ui(o).toVar(),u=Bi(n).toVar(),l=Ui(i).toVar(),d=Ui(s).toVar(),c=Ui(r).toVar(),h=Ui(t).toVar(),p=Ii(e).toVar(),g=Oi(fx(Ii(h.add(d),c.add(l)))).toVar(),m=Ii(g.x,g.y).toVar();m.subAssign(.5),m.mulAssign(u),m.addAssign(.5);const f=Ii(Ii(Bi(h),Bi(c)).add(m)).toVar(),y=Ii(f.sub(p)).toVar();return Ei(a.equal(Ui(2)),(()=>Lo(y.x).add(Lo(y.y)))),Ei(a.equal(Ui(3)),(()=>Zo(Lo(y.x),Lo(y.y)))),ia(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"}]}),Ai((([e,t,r,s,i,n,o,a,u])=>{const l=Ui(u).toVar(),d=Bi(a).toVar(),c=Ui(o).toVar(),h=Ui(n).toVar(),p=Ui(i).toVar(),g=Ui(s).toVar(),m=Ui(r).toVar(),f=Ui(t).toVar(),y=Oi(e).toVar(),b=Oi(fx(Oi(f.add(p),m.add(h),g.add(c)))).toVar();b.subAssign(.5),b.mulAssign(d),b.addAssign(.5);const x=Oi(Oi(Bi(f),Bi(m),Bi(g)).add(b)).toVar(),T=Oi(x.sub(y)).toVar();return Ei(l.equal(Ui(2)),(()=>Lo(T.x).add(Lo(T.y)).add(Lo(T.z)))),Ei(l.equal(Ui(3)),(()=>Zo(Zo(Lo(T.x),Lo(T.y)),Lo(T.z)))),ia(T,T)})).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"}]})]),vx=Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Ii(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ii(qb(n.x,o),qb(n.y,a)).toVar(),l=Bi(1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{const r=Bi(_x(u,e,t,o,a,i,s)).toVar();l.assign(Qo(l,r))}))})),Ei(s.equal(Ui(0)),(()=>{l.assign(Ao(l))})),l})).setLayout({name:"mx_worley_noise_float_0",type:"float",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),Nx=Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Ii(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ii(qb(n.x,o),qb(n.y,a)).toVar(),l=Ii(1e6,1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{const r=Bi(_x(u,e,t,o,a,i,s)).toVar();Ei(r.lessThan(l.x),(()=>{l.y.assign(l.x),l.x.assign(r)})).ElseIf(r.lessThan(l.y),(()=>{l.y.assign(r)}))}))})),Ei(s.equal(Ui(0)),(()=>{l.assign(Ao(l))})),l})).setLayout({name:"mx_worley_noise_vec2_0",type:"vec2",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),Sx=Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Ii(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ii(qb(n.x,o),qb(n.y,a)).toVar(),l=Oi(1e6,1e6,1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{const r=Bi(_x(u,e,t,o,a,i,s)).toVar();Ei(r.lessThan(l.x),(()=>{l.z.assign(l.y),l.y.assign(l.x),l.x.assign(r)})).ElseIf(r.lessThan(l.y),(()=>{l.z.assign(l.y),l.y.assign(r)})).ElseIf(r.lessThan(l.z),(()=>{l.z.assign(r)}))}))})),Ei(s.equal(Ui(0)),(()=>{l.assign(Ao(l))})),l})).setLayout({name:"mx_worley_noise_vec3_0",type:"vec3",inputs:[{name:"p",type:"vec2"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]}),Ax=Fm([vx,Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Oi(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ui().toVar(),l=Oi(qb(n.x,o),qb(n.y,a),qb(n.z,u)).toVar(),d=Bi(1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{pc({start:-1,end:Ui(1),name:"z",condition:"<="},(({z:r})=>{const n=Bi(_x(l,e,t,r,o,a,u,i,s)).toVar();d.assign(Qo(d,n))}))}))})),Ei(s.equal(Ui(0)),(()=>{d.assign(Ao(d))})),d})).setLayout({name:"mx_worley_noise_float_1",type:"float",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),Rx=Fm([Nx,Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Oi(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ui().toVar(),l=Oi(qb(n.x,o),qb(n.y,a),qb(n.z,u)).toVar(),d=Ii(1e6,1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{pc({start:-1,end:Ui(1),name:"z",condition:"<="},(({z:r})=>{const n=Bi(_x(l,e,t,r,o,a,u,i,s)).toVar();Ei(n.lessThan(d.x),(()=>{d.y.assign(d.x),d.x.assign(n)})).ElseIf(n.lessThan(d.y),(()=>{d.y.assign(n)}))}))}))})),Ei(s.equal(Ui(0)),(()=>{d.assign(Ao(d))})),d})).setLayout({name:"mx_worley_noise_vec2_1",type:"vec2",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),Cx=Fm([Sx,Ai((([e,t,r])=>{const s=Ui(r).toVar(),i=Bi(t).toVar(),n=Oi(e).toVar(),o=Ui().toVar(),a=Ui().toVar(),u=Ui().toVar(),l=Oi(qb(n.x,o),qb(n.y,a),qb(n.z,u)).toVar(),d=Oi(1e6,1e6,1e6).toVar();return pc({start:-1,end:Ui(1),name:"x",condition:"<="},(({x:e})=>{pc({start:-1,end:Ui(1),name:"y",condition:"<="},(({y:t})=>{pc({start:-1,end:Ui(1),name:"z",condition:"<="},(({z:r})=>{const n=Bi(_x(l,e,t,r,o,a,u,i,s)).toVar();Ei(n.lessThan(d.x),(()=>{d.z.assign(d.y),d.y.assign(d.x),d.x.assign(n)})).ElseIf(n.lessThan(d.y),(()=>{d.z.assign(d.y),d.y.assign(n)})).ElseIf(n.lessThan(d.z),(()=>{d.z.assign(n)}))}))}))})),Ei(s.equal(Ui(0)),(()=>{d.assign(Ao(d))})),d})).setLayout({name:"mx_worley_noise_vec3_1",type:"vec3",inputs:[{name:"p",type:"vec3"},{name:"jitter",type:"float"},{name:"metric",type:"int"}]})]),Ex=Ai((([e])=>{const t=e.y,r=e.z,s=Oi().toVar();return Ei(t.lessThan(1e-4),(()=>{s.assign(Oi(r,r,r))})).Else((()=>{let i=e.x;i=i.sub(Co(i)).mul(6).toVar();const n=Ui(jo(i)),o=i.sub(Bi(n)),a=r.mul(t.oneMinus()),u=r.mul(t.mul(o).oneMinus()),l=r.mul(t.mul(o.oneMinus()).oneMinus());Ei(n.equal(Ui(0)),(()=>{s.assign(Oi(r,l,a))})).ElseIf(n.equal(Ui(1)),(()=>{s.assign(Oi(u,r,a))})).ElseIf(n.equal(Ui(2)),(()=>{s.assign(Oi(a,r,l))})).ElseIf(n.equal(Ui(3)),(()=>{s.assign(Oi(a,u,r))})).ElseIf(n.equal(Ui(4)),(()=>{s.assign(Oi(l,a,r))})).Else((()=>{s.assign(Oi(r,a,u))}))})),s})).setLayout({name:"mx_hsvtorgb",type:"vec3",inputs:[{name:"hsv",type:"vec3"}]}),wx=Ai((([e])=>{const t=Oi(e).toVar(),r=Bi(t.x).toVar(),s=Bi(t.y).toVar(),i=Bi(t.z).toVar(),n=Bi(Qo(r,Qo(s,i))).toVar(),o=Bi(Zo(r,Zo(s,i))).toVar(),a=Bi(o.sub(n)).toVar(),u=Bi().toVar(),l=Bi().toVar(),d=Bi().toVar();return d.assign(o),Ei(o.greaterThan(0),(()=>{l.assign(a.div(o))})).Else((()=>{l.assign(0)})),Ei(l.lessThanEqual(0),(()=>{u.assign(0)})).Else((()=>{Ei(r.greaterThanEqual(o),(()=>{u.assign(s.sub(i).div(a))})).ElseIf(s.greaterThanEqual(o),(()=>{u.assign($n(2,i.sub(r).div(a)))})).Else((()=>{u.assign($n(4,r.sub(s).div(a)))})),u.mulAssign(1/6),Ei(u.lessThan(0),(()=>{u.addAssign(1)}))})),Oi(u,l,d)})).setLayout({name:"mx_rgbtohsv",type:"vec3",inputs:[{name:"c",type:"vec3"}]}),Mx=Ai((([e])=>{const t=Oi(e).toVar(),r=zi(Qn(t,Oi(.04045))).toVar(),s=Oi(t.div(12.92)).toVar(),i=Oi(oa(Zo(t.add(Oi(.055)),Oi(0)).div(1.055),Oi(2.4))).toVar();return pa(s,i,r)})).setLayout({name:"mx_srgb_texture_to_lin_rec709",type:"vec3",inputs:[{name:"color",type:"vec3"}]}),Bx=(e,t)=>{e=Bi(e),t=Bi(t);const r=Ii(t.dFdx(),t.dFdy()).length().mul(.7071067811865476);return ya(e.sub(r),e.add(r),t)},Ux=(e,t,r,s)=>pa(e,t,r[s].clamp()),Fx=(e,t,r,s,i)=>pa(e,t,Bx(r,s[i])),Px=Ai((([e,t,r])=>{const s=wo(e).toVar("nDir"),i=Hn(Bi(.5).mul(t.sub(r)),nl).div(s).toVar("rbmax"),n=Hn(Bi(-.5).mul(t.sub(r)),nl).div(s).toVar("rbmin"),o=Oi().toVar("rbminmax");o.x=s.x.greaterThan(Bi(0)).select(i.x,n.x),o.y=s.y.greaterThan(Bi(0)).select(i.y,n.y),o.z=s.z.greaterThan(Bi(0)).select(i.z,n.z);const a=Qo(Qo(o.x,o.y),o.z).toVar("correction");return nl.add(s.mul(a)).toVar("boxIntersection").sub(r)})),Ix=Ai((([e,t])=>{const r=e.x,s=e.y,i=e.z;let n=t.element(0).mul(.886227);return n=n.add(t.element(1).mul(1.023328).mul(s)),n=n.add(t.element(2).mul(1.023328).mul(i)),n=n.add(t.element(3).mul(1.023328).mul(r)),n=n.add(t.element(4).mul(.858086).mul(r).mul(s)),n=n.add(t.element(5).mul(.858086).mul(s).mul(i)),n=n.add(t.element(6).mul(i.mul(i).mul(.743125).sub(.247708))),n=n.add(t.element(7).mul(.858086).mul(r).mul(i)),n=n.add(t.element(8).mul(.429043).mul(Wn(r,r).sub(Wn(s,s)))),n}));var Dx=Object.freeze({__proto__:null,BRDF_GGX:Kh,BRDF_Lambert:Fh,BasicShadowFilter:bb,Break:gc,Const:Pa,Continue:()=>fu("continue").append(),DFGApprox:Xh,D_GGX:Wh,Discard:yu,EPSILON:po,F_Schlick:Uh,Fn:Ai,INFINITY:go,If:Ei,Loop:pc,NodeAccess:Es,NodeShaderStage:As,NodeType:Cs,NodeUpdateType:Rs,PCFShadowFilter:xb,PCFSoftShadowFilter:Tb,PI:mo,PI2:fo,Return:()=>fu("return").append(),Schlick_to_F0:Qh,ScriptableNodeResources:Ny,ShaderNode:xi,TBNViewMatrix:Jl,VSMShadowFilter:_b,V_GGX_SmithCorrelated:$h,Var:Fa,abs:Lo,acesFilmicToneMapping:ly,acos:Io,add:$n,addMethodChaining:qs,addNodeElement:function(e){console.warn("THREE.TSLBase: AddNodeElement has been removed in favor of tree-shaking. Trying add",e)},agxToneMapping:py,all:yo,alphaT:_n,and:eo,anisotropy:vn,anisotropyB:Sn,anisotropyT:Nn,any:bo,append:wi,arrayBuffer:e=>Ti(new Hs(e,"ArrayBuffer")),asin:Po,assign:On,atan:Do,atan2:va,atomicAdd:(e,t,r=null)=>jy(Hy.ATOMIC_ADD,e,t,r),atomicAnd:(e,t,r=null)=>jy(Hy.ATOMIC_AND,e,t,r),atomicFunc:jy,atomicMax:(e,t,r=null)=>jy(Hy.ATOMIC_MAX,e,t,r),atomicMin:(e,t,r=null)=>jy(Hy.ATOMIC_MIN,e,t,r),atomicOr:(e,t,r=null)=>jy(Hy.ATOMIC_OR,e,t,r),atomicStore:(e,t,r=null)=>jy(Hy.ATOMIC_STORE,e,t,r),atomicSub:(e,t,r=null)=>jy(Hy.ATOMIC_SUB,e,t,r),atomicXor:(e,t,r=null)=>jy(Hy.ATOMIC_XOR,e,t,r),attenuationColor:Dn,attenuationDistance:In,attribute:_u,attributeArray:(e,t="float")=>{const r=bs(t),s=ys(t),i=new xf(e,r,s);return Nf(i,t,e)},backgroundBlurriness:Mf,backgroundIntensity:Bf,backgroundRotation:Uf,batch:uc,billboarding:Om,bitAnd:io,bitNot:no,bitOr:oo,bitXor:ao,bitangentGeometry:ql,bitangentLocal:Kl,bitangentView:Xl,bitangentWorld:Yl,bitcast:Xo,blendBurn:kf,blendColor:Wf,blendDodge:zf,blendOverlay:Hf,blendScreen:$f,blur:Xp,bool:Pi,buffer:Ml,bufferAttribute:ru,bumpMap:ud,burn:(...e)=>(console.warn('THREE.TSL: "burn" has been renamed. Use "blendBurn" instead.'),kf(e)),bvec2:Vi,bvec3:zi,bvec4:ji,bypass:cu,cache:lu,call:kn,cameraFar:Bu,cameraNear:Mu,cameraNormalMatrix:Du,cameraPosition:Lu,cameraProjectionMatrix:Uu,cameraProjectionMatrixInverse:Fu,cameraViewMatrix:Pu,cameraWorldMatrix:Iu,cbrt:ca,cdl:Qf,ceil:Eo,checker:zb,cineonToneMapping:ay,clamp:ga,clearcoat:gn,clearcoatRoughness:mn,code:fy,color:Mi,colorSpaceToWorking:qa,colorToDirection:e=>Ti(e).mul(2).sub(1),compute:au,cond:Ca,context:wa,convert:Qi,convertColorSpace:(e,t,r)=>Ti(new $a(Ti(e),t,r)),convertToTexture:(e,...t)=>e.isTextureNode?e:e.isPassNode?e.getTextureNode():gf(e,...t),cos:Uo,cross:na,cubeTexture:El,dFdx:zo,dFdy:$o,dashSize:wn,defaultBuildStages:Ms,defaultShaderStages:ws,defined:yi,degrees:To,deltaTime:Im,densityFog:function(e,t){return console.warn('THREE.TSL: "densityFog( color, density )" is deprecated. Use "fog( color, densityFogFactor( density ) )" instead.'),wy(e,Ey(t))},densityFogFactor:Ey,depth:Qc,depthPass:(e,t,r)=>Ti(new sy(sy.DEPTH,e,t,r)),difference:sa,diffuseColor:dn,directPointLight:Gb,directionToColor:mh,dispersion:Ln,distance:ra,div:jn,dodge:(...e)=>(console.warn('THREE.TSL: "dodge" has been renamed. Use "blendDodge" instead.'),zf(e)),dot:ia,drawIndex:rc,dynamicBufferAttribute:su,element:Yi,emissive:cn,equal:Kn,equals:Yo,equirectUV:xh,exp:_o,exp2:vo,expression:fu,faceDirection:cl,faceForward:ba,faceforward:Na,float:Bi,floor:Co,fog:wy,fract:Mo,frameGroup:tn,frameId:Dm,frontFacing:dl,fwidth:qo,gain:(e,t)=>e.lessThan(.5)?Cm(e.mul(2),t).div(2):Hn(1,Cm(Wn(Hn(1,e),2),t).div(2)),gapSize:Mn,getConstNodeType:bi,getCurrentStack:Ci,getDirection:Wp,getDistanceAttenuation:Mb,getGeometryRoughness:kh,getNormalFromDepth:yf,getParallaxCorrectNormal:Px,getRoughness:zh,getScreenPosition:ff,getShIrradianceAt:Ix,getTextureIndex:Nm,getViewPosition:mf,globalId:Vy,glsl:(e,t)=>fy(e,t,"glsl"),glslFn:(e,t)=>by(e,t,"glsl"),grayscale:jf,greaterThan:Qn,greaterThanEqual:Jn,hash:Rm,highpModelNormalViewMatrix:tl,highpModelViewMatrix:el,hue:Xf,instance:ic,instanceIndex:Zd,instancedArray:(e,t="float")=>{const r=bs(t),s=ys(t),i=new bf(e,r,s);return Nf(i,t,e)},instancedBufferAttribute:iu,instancedDynamicBufferAttribute:nu,instancedMesh:oc,int:Ui,inverseSqrt:Ro,inversesqrt:Sa,invocationLocalIndex:tc,invocationSubgroupIndex:ec,ior:Un,iridescence:bn,iridescenceIOR:xn,iridescenceThickness:Tn,ivec2:Di,ivec3:Gi,ivec4:Hi,js:(e,t)=>fy(e,t,"js"),label:Ma,length:Oo,lengthSq:ha,lessThan:Yn,lessThanEqual:Zn,lightPosition:Qy,lightProjectionUV:Yy,lightShadowMatrix:Xy,lightTargetDirection:eb,lightTargetPosition:Zy,lightViewPosition:Jy,lightingContext:Nc,lights:(e=[])=>Ti(new sb).setLights(e),linearDepth:Zc,linearToneMapping:ny,localId:Oy,log:No,log2:So,logarithmicDepthToViewZ:(e,t,r)=>{const s=e.mul(No(r.div(t)));return Bi(Math.E).pow(s).mul(t).negate()},loop:(...e)=>(console.warn("TSL.LoopNode: loop() has been renamed to Loop()."),pc(...e)),luminance:Yf,mat2:qi,mat3:Ki,mat4:Xi,matcapUV:fg,materialAO:qd,materialAlphaTest:cd,materialAnisotropy:Md,materialAnisotropyVector:Kd,materialAttenuationColor:Vd,materialAttenuationDistance:Ld,materialClearcoat:Sd,materialClearcoatNormal:Rd,materialClearcoatRoughness:Ad,materialColor:hd,materialDispersion:Wd,materialEmissive:gd,materialIOR:Dd,materialIridescence:Bd,materialIridescenceIOR:Ud,materialIridescenceThickness:Fd,materialLightMap:jd,materialLineDashOffset:$d,materialLineDashSize:Gd,materialLineGapSize:kd,materialLineScale:Od,materialLineWidth:zd,materialMetalness:vd,materialNormal:Nd,materialOpacity:md,materialPointSize:Hd,materialReference:Ol,materialReflectivity:Td,materialRefractionRatio:vl,materialRotation:Cd,materialRoughness:_d,materialSheen:Ed,materialSheenRoughness:wd,materialShininess:pd,materialSpecular:fd,materialSpecularColor:bd,materialSpecularIntensity:yd,materialSpecularStrength:xd,materialThickness:Id,materialTransmission:Pd,max:Zo,maxMipLevel:Ru,mediumpModelViewMatrix:Ju,metalness:pn,min:Qo,mix:pa,mixElement:Ta,mod:Jo,modInt:qn,modelDirection:Wu,modelNormalMatrix:Yu,modelPosition:qu,modelScale:Ku,modelViewMatrix:Zu,modelViewPosition:Xu,modelViewProjection:Xd,modelWorldMatrix:ju,modelWorldMatrixInverse:Qu,morphReference:xc,mrt:Am,mul:Wn,mx_aastep:Bx,mx_cell_noise_float:(e=vu())=>mx(e.convert("vec2|vec3")),mx_contrast:(e,t=1,r=.5)=>Bi(e).sub(r).mul(t).add(r),mx_fractal_noise_float:(e=vu(),t=3,r=2,s=.5,i=1)=>yx(e,Ui(t),r,s).mul(i),mx_fractal_noise_vec2:(e=vu(),t=3,r=2,s=.5,i=1)=>xx(e,Ui(t),r,s).mul(i),mx_fractal_noise_vec3:(e=vu(),t=3,r=2,s=.5,i=1)=>bx(e,Ui(t),r,s).mul(i),mx_fractal_noise_vec4:(e=vu(),t=3,r=2,s=.5,i=1)=>Tx(e,Ui(t),r,s).mul(i),mx_hsvtorgb:Ex,mx_noise_float:(e=vu(),t=1,r=0)=>px(e.convert("vec2|vec3")).mul(t).add(r),mx_noise_vec3:(e=vu(),t=1,r=0)=>gx(e.convert("vec2|vec3")).mul(t).add(r),mx_noise_vec4:(e=vu(),t=1,r=0)=>{e=e.convert("vec2|vec3");return $i(gx(e),px(e.add(Ii(19,73)))).mul(t).add(r)},mx_ramplr:(e,t,r=vu())=>Ux(e,t,r,"x"),mx_ramptb:(e,t,r=vu())=>Ux(e,t,r,"y"),mx_rgbtohsv:wx,mx_safepower:(e,t=1)=>(e=Bi(e)).abs().pow(t).mul(e.sign()),mx_splitlr:(e,t,r,s=vu())=>Fx(e,t,r,s,"x"),mx_splittb:(e,t,r,s=vu())=>Fx(e,t,r,s,"y"),mx_srgb_texture_to_lin_rec709:Mx,mx_transform_uv:(e=1,t=0,r=vu())=>r.mul(e).add(t),mx_worley_noise_float:(e=vu(),t=1)=>Ax(e.convert("vec2|vec3"),t,Ui(1)),mx_worley_noise_vec2:(e=vu(),t=1)=>Rx(e.convert("vec2|vec3"),t,Ui(1)),mx_worley_noise_vec3:(e=vu(),t=1)=>Cx(e.convert("vec2|vec3"),t,Ui(1)),negate:Go,neutralToneMapping:gy,nodeArray:vi,nodeImmutable:Si,nodeObject:Ti,nodeObjects:_i,nodeProxy:Ni,normalFlat:gl,normalGeometry:hl,normalLocal:pl,normalMap:id,normalView:ml,normalWorld:fl,normalize:wo,not:ro,notEqual:Xn,numWorkgroups:Dy,objectDirection:Ou,objectGroup:sn,objectPosition:ku,objectScale:zu,objectViewPosition:$u,objectWorldMatrix:Gu,oneMinus:ko,or:to,orthographicDepthToViewZ:(e,t,r)=>t.sub(r).mul(e).sub(t),oscSawtooth:(e=Pm)=>e.fract(),oscSine:(e=Pm)=>e.add(.75).mul(2*Math.PI).sin().mul(.5).add(.5),oscSquare:(e=Pm)=>e.fract().round(),oscTriangle:(e=Pm)=>e.add(.5).fract().mul(2).sub(1).abs(),output:En,outputStruct:vm,overlay:(...e)=>(console.warn('THREE.TSL: "overlay" has been renamed. Use "blendOverlay" instead.'),Hf(e)),overloadingFn:Fm,parabola:Cm,parallaxDirection:ed,parallaxUV:(e,t)=>e.sub(ed.mul(t)),parameter:(e,t)=>Ti(new bm(e,t)),pass:(e,t,r)=>Ti(new sy(sy.COLOR,e,t,r)),passTexture:(e,t)=>Ti(new ty(e,t)),pcurve:(e,t,r)=>oa(jn(oa(e,t),$n(oa(e,t),oa(Hn(1,e),r))),1/t),perspectiveDepthToViewZ:Kc,pmremTexture:eg,pointUV:Rf,pointWidth:Bn,positionGeometry:rl,positionLocal:sl,positionPrevious:il,positionView:al,positionViewDirection:ul,positionWorld:nl,positionWorldDirection:ol,posterize:Jf,pow:oa,pow2:aa,pow3:ua,pow4:la,property:un,radians:xo,rand:xa,range:Fy,rangeFog:function(e,t,r){return console.warn('THREE.TSL: "rangeFog( color, near, far )" is deprecated. Use "fog( color, rangeFogFactor( near, far ) )" instead.'),wy(e,Cy(t,r))},rangeFogFactor:Cy,reciprocal:Wo,reference:Dl,referenceBuffer:Ll,reflect:ta,reflectVector:Al,reflectView:Nl,reflector:e=>Ti(new of(e)),refract:fa,refractVector:Rl,refractView:Sl,reinhardToneMapping:oy,remainder:co,remap:pu,remapClamp:gu,renderGroup:rn,renderOutput:xu,rendererReference:Qa,rotate:Tg,rotateUV:Lm,roughness:hn,round:Ho,rtt:gf,sRGBTransferEOTF:Oa,sRGBTransferOETF:Ga,sampler:e=>(!0===e.isNode?e:Eu(e)).convert("sampler"),saturate:ma,saturation:qf,screen:(...e)=>(console.warn('THREE.TSL: "screen" has been renamed. Use "blendScreen" instead.'),$f(e)),screenCoordinate:Mc,screenSize:wc,screenUV:Ec,scriptable:Ay,scriptableValue:Ty,select:Ra,setCurrentStack:Ri,shaderStages:Bs,shadow:Eb,shadowPositionWorld:nb,shapeCircle:$b,sharedUniformGroup:en,sheen:fn,sheenRoughness:yn,shiftLeft:uo,shiftRight:lo,shininess:Cn,sign:Vo,sin:Bo,sinc:(e,t)=>Bo(mo.mul(t.mul(e).sub(1))).div(mo.mul(t.mul(e).sub(1))),skinning:e=>Ti(new dc(e)),skinningReference:cc,smoothstep:ya,smoothstepElement:_a,specularColor:An,specularF90:Rn,spherizeUV:Vm,split:(e,t)=>Ti(new Gs(Ti(e),t)),spritesheetUV:zm,sqrt:Ao,stack:Tm,step:ea,storage:Nf,storageBarrier:()=>ky("storage").append(),storageObject:(e,t,r)=>(console.warn('THREE.TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.'),Nf(e,t,r).setPBO(!0)),storageTexture:Pf,string:(e="")=>Ti(new Hs(e,"string")),sub:Hn,subgroupIndex:Jd,subgroupSize:Gy,tan:Fo,tangentGeometry:Gl,tangentLocal:kl,tangentView:zl,tangentWorld:$l,temp:Ia,texture:Eu,texture3D:Mg,textureBarrier:()=>ky("texture").append(),textureBicubic:mp,textureCubeUV:jp,textureLoad:wu,textureSize:Su,textureStore:(e,t,r)=>{const s=Pf(e,t,r);return null!==r&&s.append(),s},thickness:Pn,time:Pm,timerDelta:(e=1)=>(console.warn('TSL: timerDelta() is deprecated. Use "deltaTime" instead.'),Im.mul(e)),timerGlobal:(e=1)=>(console.warn('TSL: timerGlobal() is deprecated. Use "time" instead.'),Pm.mul(e)),timerLocal:(e=1)=>(console.warn('TSL: timerLocal() is deprecated. Use "time" instead.'),Pm.mul(e)),toOutputColorSpace:Ha,toWorkingColorSpace:Wa,toneMapping:Ja,toneMappingExposure:eu,toonOutlinePass:(t,r,s=new e(0,0,0),i=.003,n=1)=>Ti(new iy(t,r,Ti(s),Ti(i),Ti(n))),transformDirection:da,transformNormal:Tl,transformNormalToView:_l,transformedBentNormalView:td,transformedBitangentView:Ql,transformedBitangentWorld:Zl,transformedClearcoatNormalView:xl,transformedNormalView:yl,transformedNormalWorld:bl,transformedTangentView:Hl,transformedTangentWorld:Wl,transmission:Fn,transpose:Ko,triNoise3D:Mm,triplanarTexture:(...e)=>Hm(...e),triplanarTextures:Hm,trunc:jo,tslFn:(...e)=>(console.warn("TSL.ShaderNode: tslFn() has been renamed to Fn()."),Ai(...e)),uint:Fi,uniform:on,uniformArray:Fl,uniformGroup:Ji,uniforms:(e,t)=>(console.warn("TSL.UniformArrayNode: uniforms() has been renamed to uniformArray()."),Ti(new Ul(e,t))),userData:(e,t,r)=>Ti(new If(e,t,r)),uv:vu,uvec2:Li,uvec3:ki,uvec4:Wi,varying:La,varyingProperty:ln,vec2:Ii,vec3:Oi,vec4:$i,vectorComponents:Us,velocity:Gf,vertexColor:e=>Ti(new Sf(e)),vertexIndex:Qd,vertexStage:Va,vibrance:Kf,viewZToLogarithmicDepth:Xc,viewZToOrthographicDepth:jc,viewZToPerspectiveDepth:qc,viewport:Bc,viewportBottomLeft:Lc,viewportCoordinate:Fc,viewportDepthTexture:Hc,viewportLinearDepth:Jc,viewportMipTexture:kc,viewportResolution:Ic,viewportSafeUV:Gm,viewportSharedTexture:hh,viewportSize:Uc,viewportTexture:Gc,viewportTopLeft:Dc,viewportUV:Pc,wgsl:(e,t)=>fy(e,t,"wgsl"),wgslFn:(e,t)=>by(e,t,"wgsl"),workgroupArray:(e,t)=>Ti(new $y("Workgroup",e,t)),workgroupBarrier:()=>ky("workgroup").append(),workgroupId:Ly,workingToColorSpace:ja,xor:so});const Lx=new ym;class Vx extends Vg{constructor(e,t){super(),this.renderer=e,this.nodes=t}update(e,t,r){const s=this.renderer,i=this.nodes.getBackgroundNode(e)||e.background;let n=!1;if(null===i)s._clearColor.getRGB(Lx,Re),Lx.a=s._clearColor.a;else if(!0===i.isColor)i.getRGB(Lx,Re),Lx.a=1,n=!0;else if(!0===i.isNode){const r=this.get(e),n=i;Lx.copy(s._clearColor);let o=r.backgroundMesh;if(void 0===o){const e=wa($i(n).mul(Bf),{getUV:()=>Uf.mul(fl),getTextureLevel:()=>Mf});let t=Xd;t=t.setZ(t.w);const s=new nh;s.name="Background.material",s.side=T,s.depthTest=!1,s.depthWrite=!1,s.fog=!1,s.lights=!1,s.vertexNode=t,s.colorNode=e,r.backgroundMeshNode=e,r.backgroundMesh=o=new G(new Be(1,32,32),s),o.frustumCulled=!1,o.name="Background.mesh",o.onBeforeRender=function(e,t,r){this.matrixWorld.copyPosition(r.matrixWorld)}}const a=n.getCacheKey();r.backgroundCacheKey!==a&&(r.backgroundMeshNode.node=$i(n).mul(Bf),r.backgroundMeshNode.needsUpdate=!0,o.material.needsUpdate=!0,r.backgroundCacheKey=a),t.unshift(o,o.geometry,o.material,0,0,null,null)}else console.error("THREE.Renderer: Unsupported background configuration.",i);if(!0===s.autoClear||!0===n){const e=r.clearColorValue;e.r=Lx.r,e.g=Lx.g,e.b=Lx.b,e.a=Lx.a,!0!==s.backend.isWebGLBackend&&!0!==s.alpha||(e.r*=e.a,e.g*=e.a,e.b*=e.a),r.depthClearValue=s._clearDepth,r.stencilClearValue=s._clearStencil,r.clearColor=!0===s.autoClearColor,r.clearDepth=!0===s.autoClearDepth,r.clearStencil=!0===s.autoClearStencil}else r.clearColor=!1,r.clearDepth=!1,r.clearStencil=!1}}let Ox=0;class Gx{constructor(e="",t=[],r=0,s=[]){this.name=e,this.bindings=t,this.index=r,this.bindingsReference=s,this.id=Ox++}}class kx{constructor(e,t,r,s,i,n,o,a,u,l=[]){this.vertexShader=e,this.fragmentShader=t,this.computeShader=r,this.transforms=l,this.nodeAttributes=s,this.bindings=i,this.updateNodes=n,this.updateBeforeNodes=o,this.updateAfterNodes=a,this.monitor=u,this.usedTimes=0}createBindings(){const e=[];for(const t of this.bindings){if(!0!==t.bindings[0].groupNode.shared){const r=new Gx(t.name,[],t.index,t);e.push(r);for(const e of t.bindings)r.bindings.push(e.clone())}else e.push(t)}return e}}class zx{constructor(e,t,r=null){this.isNodeAttribute=!0,this.name=e,this.type=t,this.node=r}}class $x{constructor(e,t,r){this.isNodeUniform=!0,this.name=e,this.type=t,this.node=r.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 Hx{constructor(e,t,r=!1){this.isNodeVar=!0,this.name=e,this.type=t,this.readOnly=r}}class Wx extends Hx{constructor(e,t){super(e,t),this.needsInterpolation=!1,this.isNodeVarying=!0}}class jx{constructor(e,t,r=""){this.name=e,this.type=t,this.code=r,Object.defineProperty(this,"isNodeCode",{value:!0})}}let qx=0;class Kx{constructor(e=null){this.id=qx++,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 Xx extends Ps{static get type(){return"StructTypeNode"}constructor(e,t){super(),this.name=e,this.types=t,this.isStructTypeNode=!0}getMemberTypes(){return this.types}}class Yx{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 Qx extends Yx{constructor(e,t=0){super(e,t),this.isNumberUniform=!0,this.boundary=4,this.itemSize=1}}class Zx extends Yx{constructor(e,r=new t){super(e,r),this.isVector2Uniform=!0,this.boundary=8,this.itemSize=2}}class Jx extends Yx{constructor(e,t=new r){super(e,t),this.isVector3Uniform=!0,this.boundary=16,this.itemSize=3}}class eT extends Yx{constructor(e,t=new s){super(e,t),this.isVector4Uniform=!0,this.boundary=16,this.itemSize=4}}class tT extends Yx{constructor(t,r=new e){super(t,r),this.isColorUniform=!0,this.boundary=16,this.itemSize=3}}class rT extends Yx{constructor(e,t=new i){super(e,t),this.isMatrix3Uniform=!0,this.boundary=48,this.itemSize=12}}class sT extends Yx{constructor(e,t=new n){super(e,t),this.isMatrix4Uniform=!0,this.boundary=64,this.itemSize=16}}class iT extends Qx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class nT extends Zx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class oT extends Jx{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class aT extends eT{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class uT extends tT{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class lT extends rT{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}class dT extends sT{constructor(e){super(e.name,e.value),this.nodeUniform=e}getValue(){return this.nodeUniform.value}getType(){return this.nodeUniform.type}}const cT=[.125,.215,.35,.446,.526,.582],hT=20,pT=new Te(-1,1,1,-1,0,1),gT=new Fe(90,1),mT=new e;let fT=null,yT=0,bT=0;const xT=(1+Math.sqrt(5))/2,TT=1/xT,_T=[new r(-xT,TT,0),new r(xT,TT,0),new r(-TT,0,xT),new r(TT,0,xT),new r(0,xT,-TT),new r(0,xT,TT),new r(-1,1,-1),new r(1,1,-1),new r(-1,1,1),new r(1,1,1)],vT=[3,1,5,0,4,2],NT=Wp(vu(),_u("faceIndex")).normalize(),ST=Oi(NT.x,NT.y,NT.z);class AT{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}get _hasInitialized(){return this._renderer.hasInitialized()}fromScene(e,t=0,r=.1,s=100,i=null){if(this._setSize(256),!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromScene() called before the backend is initialized. Try using .fromSceneAsync() instead.");const n=i||this._allocateTargets();return this.fromSceneAsync(e,t,r,s,n),n}fT=this._renderer.getRenderTarget(),yT=this._renderer.getActiveCubeFace(),bT=this._renderer.getActiveMipmapLevel();const n=i||this._allocateTargets();return n.depthBuffer=!0,this._sceneToCubeUV(e,r,s,n),t>0&&this._blur(n,0,0,t),this._applyPMREM(n),this._cleanup(n),n}async fromSceneAsync(e,t=0,r=.1,s=100,i=null){return!1===this._hasInitialized&&await this._renderer.init(),this.fromScene(e,t,r,s,i)}fromEquirectangular(e,t=null){if(!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromEquirectangular() called before the backend is initialized. Try using .fromEquirectangularAsync() instead."),this._setSizeFromTexture(e);const r=t||this._allocateTargets();return this.fromEquirectangularAsync(e,r),r}return this._fromTexture(e,t)}async fromEquirectangularAsync(e,t=null){return!1===this._hasInitialized&&await this._renderer.init(),this._fromTexture(e,t)}fromCubemap(e,t=null){if(!1===this._hasInitialized){console.warn("THREE.PMREMGenerator: .fromCubemap() called before the backend is initialized. Try using .fromCubemapAsync() instead."),this._setSizeFromTexture(e);const r=t||this._allocateTargets();return this.fromCubemapAsync(e,t),r}return this._fromTexture(e,t)}async fromCubemapAsync(e,t=null){return!1===this._hasInitialized&&await this._renderer.init(),this._fromTexture(e,t)}async compileCubemapShader(){null===this._cubemapMaterial&&(this._cubemapMaterial=wT(),await this._compileMaterial(this._cubemapMaterial))}async compileEquirectangularShader(){null===this._equirectMaterial&&(this._equirectMaterial=MT(),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())}_setSizeFromTexture(e){e.mapping===_||e.mapping===v?this._setSize(0===e.image.length?16:e.image[0].width||e.image[0].image.width):this._setSize(e.image.width/4)}_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?u=cT[a-e+4-1]:0===a&&(u=0),s.push(u);const l=1/(o-2),d=-l,c=1+l,h=[d,d,c,d,c,c,d,d,c,c,d,c],p=6,g=6,m=3,f=2,y=1,b=new Float32Array(m*g*p),x=new Float32Array(f*g*p),T=new Float32Array(y*g*p);for(let e=0;e2?0:-1,s=[t,r,0,t+2/3,r,0,t+2/3,r+1,0,t,r,0,t+2/3,r+1,0,t,r+1,0],i=vT[e];b.set(s,m*g*i),x.set(h,f*g*i);const n=[i,i,i,i,i,i];T.set(n,y*g*i)}const _=new _e;_.setAttribute("position",new Ne(b,m)),_.setAttribute("uv",new Ne(x,f)),_.setAttribute("faceIndex",new Ne(T,y)),t.push(_),i.push(new G(_,null)),n>4&&n--}return{lodPlanes:t,sizeLods:r,sigmas:s,lodMeshes:i}}(i)),this._blurMaterial=function(e,t,s){const i=Fl(new Array(hT).fill(0)),n=on(new r(0,1,0)),o=on(0),a=Bi(hT),u=on(0),l=on(1),d=Eu(null),c=on(0),h=Bi(1/t),p=Bi(1/s),g=Bi(e),m={n:a,latitudinal:u,weights:i,poleAxis:n,outputDirection:ST,dTheta:o,samples:l,envMap:d,mipInt:c,CUBEUV_TEXEL_WIDTH:h,CUBEUV_TEXEL_HEIGHT:p,CUBEUV_MAX_MIP:g},f=ET("blur");return f.uniforms=m,f.fragmentNode=Xp({...m,latitudinal:u.equal(1)}),f}(i,e,t)}return i}async _compileMaterial(e){const t=new G(this._lodPlanes[0],e);await this._renderer.compile(t,pT)}_sceneToCubeUV(e,t,r,s){const i=gT;i.near=t,i.far=r;const n=[1,1,1,1,-1,1],o=[1,-1,1,-1,1,-1],a=this._renderer,u=a.autoClear;a.getClearColor(mT),a.autoClear=!1;let l=this._backgroundBox;if(null===l){const e=new Y({name:"PMREM.Background",side:T,depthWrite:!1,depthTest:!1});l=new G(new O,e)}let d=!1;const c=e.background;c?c.isColor&&(l.material.color.copy(c),e.background=null,d=!0):(l.material.color.copy(mT),d=!0),a.setRenderTarget(s),a.clear(),d&&a.render(l,i);for(let t=0;t<6;t++){const r=t%3;0===r?(i.up.set(0,n[t],0),i.lookAt(o[t],0,0)):1===r?(i.up.set(0,0,n[t]),i.lookAt(0,o[t],0)):(i.up.set(0,n[t],0),i.lookAt(0,0,o[t]));const u=this._cubeSize;CT(s,r*u,t>2?u:0,u,u),a.render(e,i)}a.autoClear=u,e.background=c}_textureToCubeUV(e,t){const r=this._renderer,s=e.mapping===_||e.mapping===v;s?null===this._cubemapMaterial&&(this._cubemapMaterial=wT(e)):null===this._equirectMaterial&&(this._equirectMaterial=MT(e));const i=s?this._cubemapMaterial:this._equirectMaterial;i.fragmentNode.value=e;const n=this._lodMeshes[0];n.material=i;const o=this._cubeSize;CT(t,0,0,3*o,2*o),r.setRenderTarget(t),r.render(n,pT)}_applyPMREM(e){const t=this._renderer,r=t.autoClear;t.autoClear=!1;const s=this._lodPlanes.length;for(let t=1;thT&&console.warn(`sigmaRadians, ${i}, is too large and will clip, as it requested ${g} samples when the maximum is set to 20`);const m=[];let f=0;for(let e=0;ey-4?s-y+4:0),4*(this._cubeSize-b),3*b,2*b),a.setRenderTarget(t),a.render(l,pT)}}function RT(e,t,r){const s=new me(e,t,r);return s.texture.mapping=Ue,s.texture.name="PMREM.cubeUv",s.texture.isPMREMTexture=!0,s.scissorTest=!0,s}function CT(e,t,r,s,i){e.viewport.set(t,r,s,i),e.scissor.set(t,r,s,i)}function ET(e){const t=new nh;return t.depthTest=!1,t.depthWrite=!1,t.blending=D,t.name=`PMREM_${e}`,t}function wT(e){const t=ET("cubemap");return t.fragmentNode=El(e,ST),t}function MT(e){const t=ET("equirect");return t.fragmentNode=Eu(e,xh(ST),0),t}const BT=new WeakMap,UT=new Map([[Int8Array,"int"],[Int16Array,"int"],[Int32Array,"int"],[Uint8Array,"uint"],[Uint16Array,"uint"],[Uint32Array,"uint"],[Float32Array,"float"]]),FT=e=>/e/g.test(e)?String(e).replace(/\+/g,""):(e=Number(e))+(e%1?"":".0");class PT{constructor(e,t,r){this.object=e,this.material=e&&e.material||null,this.geometry=e&&e.geometry||null,this.renderer=t,this.parser=r,this.scene=null,this.camera=null,this.nodes=[],this.sequentialNodes=[],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=Tm(),this.stacks=[],this.tab="\t",this.currentFunctionNode=null,this.context={material:this.material},this.cache=new Kx,this.globalCache=this.cache,this.flowsData=new WeakMap,this.shaderStage=null,this.buildStage=null,this.useComparisonMethod=!1}getBindGroupsCache(){let e=BT.get(this.renderer);return void 0===e&&(e=new Fg,BT.set(this.renderer,e)),e}createRenderTarget(e,t,r){return new me(e,t,r)}createCubeRenderTarget(e,t){return new Th(e,t)}createPMREMGenerator(){return new AT(this.renderer)}includes(e){return this.nodes.includes(e)}getOutputStructName(){}_getBindGroup(e,t){const r=this.getBindGroupsCache(),s=[];let i,n=!0;for(const e of t)s.push(e),n=n&&!0!==e.groupNode.shared;return n?(i=r.get(s),void 0===i&&(i=new Gx(e,s,this.bindingsIndexes[e].group,s),r.set(s,i))):i=new Gx(e,s,this.bindingsIndexes[e].group,s),i}getBindGroupArray(e,t){const r=this.bindings[t];let s=r[e];return void 0===s&&(void 0===this.bindingsIndexes[e]&&(this.bindingsIndexes[e]={binding:0,group:Object.keys(this.bindingsIndexes).length}),r[e]=s=[]),s}getBindings(){let e=this.bindGroups;if(null===e){const t={},r=this.bindings;for(const e of Bs)for(const s in r[e]){const i=r[e][s];(t[s]||(t[s]=[])).push(...i)}e=[];for(const r in t){const s=t[r],i=this._getBindGroup(r,s);e.push(i)}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(n)}u`:"0u";if("bool"===i)return n?"true":"false";if("color"===i)return`${this.getType("vec3")}( ${FT(n.r)}, ${FT(n.g)}, ${FT(n.b)} )`;const o=this.getTypeLength(i),a=this.getComponentType(i),u=e=>this.generateConst(a,e);if(2===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)} )`;if(3===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)}, ${u(n.z)} )`;if(4===o)return`${this.getType(i)}( ${u(n.x)}, ${u(n.y)}, ${u(n.z)}, ${u(n.w)} )`;if(o>4&&n&&(n.isMatrix3||n.isMatrix4))return`${this.getType(i)}( ${n.elements.map(u).join(", ")} )`;if(o>4)return`${this.getType(i)}()`;throw new Error(`NodeBuilder: Type '${i}' 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 r=this.attributes;for(const t of r)if(t.name===e)return t;const s=new zx(e,t);return r.push(s),s}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===x)return"int";if(t===b)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 r=fs(e);return("float"===t?"":t[0])+r}getTypeFromArray(e){return UT.get(e.constructor)}getTypeFromAttribute(e){let t=e;e.isInterleavedBufferAttribute&&(t=e.data);const r=t.array,s=e.itemSize,i=e.normalized;let n;return e instanceof Le||!0===i||(n=this.getTypeFromArray(r)),this.getTypeFromLength(s,n)}getTypeLength(e){const t=this.getVectorType(e),r=/vec([2-4])/.exec(t);return null!==r?Number(r[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=Tm(this.stack),this.stacks.push(Ci()||this.stack),Ri(this.stack),this.stack}removeStack(){const e=this.stack;return this.stack=e.parent,Ri(this.stacks.pop()),e}getDataFromNode(e,t=this.shaderStage,r=null){let s=(r=null===r?e.isGlobal(this)?this.globalCache:this.cache:r).getData(e);return void 0===s&&(s={},r.setData(e,s)),void 0===s[t]&&(s[t]={}),s[t]}getNodeProperties(e,t="any"){const r=this.getDataFromNode(e,t);return r.properties||(r.properties={outputNode:null})}getBufferAttributeFromNode(e,t){const r=this.getDataFromNode(e);let s=r.bufferAttribute;if(void 0===s){const i=this.uniforms.index++;s=new zx("nodeAttribute"+i,t,e),this.bufferAttributes.push(s),r.bufferAttribute=s}return s}getStructTypeFromNode(e,t,r=this.shaderStage){const s=this.getDataFromNode(e,r);let i=s.structType;if(void 0===i){const e=this.structs.index++;i=new Xx("StructType"+e,t),this.structs[r].push(i),s.structType=i}return i}getUniformFromNode(e,t,r=this.shaderStage,s=null){const i=this.getDataFromNode(e,r,this.globalCache);let n=i.uniform;if(void 0===n){const o=this.uniforms.index++;n=new $x(s||"nodeUniform"+o,t,e),this.uniforms[r].push(n),i.uniform=n}return n}getVarFromNode(e,t=null,r=e.getNodeType(this),s=this.shaderStage,i=!1){const n=this.getDataFromNode(e,s);let o=n.variable;if(void 0===o){const e=i?"_const":"_var",a=this.vars[s]||(this.vars[s]=[]),u=this.vars[e]||(this.vars[e]=0);null===t&&(t=(i?"nodeConst":"nodeVar")+u,this.vars[e]++),o=new Hx(t,r,i),i||a.push(o),n.variable=o}return o}isDeterministic(e){return e.isMathNode?this.isDeterministic(e.aNode)&&(!e.bNode||this.isDeterministic(e.bNode))&&(!e.cNode||this.isDeterministic(e.cNode)):e.isOperatorNode?this.isDeterministic(e.aNode)&&(!e.bNode||this.isDeterministic(e.bNode)):!!e.isConstNode}getVaryingFromNode(e,t=null,r=e.getNodeType(this)){const s=this.getDataFromNode(e,"any");let i=s.varying;if(void 0===i){const e=this.varyings,n=e.length;null===t&&(t="nodeVarying"+n),i=new Wx(t,r),e.push(i),s.varying=i}return i}getCodeFromNode(e,t,r=this.shaderStage){const s=this.getDataFromNode(e);let i=s.code;if(void 0===i){const e=this.codes[r]||(this.codes[r]=[]),n=e.length;i=new jx("nodeCode"+n,t),e.push(i),s.code=i}return i}addFlowCodeHierarchy(e,t){const{flowCodes:r,flowCodeBlock:s}=this.getDataFromNode(e);let i=!0,n=t;for(;n;){if(!0===s.get(n)){i=!1;break}n=this.getDataFromNode(n).parentNodeBlock}if(i)for(const e of r)this.addLineFlowCode(e)}addLineFlowCodeBlock(e,t,r){const s=this.getDataFromNode(e),i=s.flowCodes||(s.flowCodes=[]),n=s.flowCodeBlock||(s.flowCodeBlock=new WeakMap);i.push(t),n.set(r,!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),r=this.flowChildNode(e,t);return this.flowsData.set(e,r),r}buildFunctionNode(e){const t=new yy,r=this.currentFunctionNode;return this.currentFunctionNode=t,t.code=this.buildFunctionCode(e),this.currentFunctionNode=r,t}flowShaderNode(e){const t=e.layout,r={[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)r[e.name]=new bm(e.type,e.name);e.layout=null;const s=e.call(r),i=this.flowStagesNode(s,t.type);return e.layout=t,i}flowStagesNode(e,t=null){const r=this.flow,s=this.vars,i=this.cache,n=this.buildStage,o=this.stack,a={code:""};this.flow=a,this.vars={},this.cache=new Kx,this.stack=Tm();for(const r of Ms)this.setBuildStage(r),a.result=e.build(this,t);return a.vars=this.getVars(this.shaderStage),this.flow=r,this.vars=s,this.cache=i,this.stack=o,this.setBuildStage(n),a}getFunctionOperator(){return null}flowChildNode(e,t=null){const r=this.flow,s={code:""};return this.flow=s,s.result=e.build(this,t),this.flow=r,s}flowNodeFromShaderStage(e,t,r=null,s=null){const i=this.shaderStage;this.setShaderStage(e);const n=this.flowChildNode(t,r);return null!==s&&(n.code+=`${this.tab+s} = ${n.result};\n`),this.flowCode[e]=this.flowCode[e]+n.code,this.setShaderStage(i),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 r=this.vars[e];if(void 0!==r)for(const e of r)t+=`${this.getVar(e.type,e.name)}; `;return t}getUniforms(){console.warn("Abstract function.")}getCodes(e){const t=this.codes[e];let r="";if(void 0!==t)for(const e of t)r+=e.code+"\n";return r}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:r}=this;if(null!==t){let e=r.library.fromMaterial(t);null===e&&(console.error(`NodeMaterial: Material "${t.type}" is not compatible.`),e=new nh),e.build(this)}else this.addFlow("compute",e);for(const e of Ms){this.setBuildStage(e),this.context.vertex&&this.context.vertex.isNode&&this.flowNodeFromShaderStage("vertex",this.context.vertex);for(const t of Bs){this.setShaderStage(t);const r=this.flowNodes[t];for(const t of r)"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 iT(e);if("vec2"===t||"ivec2"===t||"uvec2"===t)return new nT(e);if("vec3"===t||"ivec3"===t||"uvec3"===t)return new oT(e);if("vec4"===t||"ivec4"===t||"uvec4"===t)return new aT(e);if("color"===t)return new uT(e);if("mat3"===t)return new lT(e);if("mat4"===t)return new dT(e);throw new Error(`Uniform "${t}" not declared.`)}format(e,t,r){if((t=this.getVectorType(t))===(r=this.getVectorType(r))||null===r||this.isReference(r))return e;const s=this.getTypeLength(t),i=this.getTypeLength(r);return 16===s&&9===i?`${this.getType(r)}(${e}[0].xyz, ${e}[1].xyz, ${e}[2].xyz)`:9===s&&4===i?`${this.getType(r)}(${e}[0].xy, ${e}[1].xy)`:s>4||i>4||0===i?e:s===i?`${this.getType(r)}( ${e} )`:s>i?this.format(`${e}.${"xyz".slice(0,i)}`,this.getTypeFromLength(i,this.getComponentType(t)),r):4===i&&s>1?`${this.getType(r)}( ${this.format(e,t,"vec3")}, 1.0 )`:2===s?`${this.getType(r)}( ${this.format(e,t,"vec2")}, 0.0 )`:(1===s&&i>1&&t!==this.getComponentType(r)&&(e=`${this.getType(this.getComponentType(r))}( ${e} )`),`${this.getType(r)}( ${e} )`)}getSignature(){return`// Three.js r${Ve} - Node System\n`}createNodeMaterial(e="NodeMaterial"){throw new Error(`THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${e}() instead.`)}}class IT{constructor(){this.time=0,this.deltaTime=0,this.frameId=0,this.renderId=0,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 r=e.get(t);return void 0===r&&(r={renderMap:new WeakMap,frameMap:new WeakMap},e.set(t,r)),r}updateBeforeNode(e){const t=e.getUpdateBeforeType(),r=e.updateReference(this);if(t===Rs.FRAME){const{frameMap:t}=this._getMaps(this.updateBeforeMap,r);t.get(r)!==this.frameId&&!1!==e.updateBefore(this)&&t.set(r,this.frameId)}else if(t===Rs.RENDER){const{renderMap:t}=this._getMaps(this.updateBeforeMap,r);t.get(r)!==this.renderId&&!1!==e.updateBefore(this)&&t.set(r,this.renderId)}else t===Rs.OBJECT&&e.updateBefore(this)}updateAfterNode(e){const t=e.getUpdateAfterType(),r=e.updateReference(this);if(t===Rs.FRAME){const{frameMap:t}=this._getMaps(this.updateAfterMap,r);t.get(r)!==this.frameId&&!1!==e.updateAfter(this)&&t.set(r,this.frameId)}else if(t===Rs.RENDER){const{renderMap:t}=this._getMaps(this.updateAfterMap,r);t.get(r)!==this.renderId&&!1!==e.updateAfter(this)&&t.set(r,this.renderId)}else t===Rs.OBJECT&&e.updateAfter(this)}updateNode(e){const t=e.getUpdateType(),r=e.updateReference(this);if(t===Rs.FRAME){const{frameMap:t}=this._getMaps(this.updateMap,r);t.get(r)!==this.frameId&&!1!==e.update(this)&&t.set(r,this.frameId)}else if(t===Rs.RENDER){const{renderMap:t}=this._getMaps(this.updateMap,r);t.get(r)!==this.renderId&&!1!==e.update(this)&&t.set(r,this.renderId)}else t===Rs.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 DT{constructor(e,t,r=null,s="",i=!1){this.type=e,this.name=t,this.count=r,this.qualifier=s,this.isConst=i}}DT.isNodeFunctionInput=!0;class LT extends wb{static get type(){return"DirectionalLightNode"}constructor(e=null){super(e)}setup(e){super.setup(e);const t=e.context.lightingModel,r=this.colorNode,s=eb(this.light),i=e.context.reflectedLight;t.direct({lightDirection:s,lightColor:r,reflectedLight:i},e.stack,e)}}const VT=new n,OT=new n;let GT=null;class kT extends wb{static get type(){return"RectAreaLightNode"}constructor(e=null){super(e),this.halfHeight=on(new r).setGroup(rn),this.halfWidth=on(new r).setGroup(rn),this.updateType=Rs.RENDER}update(e){super.update(e);const{light:t}=this,r=e.camera.matrixWorldInverse;OT.identity(),VT.copy(t.matrixWorld),VT.premultiply(r),OT.extractRotation(VT),this.halfWidth.value.set(.5*t.width,0,0),this.halfHeight.value.set(0,.5*t.height,0),this.halfWidth.value.applyMatrix4(OT),this.halfHeight.value.applyMatrix4(OT)}setup(e){let t,r;super.setup(e),e.isAvailable("float32Filterable")?(t=Eu(GT.LTC_FLOAT_1),r=Eu(GT.LTC_FLOAT_2)):(t=Eu(GT.LTC_HALF_1),r=Eu(GT.LTC_HALF_2));const{colorNode:s,light:i}=this,n=e.context.lightingModel,o=Jy(i),a=e.context.reflectedLight;n.directRectArea({lightColor:s,lightPosition:o,halfWidth:this.halfWidth,halfHeight:this.halfHeight,reflectedLight:a,ltc_1:t,ltc_2:r},e.stack,e)}static setLTC(e){GT=e}}class zT extends wb{static get type(){return"SpotLightNode"}constructor(e=null){super(e),this.coneCosNode=on(0).setGroup(rn),this.penumbraCosNode=on(0).setGroup(rn),this.cutoffDistanceNode=on(0).setGroup(rn),this.decayExponentNode=on(0).setGroup(rn)}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:r}=this;return ya(t,r,e)}setup(e){super.setup(e);const t=e.context.lightingModel,{colorNode:r,cutoffDistanceNode:s,decayExponentNode:i,light:n}=this,o=Jy(n).sub(al),a=o.normalize(),u=a.dot(eb(n)),l=this.getSpotAttenuation(u),d=o.length(),c=Mb({lightDistance:d,cutoffDistance:s,decayExponent:i});let h=r.mul(l).mul(c);if(n.map){const e=Yy(n),t=Eu(n.map,e.xy).onRenderUpdate((()=>n.map));h=e.mul(2).sub(1).abs().lessThan(1).all().select(h.mul(t),h)}const p=e.context.reflectedLight;t.direct({lightDirection:a,lightColor:h,reflectedLight:p},e.stack,e)}}class $T extends zT{static get type(){return"IESSpotLightNode"}getSpotAttenuation(e){const t=this.light.iesMap;let r=null;if(t&&!0===t.isTexture){const s=e.acos().mul(1/Math.PI);r=Eu(t,Ii(s,0),0).r}else r=super.getSpotAttenuation(e);return r}}class HT extends wb{static get type(){return"AmbientLightNode"}constructor(e=null){super(e)}setup({context:e}){e.irradiance.addAssign(this.colorNode)}}class WT extends wb{static get type(){return"HemisphereLightNode"}constructor(t=null){super(t),this.lightPositionNode=Qy(t),this.lightDirectionNode=this.lightPositionNode.normalize(),this.groundColorNode=on(new e).setGroup(rn)}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:r,lightDirectionNode:s}=this,i=ml.dot(s).mul(.5).add(.5),n=pa(r,t,i);e.context.irradiance.addAssign(n)}}class jT extends wb{static get type(){return"LightProbeNode"}constructor(e=null){super(e);const t=[];for(let e=0;e<9;e++)t.push(new r);this.lightProbe=Fl(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=Ix(fl,this.lightProbe);e.context.irradiance.addAssign(t)}}class qT{parseFunction(){console.warn("Abstract function.")}}class KT{constructor(e,t,r="",s=""){this.type=e,this.inputs=t,this.name=r,this.precision=s}getCode(){console.warn("Abstract function.")}}KT.isNodeFunction=!0;const XT=/^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\(([\s\S]*?)\)/i,YT=/[a-z_0-9]+/gi,QT="#pragma main";class ZT extends KT{constructor(e){const{type:t,inputs:r,name:s,precision:i,inputsCode:n,blockCode:o,headerCode:a}=(e=>{const t=(e=e.trim()).indexOf(QT),r=-1!==t?e.slice(t+12):e,s=r.match(XT);if(null!==s&&5===s.length){const i=s[4],n=[];let o=null;for(;null!==(o=YT.exec(i));)n.push(o);const a=[];let u=0;for(;u0||e.backgroundBlurriness>0&&0===t.backgroundBlurriness;if(t.background!==r||s){const i=this.getCacheNode("background",r,(()=>{if(!0===r.isCubeTexture||r.mapping===W||r.mapping===j||r.mapping===Ue){if(e.backgroundBlurriness>0||r.mapping===Ue)return eg(r);{let e;return e=!0===r.isCubeTexture?El(r):Eu(r),Ah(e)}}if(!0===r.isTexture)return Eu(r,Ec.flipY()).setUpdateMatrix(!0);!0!==r.isColor&&console.error("WebGPUNodes: Unsupported background configuration.",r)}),s);t.backgroundNode=i,t.background=r,t.backgroundBlurriness=e.backgroundBlurriness}}else t.backgroundNode&&(delete t.backgroundNode,delete t.background)}getCacheNode(e,t,r,s=!1){const i=this.cacheLib[e]||(this.cacheLib[e]=new WeakMap);let n=i.get(t);return(void 0===n||s)&&(n=r(),i.set(t,n)),n}updateFog(e){const t=this.get(e),r=e.fog;if(r){if(t.fog!==r){const e=this.getCacheNode("fog",r,(()=>{if(r.isFogExp2){const e=Dl("color","color",r).setGroup(rn),t=Dl("density","float",r).setGroup(rn);return wy(e,Ey(t))}if(r.isFog){const e=Dl("color","color",r).setGroup(rn),t=Dl("near","float",r).setGroup(rn),s=Dl("far","float",r).setGroup(rn);return wy(e,Cy(t,s))}console.error("THREE.Renderer: Unsupported fog configuration.",r)}));t.fogNode=e,t.fog=r}}else delete t.fogNode,delete t.fog}updateEnvironment(e){const t=this.get(e),r=e.environment;if(r){if(t.environment!==r){const e=this.getCacheNode("environment",r,(()=>!0===r.isCubeTexture?El(r):!0===r.isTexture?Eu(r):void console.error("Nodes: Unsupported environment configuration.",r)));t.environmentNode=e,t.environment=r}}else t.environmentNode&&(delete t.environmentNode,delete t.environment)}getNodeFrame(e=this.renderer,t=null,r=null,s=null,i=null){const n=this.nodeFrame;return n.renderer=e,n.scene=t,n.object=r,n.camera=s,n.material=i,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 e_.get(e)!==this.getOutputCacheKey()}getOutputNode(e){const t=this.renderer,r=this.getOutputCacheKey(),s=Eu(e,Ec).renderOutput(t.toneMapping,t.currentColorSpace);return e_.set(e,r),s}updateBefore(e){const t=e.getNodeBuilderState();for(const r of t.updateBeforeNodes)this.getNodeFrameForRender(e).updateBeforeNode(r)}updateAfter(e){const t=e.getNodeBuilderState();for(const r of t.updateAfterNodes)this.getNodeFrameForRender(e).updateAfterNode(r)}updateForCompute(e){const t=this.getNodeFrame(),r=this.getForCompute(e);for(const e of r.updateNodes)t.updateNode(e)}updateForRender(e){const t=this.getNodeFrameForRender(e),r=e.getNodeBuilderState();for(const e of r.updateNodes)t.updateNode(e)}needsRefresh(e){const t=this.getNodeFrameForRender(e);return e.getMonitor().needsRefresh(e,t)}dispose(){super.dispose(),this.nodeFrame=new IT,this.nodeBuilderCache=new Map,this.cacheLib={}}}const i_=new fe;class n_{constructor(e=null){this.version=0,this.clipIntersection=null,this.cacheKey="",this.shadowPass=!1,this.viewNormalMatrix=new i,this.clippingGroupContexts=new WeakMap,this.intersectionPlanes=[],this.unionPlanes=[],this.parentVersion=null,null!==e&&(this.viewNormalMatrix=e.viewNormalMatrix,this.clippingGroupContexts=e.clippingGroupContexts,this.shadowPass=e.shadowPass,this.viewMatrix=e.viewMatrix)}projectPlanes(e,t,r){const s=e.length;for(let i=0;i{await this.compileAsync(e,t);const s=this._renderLists.get(e,t),i=this._renderContexts.get(e,t,this._renderTarget),n=e.overrideMaterial||r.material,o=this._objects.get(r,n,e,t,s.lightsNode,i,i.clippingContext),{fragmentShader:a,vertexShader:u}=o.getNodeBuilderState();return{fragmentShader:a,vertexShader:u}}}}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 r=this.backend;try{await r.init(this)}catch(e){if(null===this._getFallback)return void t(e);try{this.backend=r=this._getFallback(e),await r.init(this)}catch(e){return void t(e)}}this._nodes=new s_(this,r),this._animation=new Ug(this._nodes,this.info),this._attributes=new Hg(r),this._background=new Vx(this,this._nodes),this._geometries=new qg(this._attributes,this.info),this._textures=new fm(this,r,this.info),this._pipelines=new em(r,this._nodes),this._bindings=new tm(r,this._nodes,this._textures,this._attributes,this._pipelines,this.info),this._objects=new Lg(this,this._nodes,this._geometries,this._pipelines,this._bindings,this.info),this._renderLists=new am(this.lighting),this._bundles=new u_,this._renderContexts=new gm,this._animation.start(),this._initialized=!0,e()}))),this._initPromise}get coordinateSystem(){return this.backend.coordinateSystem}async compileAsync(e,t,r=null){if(!0===this._isDeviceLost)return;!1===this._initialized&&await this.init();const s=this._nodes.nodeFrame,i=s.renderId,n=this._currentRenderContext,o=this._currentRenderObjectFunction,a=this._compilationPromises,u=!0===e.isScene?e:p_;null===r&&(r=e);const l=this._renderTarget,d=this._renderContexts.get(r,t,l),c=this._activeMipmapLevel,h=[];this._currentRenderContext=d,this._currentRenderObjectFunction=this.renderObject,this._handleObjectFunction=this._createObjectPipeline,this._compilationPromises=h,s.renderId++,s.update(),d.depth=this.depth,d.stencil=this.stencil,d.clippingContext||(d.clippingContext=new n_),d.clippingContext.updateGlobal(u,t),u.onBeforeRender(this,e,t,l);const p=this._renderLists.get(e,t);if(p.begin(),this._projectObject(e,t,0,p,d.clippingContext),r!==e&&r.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);d.textures=e.textures,d.depthTexture=e.depthTexture}else d.textures=null,d.depthTexture=null;this._background.update(u,p,d);const g=p.opaque,m=p.transparent,f=p.transparentDoublePass,y=p.lightsNode;!0===this.opaque&&g.length>0&&this._renderObjects(g,t,u,y),!0===this.transparent&&m.length>0&&this._renderTransparents(m,f,t,u,y),s.renderId=i,this._currentRenderContext=n,this._currentRenderObjectFunction=o,this._compilationPromises=a,this._handleObjectFunction=this._renderObjectDirect,await Promise.all(h)}async renderAsync(e,t){!1===this._initialized&&await this.init();const r=this._renderScene(e,t);await this.backend.resolveTimestampAsync(r,"render")}async waitForGPU(){await this.backend.waitForGPU()}setMRT(e){return this._mrt=e,this}getMRT(){return this._mrt}_onDeviceLost(e){let t=`THREE.WebGPURenderer: ${e.api} Device Lost:\n\nMessage: ${e.message}`;e.reason&&(t+=`\nReason: ${e.reason}`),console.error(t),this._isDeviceLost=!0}_renderBundle(e,t,r){const{bundleGroup:s,camera:i,renderList:n}=e,o=this._currentRenderContext,a=this._bundles.get(s,i),u=this.backend.get(a);void 0===u.renderContexts&&(u.renderContexts=new Set);const l=s.version!==u.version,d=!1===u.renderContexts.has(o)||l;if(u.renderContexts.add(o),d){this.backend.beginBundle(o),(void 0===u.renderObjects||l)&&(u.renderObjects=[]),this._currentRenderBundle=a;const e=n.opaque;!0===this.opaque&&e.length>0&&this._renderObjects(e,i,t,r),this._currentRenderBundle=null,this.backend.finishBundle(o,a),u.version=s.version}else{const{renderObjects:e}=u;for(let t=0,r=e.length;t>=c,p.viewportValue.height>>=c,p.viewportValue.minDepth=b,p.viewportValue.maxDepth=x,p.viewport=!1===p.viewportValue.equals(m_),p.scissorValue.copy(f).multiplyScalar(y).floor(),p.scissor=this._scissorTest&&!1===p.scissorValue.equals(m_),p.scissorValue.width>>=c,p.scissorValue.height>>=c,p.clippingContext||(p.clippingContext=new n_),p.clippingContext.updateGlobal(u,t),u.onBeforeRender(this,e,t,h),y_.multiplyMatrices(t.projectionMatrix,t.matrixWorldInverse),f_.setFromProjectionMatrix(y_,g);const T=this._renderLists.get(e,t);if(T.begin(),this._projectObject(e,t,0,T,p.clippingContext),T.finish(),!0===this.sortObjects&&T.sort(this._opaqueSort,this._transparentSort),null!==h){this._textures.updateRenderTarget(h,c);const e=this._textures.get(h);p.textures=e.textures,p.depthTexture=e.depthTexture,p.width=e.width,p.height=e.height,p.renderTarget=h,p.depth=h.depthBuffer,p.stencil=h.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=d,p.activeMipmapLevel=c,p.occlusionQueryCount=T.occlusionQueryCount,this._background.update(u,T,p),this.backend.beginRender(p);const{bundles:_,lightsNode:v,transparentDoublePass:N,transparent:S,opaque:A}=T;if(_.length>0&&this._renderBundles(_,u,v),!0===this.opaque&&A.length>0&&this._renderObjects(A,t,u,v),!0===this.transparent&&S.length>0&&this._renderTransparents(S,N,t,u,v),this.backend.finishRender(p),i.renderId=n,this._currentRenderContext=o,this._currentRenderObjectFunction=a,null!==s){this.setRenderTarget(l,d,c);const e=this._quad;this._nodes.hasOutputChange(h.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(h.texture),e.material.needsUpdate=!0),this._renderScene(e,e.camera,!1)}return u.onAfterRender(this,e,t,h),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._pixelRatio=e,this.setSize(this._width,this._height,!1))}setDrawingBufferSize(e,t,r){this._width=e,this._height=t,this._pixelRatio=r,this.domElement.width=Math.floor(e*r),this.domElement.height=Math.floor(t*r),this.setViewport(0,0,e,t),this._initialized&&this.backend.updateSize()}setSize(e,t,r=!0){this._width=e,this._height=t,this.domElement.width=Math.floor(e*this._pixelRatio),this.domElement.height=Math.floor(t*this._pixelRatio),!0===r&&(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,r,s){const i=this._scissor;e.isVector4?i.copy(e):i.set(e,t,r,s)}getScissorTest(){return this._scissorTest}setScissorTest(e){this._scissorTest=e,this.backend.setScissorTest(e)}getViewport(e){return e.copy(this._viewport)}setViewport(e,t,r,s,i=0,n=1){const o=this._viewport;e.isVector4?o.copy(e):o.set(e,t,r,s),o.minDepth=i,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,r=!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,r);const s=this._renderTarget||this._getFrameBufferTarget();let i=null;if(null!==s){this._textures.updateRenderTarget(s);const e=this._textures.get(s);i=this._renderContexts.getForClear(s),i.textures=e.textures,i.depthTexture=e.depthTexture,i.width=e.width,i.height=e.height,i.renderTarget=s,i.depth=s.depthBuffer,i.stencil=s.stencilBuffer}if(this.backend.clear(e,t,r,i),null!==s&&null===this._renderTarget){const e=this._quad;this._nodes.hasOutputChange(s.texture)&&(e.material.fragmentNode=this._nodes.getOutputNode(s.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,r=!0){!1===this._initialized&&await this.init(),this.clear(e,t,r)}async clearColorAsync(){this.clearAsync(!0,!1,!1)}async clearDepthAsync(){this.clearAsync(!1,!0,!1)}async clearStencilAsync(){this.clearAsync(!1,!1,!0)}get currentToneMapping(){return null!==this._renderTarget?h:this.toneMapping}get currentColorSpace(){return null!==this._renderTarget?Re:this.outputColorSpace}dispose(){this.info.dispose(),this.backend.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,r=0){this._renderTarget=e,this._activeCubeFace=t,this._activeMipmapLevel=r}getRenderTarget(){return this._renderTarget}setRenderObjectFunction(e){this._renderObjectFunction=e}getRenderObjectFunction(){return this._renderObjectFunction}compute(e){if(!0===this._isDeviceLost)return;if(!1===this._initialized)return console.warn("THREE.Renderer: .compute() called before the backend is initialized. Try using .computeAsync() instead."),this.computeAsync(e);const t=this._nodes.nodeFrame,r=t.renderId;this.info.calls++,this.info.compute.calls++,this.info.compute.frameCalls++,t.renderId=this.info.calls;const s=this.backend,i=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.");s.beginCompute(e);for(const t of a){if(!1===i.has(t)){const e=()=>{t.removeEventListener("dispose",e),i.delete(t),n.delete(t),o.delete(t)};t.addEventListener("dispose",e);const r=t.onInitFunction;null!==r&&r.call(t,{renderer:this})}o.updateForCompute(t),n.updateForCompute(t);const r=n.getForCompute(t),a=i.getForCompute(t,r);s.compute(e,t,r,a)}s.finishCompute(e),t.renderId=r}async computeAsync(e){!1===this._initialized&&await this.init(),this.compute(e),await this.backend.resolveTimestampAsync(e,"compute")}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)}hasInitialized(){return this._initialized}async initTextureAsync(e){!1===this._initialized&&await this.init(),this._textures.updateTexture(e)}initTexture(e){!1===this._initialized&&console.warn("THREE.Renderer: .initTexture() called before the backend is initialized. Try using .initTextureAsync() instead."),this._textures.updateTexture(e)}copyFramebufferToTexture(e,t=null){if(null!==t)if(t.isVector2)t=b_.set(t.x,t.y,e.image.width,e.image.height).floor();else{if(!t.isVector4)return void console.error("THREE.Renderer.copyFramebufferToTexture: Invalid rectangle.");t=b_.copy(t).floor()}else t=b_.set(0,0,e.image.width,e.image.height);let r,s=this._currentRenderContext;null!==s?r=s.renderTarget:(r=this._renderTarget||this._getFrameBufferTarget(),null!==r&&(this._textures.updateRenderTarget(r),s=this._textures.get(r))),this._textures.updateTexture(e,{renderTarget:r}),this.backend.copyFramebufferToTexture(e,s,t)}copyTextureToTexture(e,t,r=null,s=null,i=0){this._textures.updateTexture(e),this._textures.updateTexture(t),this.backend.copyTextureToTexture(e,t,r,s,i)}async readRenderTargetPixelsAsync(e,t,r,s,i,n=0,o=0){return this.backend.copyTextureToBuffer(e.textures[n],t,r,s,i,o)}_projectObject(e,t,r,s,i){if(!1===e.visible)return;if(e.layers.test(t.layers))if(e.isGroup)r=e.renderOrder,e.isClippingGroup&&e.enabled&&(i=i.getGroupContext(e));else if(e.isLOD)!0===e.autoUpdate&&e.update(t);else if(e.isLight)s.pushLight(e);else if(e.isSprite){if(!e.frustumCulled||f_.intersectsSprite(e)){!0===this.sortObjects&&b_.setFromMatrixPosition(e.matrixWorld).applyMatrix4(y_);const{geometry:t,material:n}=e;n.visible&&s.push(e,t,n,r,b_.z,null,i)}}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||f_.intersectsObject(e))){const{geometry:t,material:n}=e;if(!0===this.sortObjects&&(null===t.boundingSphere&&t.computeBoundingSphere(),b_.copy(t.boundingSphere.center).applyMatrix4(e.matrixWorld).applyMatrix4(y_)),Array.isArray(n)){const o=t.groups;for(let a=0,u=o.length;a0){for(const{material:e}of t)e.side=T;this._renderObjects(t,r,s,i,"backSide");for(const{material:e}of t)e.side=ke;this._renderObjects(e,r,s,i);for(const{material:e}of t)e.side=le}else this._renderObjects(e,r,s,i)}_renderObjects(e,t,r,s,i=null){for(let n=0,o=e.length;n0,e.isShadowPassMaterial&&(e.side=null===i.shadowSide?i.side:i.shadowSide,i.depthNode&&i.depthNode.isNode&&(c=e.depthNode,e.depthNode=i.depthNode),i.castShadowNode&&i.castShadowNode.isNode&&(d=e.colorNode,e.colorNode=i.castShadowNode)),i=e}!0===i.transparent&&i.side===le&&!1===i.forceSinglePass?(i.side=T,this._handleObjectFunction(e,i,t,r,o,n,a,"backSide"),i.side=ke,this._handleObjectFunction(e,i,t,r,o,n,a,u),i.side=le):this._handleObjectFunction(e,i,t,r,o,n,a,u),void 0!==l&&(t.overrideMaterial.positionNode=l),void 0!==c&&(t.overrideMaterial.depthNode=c),void 0!==d&&(t.overrideMaterial.colorNode=d),e.onAfterRender(this,t,r,s,i,n)}_renderObjectDirect(e,t,r,s,i,n,o,a){const u=this._objects.get(e,t,r,s,i,this._currentRenderContext,o,a);u.drawRange=e.geometry.drawRange,u.group=n;const l=this._nodes.needsRefresh(u);if(l&&(this._nodes.updateBefore(u),this._geometries.updateForRender(u),this._nodes.updateForRender(u),this._bindings.updateForRender(u)),this._pipelines.updateForRender(u),null!==this._currentRenderBundle){this.backend.get(this._currentRenderBundle).renderObjects.push(u),u.bundle=this._currentRenderBundle.bundleGroup}this.backend.draw(u,this.info),l&&this._nodes.updateAfter(u)}_createObjectPipeline(e,t,r,s,i,n,o,a){const u=this._objects.get(e,t,r,s,i,this._currentRenderContext,o,a);u.drawRange=e.geometry.drawRange,u.group=n,this._nodes.updateBefore(u),this._geometries.updateForRender(u),this._nodes.updateForRender(u),this._bindings.updateForRender(u),this._pipelines.getForRender(u,this._compilationPromises),this._nodes.updateAfter(u)}get compile(){return this.compileAsync}}class T_{constructor(e=""){this.name=e,this.visibility=0}setVisibility(e){this.visibility|=e}clone(){return Object.assign(new this.constructor,this)}}class __ extends T_{constructor(e,t=null){super(e),this.isBuffer=!0,this.bytesPerElement=Float32Array.BYTES_PER_ELEMENT,this._buffer=t}get byteLength(){return(e=this._buffer.byteLength)+($g-e%$g)%$g;var e}get buffer(){return this._buffer}update(){return!0}}class v_ extends __{constructor(e,t=null){super(e,t),this.isUniformBuffer=!0}}let N_=0;class S_ extends v_{constructor(e,t){super("UniformBuffer_"+N_++,e?e.value:null),this.nodeUniform=e,this.groupNode=t}get buffer(){return this.nodeUniform.value}}class A_ extends v_{constructor(e){super(e),this.isUniformsGroup=!0,this._values=null,this.uniforms=[]}addUniform(e){return this.uniforms.push(e),this}removeUniform(e){const t=this.uniforms.indexOf(e);return-1!==t&&this.uniforms.splice(t,1),this}get values(){return null===this._values&&(this._values=Array.from(this.buffer)),this._values}get buffer(){let e=this._buffer;if(null===e){const t=this.byteLength;e=new Float32Array(new ArrayBuffer(t)),this._buffer=e}return e}get byteLength(){let e=0;for(let t=0,r=this.uniforms.length;t0?s:"";t=`${e.name} {\n\t${r} ${i.name}[${n}];\n};\n`}else{t=`${this.getVectorType(i.type)} ${this.getPropertyName(i,e)};`,n=!0}const o=i.node.precision;if(null!==o&&(t=P_[o]+" "+t),n){t="\t"+t;const e=i.groupNode.name;(s[e]||(s[e]=[])).push(t)}else t="uniform "+t,r.push(t)}let i="";for(const t in s){const r=s[t];i+=this._getGLSLUniformStruct(e+"_"+t,r.join("\n"))+"\n"}return i+=r.join("\n"),i}getTypeFromAttribute(e){let t=super.getTypeFromAttribute(e);if(/^[iu]/.test(t)&&e.gpuType!==x){let r=e;e.isInterleavedBufferAttribute&&(r=e.data);const s=r.array;!1==(s instanceof Uint32Array||s instanceof Int32Array)&&(t=t.slice(1))}return t}getAttributes(e){let t="";if("vertex"===e||"compute"===e){const e=this.getAttributesArray();let r=0;for(const s of e)t+=`layout( location = ${r++} ) in ${s.type} ${s.name};\n`}return t}getStructMembers(e){const t=[],r=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,r=this.shaderStage){const s=this.extensions[r]||(this.extensions[r]=new Map);!1===s.has(e)&&s.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 r=this.extensions[e];if(void 0!==r)for(const{name:e,behavior:s}of r.values())t.push(`#extension ${e} : ${s}`);return t.join("\n")}getClipDistance(){return"gl_ClipDistance"}isAvailable(e){let t=I_[e];if(void 0===t){let r;switch(t=!1,e){case"float32Filterable":r="OES_texture_float_linear";break;case"clipDistance":r="WEBGL_clip_cull_distance"}if(void 0!==r){const e=this.renderer.backend.extensions;e.has(r)&&(e.get(r),t=!0)}I_[e]=t}return t}isFlipY(){return!0}enableHardwareClipping(e){this.enableExtension("GL_ANGLE_clip_cull_distance","require"),this.builtins.vertex.push(`out float gl_ClipDistance[ ${e} ]`)}registerTransform(e,t){this.transforms.push({varyingName:e,attributeNode:t})}getTransforms(){const e=this.transforms;let t="";for(let r=0;r0&&(r+="\n"),r+=`\t// flow -> ${n}\n\t`),r+=`${s.code}\n\t`,e===i&&"compute"!==t&&(r+="// result\n\t","vertex"===t?(r+="gl_Position = ",r+=`${s.result};`):"fragment"===t&&(e.outputNode.isOutputStructNode||(r+="fragColor = ",r+=`${s.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=r}null!==this.material?(this.vertexShader=this._getGLSLVertexCode(e.vertex),this.fragmentShader=this._getGLSLFragmentCode(e.fragment)):this.computeShader=this._getGLSLVertexCode(e.compute)}getUniformFromNode(e,t,r,s=null){const i=super.getUniformFromNode(e,t,r,s),n=this.getDataFromNode(e,r,this.globalCache);let o=n.uniformGPU;if(void 0===o){const s=e.groupNode,a=s.name,u=this.getBindGroupArray(a,r);if("texture"===t)o=new M_(i.name,i.node,s),u.push(o);else if("cubeTexture"===t)o=new B_(i.name,i.node,s),u.push(o);else if("texture3D"===t)o=new U_(i.name,i.node,s),u.push(o);else if("buffer"===t){e.name=`NodeBuffer_${e.id}`,i.name=`buffer${e.id}`;const t=new S_(e,s);t.name=e.name,u.push(t),o=t}else{const e=this.uniformGroups[r]||(this.uniformGroups[r]={});let n=e[a];void 0===n&&(n=new C_(r+"_"+a,s),e[a]=n,u.push(n)),o=this.getNodeUniform(i,t),n.addUniform(o)}n.uniformGPU=o}return i}}let V_=null,O_=null;class G_{constructor(e={}){this.parameters=Object.assign({},e),this.data=new WeakMap,this.renderer=null,this.domElement=null}async init(e){this.renderer=e}get coordinateSystem(){}beginRender(){}finishRender(){}beginCompute(){}finishCompute(){}draw(){}compute(){}createProgram(){}destroyProgram(){}createBindings(){}updateBindings(){}updateBinding(){}createRenderPipeline(){}createComputePipeline(){}needsRenderUpdate(){}getRenderCacheKey(){}createNodeBuilder(){}createSampler(){}destroySampler(){}createDefaultTexture(){}createTexture(){}updateTexture(){}generateMipmaps(){}destroyTexture(){}async copyTextureToBuffer(){}copyTextureToTexture(){}copyFramebufferToTexture(){}createAttribute(){}createIndexAttribute(){}createStorageAttribute(){}updateAttribute(){}destroyAttribute(){}getContext(){}updateSize(){}updateViewport(){}isOccluded(){}async resolveTimestampAsync(){}async waitForGPU(){}async getArrayBufferAsync(){}async hasFeatureAsync(){}hasFeature(){}getMaxAnisotropy(){}getDrawingBufferSize(){return V_=V_||new t,this.renderer.getDrawingBufferSize(V_)}setScissorTest(){}getClearColor(){const e=this.renderer;return O_=O_||new ym,e.getClearColor(O_),O_.getRGB(O_,this.renderer.currentColorSpace),O_}getDomElement(){let e=this.domElement;return null===e&&(e=void 0!==this.parameters.canvas?this.parameters.canvas:Je(),"setAttribute"in e&&e.setAttribute("data-engine",`three.js r${Ve} webgpu`),this.domElement=e),e}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)}dispose(){}}let k_=0;class z_{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 $_{constructor(e){this.backend=e}createAttribute(e,t){const r=this.backend,{gl:s}=r,i=e.array,n=e.usage||s.STATIC_DRAW,o=e.isInterleavedBufferAttribute?e.data:e,a=r.get(o);let u,l=a.bufferGPU;if(void 0===l&&(l=this._createBuffer(s,t,i,n),a.bufferGPU=l,a.bufferType=t,a.version=o.version),i instanceof Float32Array)u=s.FLOAT;else if(i instanceof Uint16Array)u=e.isFloat16BufferAttribute?s.HALF_FLOAT:s.UNSIGNED_SHORT;else if(i instanceof Int16Array)u=s.SHORT;else if(i instanceof Uint32Array)u=s.UNSIGNED_INT;else if(i instanceof Int32Array)u=s.INT;else if(i instanceof Int8Array)u=s.BYTE;else if(i instanceof Uint8Array)u=s.UNSIGNED_BYTE;else{if(!(i instanceof Uint8ClampedArray))throw new Error("THREE.WebGLBackend: Unsupported buffer data format: "+i);u=s.UNSIGNED_BYTE}let d={bufferGPU:l,bufferType:t,type:u,byteLength:i.byteLength,bytesPerElement:i.BYTES_PER_ELEMENT,version:e.version,pbo:e.pbo,isInteger:u===s.INT||u===s.UNSIGNED_INT||e.gpuType===x,id:k_++};if(e.isStorageBufferAttribute||e.isStorageInstancedBufferAttribute){const e=this._createBuffer(s,t,i,n);d=new z_(d,e)}r.set(e,d)}updateAttribute(e){const t=this.backend,{gl:r}=t,s=e.array,i=e.isInterleavedBufferAttribute?e.data:e,n=t.get(i),o=n.bufferType,a=e.isInterleavedBufferAttribute?e.data.updateRanges:e.updateRanges;if(r.bindBuffer(o,n.bufferGPU),0===a.length)r.bufferSubData(o,0,s);else{for(let e=0,t=a.length;e1?this.enable(s.SAMPLE_ALPHA_TO_COVERAGE):this.disable(s.SAMPLE_ALPHA_TO_COVERAGE),r>0&&this.currentClippingPlanes!==r){const e=12288;for(let t=0;t<8;t++)t{!function i(){const n=e.clientWaitSync(t,e.SYNC_FLUSH_COMMANDS_BIT,0);if(n===e.WAIT_FAILED)return e.deleteSync(t),void s();n!==e.TIMEOUT_EXPIRED?(e.deleteSync(t),r()):requestAnimationFrame(i)}()}))}}let X_,Y_,Q_,Z_=!1;class J_{constructor(e){this.backend=e,this.gl=e.gl,this.extensions=e.extensions,this.defaultTextures={},!1===Z_&&(this._init(),Z_=!0)}_init(){const e=this.gl;X_={[cr]:e.REPEAT,[hr]:e.CLAMP_TO_EDGE,[pr]:e.MIRRORED_REPEAT},Y_={[gr]:e.NEAREST,[mr]:e.NEAREST_MIPMAP_NEAREST,[De]:e.NEAREST_MIPMAP_LINEAR,[z]:e.LINEAR,[Ie]:e.LINEAR_MIPMAP_NEAREST,[M]:e.LINEAR_MIPMAP_LINEAR},Q_={[fr]:e.NEVER,[yr]:e.ALWAYS,[Ce]:e.LESS,[br]:e.LEQUAL,[xr]:e.EQUAL,[Tr]:e.GEQUAL,[_r]:e.GREATER,[vr]:e.NOTEQUAL}}getGLTextureType(e){const{gl:t}=this;let r;return r=!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,r}getInternalFormat(e,t,r,s,i=!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&&(r===n.FLOAT&&(a=n.R32F),r===n.HALF_FLOAT&&(a=n.R16F),r===n.UNSIGNED_BYTE&&(a=n.R8),r===n.UNSIGNED_SHORT&&(a=n.R16),r===n.UNSIGNED_INT&&(a=n.R32UI),r===n.BYTE&&(a=n.R8I),r===n.SHORT&&(a=n.R16I),r===n.INT&&(a=n.R32I)),t===n.RED_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.R8UI),r===n.UNSIGNED_SHORT&&(a=n.R16UI),r===n.UNSIGNED_INT&&(a=n.R32UI),r===n.BYTE&&(a=n.R8I),r===n.SHORT&&(a=n.R16I),r===n.INT&&(a=n.R32I)),t===n.RG&&(r===n.FLOAT&&(a=n.RG32F),r===n.HALF_FLOAT&&(a=n.RG16F),r===n.UNSIGNED_BYTE&&(a=n.RG8),r===n.UNSIGNED_SHORT&&(a=n.RG16),r===n.UNSIGNED_INT&&(a=n.RG32UI),r===n.BYTE&&(a=n.RG8I),r===n.SHORT&&(a=n.RG16I),r===n.INT&&(a=n.RG32I)),t===n.RG_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RG8UI),r===n.UNSIGNED_SHORT&&(a=n.RG16UI),r===n.UNSIGNED_INT&&(a=n.RG32UI),r===n.BYTE&&(a=n.RG8I),r===n.SHORT&&(a=n.RG16I),r===n.INT&&(a=n.RG32I)),t===n.RGB&&(r===n.FLOAT&&(a=n.RGB32F),r===n.HALF_FLOAT&&(a=n.RGB16F),r===n.UNSIGNED_BYTE&&(a=n.RGB8),r===n.UNSIGNED_SHORT&&(a=n.RGB16),r===n.UNSIGNED_INT&&(a=n.RGB32UI),r===n.BYTE&&(a=n.RGB8I),r===n.SHORT&&(a=n.RGB16I),r===n.INT&&(a=n.RGB32I),r===n.UNSIGNED_BYTE&&(a=s===Oe&&!1===i?n.SRGB8:n.RGB8),r===n.UNSIGNED_SHORT_5_6_5&&(a=n.RGB565),r===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1),r===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGB4),r===n.UNSIGNED_INT_5_9_9_9_REV&&(a=n.RGB9_E5)),t===n.RGB_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RGB8UI),r===n.UNSIGNED_SHORT&&(a=n.RGB16UI),r===n.UNSIGNED_INT&&(a=n.RGB32UI),r===n.BYTE&&(a=n.RGB8I),r===n.SHORT&&(a=n.RGB16I),r===n.INT&&(a=n.RGB32I)),t===n.RGBA&&(r===n.FLOAT&&(a=n.RGBA32F),r===n.HALF_FLOAT&&(a=n.RGBA16F),r===n.UNSIGNED_BYTE&&(a=n.RGBA8),r===n.UNSIGNED_SHORT&&(a=n.RGBA16),r===n.UNSIGNED_INT&&(a=n.RGBA32UI),r===n.BYTE&&(a=n.RGBA8I),r===n.SHORT&&(a=n.RGBA16I),r===n.INT&&(a=n.RGBA32I),r===n.UNSIGNED_BYTE&&(a=s===Oe&&!1===i?n.SRGB8_ALPHA8:n.RGBA8),r===n.UNSIGNED_SHORT_4_4_4_4&&(a=n.RGBA4),r===n.UNSIGNED_SHORT_5_5_5_1&&(a=n.RGB5_A1)),t===n.RGBA_INTEGER&&(r===n.UNSIGNED_BYTE&&(a=n.RGBA8UI),r===n.UNSIGNED_SHORT&&(a=n.RGBA16UI),r===n.UNSIGNED_INT&&(a=n.RGBA32UI),r===n.BYTE&&(a=n.RGBA8I),r===n.SHORT&&(a=n.RGBA16I),r===n.INT&&(a=n.RGBA32I)),t===n.DEPTH_COMPONENT&&(r===n.UNSIGNED_INT&&(a=n.DEPTH24_STENCIL8),r===n.FLOAT&&(a=n.DEPTH_COMPONENT32F)),t===n.DEPTH_STENCIL&&r===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:r,extensions:s,backend:i}=this;r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,t.flipY),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,t.premultiplyAlpha),r.pixelStorei(r.UNPACK_ALIGNMENT,t.unpackAlignment),r.pixelStorei(r.UNPACK_COLORSPACE_CONVERSION_WEBGL,r.NONE),r.texParameteri(e,r.TEXTURE_WRAP_S,X_[t.wrapS]),r.texParameteri(e,r.TEXTURE_WRAP_T,X_[t.wrapT]),e!==r.TEXTURE_3D&&e!==r.TEXTURE_2D_ARRAY||r.texParameteri(e,r.TEXTURE_WRAP_R,X_[t.wrapR]),r.texParameteri(e,r.TEXTURE_MAG_FILTER,Y_[t.magFilter]);const n=void 0!==t.mipmaps&&t.mipmaps.length>0,o=t.minFilter===z&&n?M:t.minFilter;if(r.texParameteri(e,r.TEXTURE_MIN_FILTER,Y_[o]),t.compareFunction&&(r.texParameteri(e,r.TEXTURE_COMPARE_MODE,r.COMPARE_REF_TO_TEXTURE),r.texParameteri(e,r.TEXTURE_COMPARE_FUNC,Q_[t.compareFunction])),!0===s.has("EXT_texture_filter_anisotropic")){if(t.magFilter===gr)return;if(t.minFilter!==De&&t.minFilter!==M)return;if(t.type===E&&!1===s.has("OES_texture_float_linear"))return;if(t.anisotropy>1){const n=s.get("EXT_texture_filter_anisotropic");r.texParameterf(e,n.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(t.anisotropy,i.getMaxAnisotropy()))}}}createDefaultTexture(e){const{gl:t,backend:r,defaultTextures:s}=this,i=this.getGLTextureType(e);let n=s[i];void 0===n&&(n=t.createTexture(),r.state.bindTexture(i,n),t.texParameteri(i,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(i,t.TEXTURE_MAG_FILTER,t.NEAREST),s[i]=n),r.set(e,{textureGPU:n,glTextureType:i,isDefault:!0})}createTexture(e,t){const{gl:r,backend:s}=this,{levels:i,width:n,height:o,depth:a}=t,u=s.utils.convert(e.format,e.colorSpace),l=s.utils.convert(e.type),d=this.getInternalFormat(e.internalFormat,u,l,e.colorSpace,e.isVideoTexture),c=r.createTexture(),h=this.getGLTextureType(e);s.state.bindTexture(h,c),this.setTextureParameters(h,e),e.isDataArrayTexture||e.isCompressedArrayTexture?r.texStorage3D(r.TEXTURE_2D_ARRAY,i,d,n,o,a):e.isData3DTexture?r.texStorage3D(r.TEXTURE_3D,i,d,n,o,a):e.isVideoTexture||r.texStorage2D(h,i,d,n,o),s.set(e,{textureGPU:c,glTextureType:h,glFormat:u,glType:l,glInternalFormat:d})}copyBufferToTexture(e,t){const{gl:r,backend:s}=this,{textureGPU:i,glTextureType:n,glFormat:o,glType:a}=s.get(t),{width:u,height:l}=t.source.data;r.bindBuffer(r.PIXEL_UNPACK_BUFFER,e),s.state.bindTexture(n,i),r.pixelStorei(r.UNPACK_FLIP_Y_WEBGL,!1),r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),r.texSubImage2D(n,0,0,0,u,l,o,a,0),r.bindBuffer(r.PIXEL_UNPACK_BUFFER,null),s.state.unbindTexture()}updateTexture(e,t){const{gl:r}=this,{width:s,height:i}=t,{textureGPU:n,glTextureType:o,glFormat:a,glType:u,glInternalFormat:l}=this.backend.get(e);if(e.isRenderTargetTexture||void 0===n)return;const d=e=>e.isDataTexture?e.image.data:"undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&e instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap||e instanceof OffscreenCanvas?e:e.data;if(this.backend.state.bindTexture(o,n),this.setTextureParameters(o,e),e.isCompressedTexture){const s=e.mipmaps,i=t.image;for(let t=0;t0,c=t.renderTarget?t.renderTarget.height:this.backend.getDrawingBufferSize().y;if(d){const r=0!==o||0!==a;let d,h;if(!0===e.isDepthTexture?(d=s.DEPTH_BUFFER_BIT,h=s.DEPTH_ATTACHMENT,t.stencil&&(d|=s.STENCIL_BUFFER_BIT)):(d=s.COLOR_BUFFER_BIT,h=s.COLOR_ATTACHMENT0),r){const e=this.backend.get(t.renderTarget),r=e.framebuffers[t.getCacheKey()],h=e.msaaFrameBuffer;i.bindFramebuffer(s.DRAW_FRAMEBUFFER,r),i.bindFramebuffer(s.READ_FRAMEBUFFER,h);const p=c-a-l;s.blitFramebuffer(o,p,o+u,p+l,o,p,o+u,p+l,d,s.NEAREST),i.bindFramebuffer(s.READ_FRAMEBUFFER,r),i.bindTexture(s.TEXTURE_2D,n),s.copyTexSubImage2D(s.TEXTURE_2D,0,0,0,o,p,u,l),i.unbindTexture()}else{const e=s.createFramebuffer();i.bindFramebuffer(s.DRAW_FRAMEBUFFER,e),s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,h,s.TEXTURE_2D,n,0),s.blitFramebuffer(0,0,u,l,0,0,u,l,d,s.NEAREST),s.deleteFramebuffer(e)}}else i.bindTexture(s.TEXTURE_2D,n),s.copyTexSubImage2D(s.TEXTURE_2D,0,0,0,o,c-l-a,u,l),i.unbindTexture();e.generateMipmaps&&this.generateMipmaps(e),this.backend._setFramebuffer(t)}setupRenderBufferStorage(e,t){const{gl:r}=this,s=t.renderTarget,{samples:i,depthTexture:n,depthBuffer:o,stencilBuffer:a,width:u,height:l}=s;if(r.bindRenderbuffer(r.RENDERBUFFER,e),o&&!a){let t=r.DEPTH_COMPONENT24;i>0?(n&&n.isDepthTexture&&n.type===r.FLOAT&&(t=r.DEPTH_COMPONENT32F),r.renderbufferStorageMultisample(r.RENDERBUFFER,i,t,u,l)):r.renderbufferStorage(r.RENDERBUFFER,t,u,l),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_ATTACHMENT,r.RENDERBUFFER,e)}else o&&a&&(i>0?r.renderbufferStorageMultisample(r.RENDERBUFFER,i,r.DEPTH24_STENCIL8,u,l):r.renderbufferStorage(r.RENDERBUFFER,r.DEPTH_STENCIL,u,l),r.framebufferRenderbuffer(r.FRAMEBUFFER,r.DEPTH_STENCIL_ATTACHMENT,r.RENDERBUFFER,e))}async copyTextureToBuffer(e,t,r,s,i,n){const{backend:o,gl:a}=this,{textureGPU:u,glFormat:l,glType:d}=this.backend.get(e),c=a.createFramebuffer();a.bindFramebuffer(a.READ_FRAMEBUFFER,c);const h=e.isCubeTexture?a.TEXTURE_CUBE_MAP_POSITIVE_X+n:a.TEXTURE_2D;a.framebufferTexture2D(a.READ_FRAMEBUFFER,a.COLOR_ATTACHMENT0,h,u,0);const p=this._getTypedArrayType(d),g=s*i*this._getBytesPerTexel(d,l),m=a.createBuffer();a.bindBuffer(a.PIXEL_PACK_BUFFER,m),a.bufferData(a.PIXEL_PACK_BUFFER,g,a.STREAM_READ),a.readPixels(t,r,s,i,l,d,0),a.bindBuffer(a.PIXEL_PACK_BUFFER,null),await o.utils._clientWaitAsync();const f=new p(g/p.BYTES_PER_ELEMENT);return a.bindBuffer(a.PIXEL_PACK_BUFFER,m),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:r}=this;let s=0;return e===r.UNSIGNED_BYTE&&(s=1),e!==r.UNSIGNED_SHORT_4_4_4_4&&e!==r.UNSIGNED_SHORT_5_5_5_1&&e!==r.UNSIGNED_SHORT_5_6_5&&e!==r.UNSIGNED_SHORT&&e!==r.HALF_FLOAT||(s=2),e!==r.UNSIGNED_INT&&e!==r.FLOAT||(s=4),t===r.RGBA?4*s:t===r.RGB?3*s:t===r.ALPHA?s:void 0}}class ev{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 tv{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 r=t.get("EXT_texture_filter_anisotropic");this.maxAnisotropy=e.getParameter(r.MAX_TEXTURE_MAX_ANISOTROPY_EXT)}else this.maxAnisotropy=0;return this.maxAnisotropy}}const rv={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 sv{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:r,mode:s,object:i,type:n,info:o,index:a}=this;0!==a?r.drawElements(s,t,n,e):r.drawArrays(s,e,t),o.update(i,t,s,1)}renderInstances(e,t,r){const{gl:s,mode:i,type:n,index:o,object:a,info:u}=this;0!==r&&(0!==o?s.drawElementsInstanced(i,t,n,e,r):s.drawArraysInstanced(i,e,t,r),u.update(a,t,i,r))}renderMultiDraw(e,t,r){const{extensions:s,mode:i,object:n,info:o}=this;if(0===r)return;const a=s.get("WEBGL_multi_draw");if(null===a)for(let s=0;s0)){const e=t.queryQueue.shift();this.initTimestampQuery(e)}}async resolveTimestampAsync(e,t="render"){if(!this.disjoint||!this.trackTimestamp)return;const r=this.get(e);r.gpuQueries||(r.gpuQueries=[]);for(let e=0;e0&&(r.currentOcclusionQueries=r.occlusionQueries,r.currentOcclusionQueryObjects=r.occlusionQueryObjects,r.lastOcclusionObject=null,r.occlusionQueries=new Array(s),r.occlusionQueryObjects=new Array(s),r.occlusionQueryIndex=0)}finishRender(e){const{gl:t,state:r}=this,s=this.get(e),i=s.previousContext,n=e.occlusionQueryCount;n>0&&(n>s.occlusionQueryIndex&&t.endQuery(t.ANY_SAMPLES_PASSED),this.resolveOccludedAsync(e));const o=e.textures;if(null!==o)for(let e=0;e0){const i=s.framebuffers[e.getCacheKey()],n=t.COLOR_BUFFER_BIT,o=s.msaaFrameBuffer,a=e.textures;r.bindFramebuffer(t.READ_FRAMEBUFFER,o),r.bindFramebuffer(t.DRAW_FRAMEBUFFER,i);for(let r=0;r{let o=0;for(let t=0;t1?f.renderInstances(x,y,b):f.render(x,y),a.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)}async copyTextureToBuffer(e,t,r,s,i,n){return this.textureUtils.copyTextureToBuffer(e,t,r,s,i,n)}createSampler(){}destroySampler(){}createNodeBuilder(e,t){return new L_(e,t)}createProgram(e){const t=this.gl,{stage:r,code:s}=e,i="fragment"===r?t.createShader(t.FRAGMENT_SHADER):t.createShader(t.VERTEX_SHADER);t.shaderSource(i,s),t.compileShader(i),this.set(e,{shaderGPU:i})}destroyProgram(e){this.delete(e)}createRenderPipeline(e,t){const r=this.gl,s=e.pipeline,{fragmentProgram:i,vertexProgram:n}=s,o=r.createProgram(),a=this.get(i).shaderGPU,u=this.get(n).shaderGPU;if(r.attachShader(o,a),r.attachShader(o,u),r.linkProgram(o),this.set(s,{programGPU:o,fragmentShader:a,vertexShader:u}),null!==t&&this.parallel){const i=new Promise((t=>{const i=this.parallel,n=()=>{r.getProgramParameter(o,i.COMPLETION_STATUS_KHR)?(this._completeCompile(e,s),t()):requestAnimationFrame(n)};n()}));t.push(i)}else this._completeCompile(e,s)}_handleSource(e,t){const r=e.split("\n"),s=[],i=Math.max(t-6,0),n=Math.min(t+6,r.length);for(let e=i;e":" "} ${i}: ${r[e]}`)}return s.join("\n")}_getShaderErrors(e,t,r){const s=e.getShaderParameter(t,e.COMPILE_STATUS),i=e.getShaderInfoLog(t).trim();if(s&&""===i)return"";const n=/ERROR: 0:(\d+)/.exec(i);if(n){const s=parseInt(n[1]);return r.toUpperCase()+"\n\n"+i+"\n\n"+this._handleSource(e.getShaderSource(t),s)}return i}_logProgramError(e,t,r){if(this.renderer.debug.checkShaderErrors){const s=this.gl,i=s.getProgramInfoLog(e).trim();if(!1===s.getProgramParameter(e,s.LINK_STATUS))if("function"==typeof this.renderer.debug.onShaderError)this.renderer.debug.onShaderError(s,e,r,t);else{const n=this._getShaderErrors(s,r,"vertex"),o=this._getShaderErrors(s,t,"fragment");console.error("THREE.WebGLProgram: Shader Error "+s.getError()+" - VALIDATE_STATUS "+s.getProgramParameter(e,s.VALIDATE_STATUS)+"\n\nProgram Info Log: "+i+"\n"+n+"\n"+o)}else""!==i&&console.warn("THREE.WebGLProgram: Program Info Log:",i)}}_completeCompile(e,t){const{state:r,gl:s}=this,i=this.get(t),{programGPU:n,fragmentShader:o,vertexShader:a}=i;!1===s.getProgramParameter(n,s.LINK_STATUS)&&this._logProgramError(n,o,a),r.useProgram(n);const u=e.getBindings();this._setupBindings(u,n),this.set(t,{programGPU:n})}createComputePipeline(e,t){const{state:r,gl:s}=this,i={stage:"fragment",code:"#version 300 es\nprecision highp float;\nvoid main() {}"};this.createProgram(i);const{computeProgram:n}=e,o=s.createProgram(),a=this.get(i).shaderGPU,u=this.get(n).shaderGPU,l=n.transforms,d=[],c=[];for(let e=0;erv[t]===e)),r=this.extensions;for(let e=0;e0){if(void 0===h){const s=[];h=t.createFramebuffer(),r.bindFramebuffer(t.FRAMEBUFFER,h);const i=[],l=e.textures;for(let r=0;r,\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:lv,stripIndexFormat:Rv},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:lv,stripIndexFormat:Rv},layout:"auto"}),this.flipYPipelines[e]=t),t}flipY(e,t,r=0){const s=t.format,{width:i,height:n}=t.size,o=this.getTransferPipeline(s),a=this.getFlipYPipeline(s),u=this.device.createTexture({size:{width:i,height:n,depthOrArrayLayers:1},format:s,usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.TEXTURE_BINDING}),l=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:xN,baseArrayLayer:r}),d=u.createView({baseMipLevel:0,mipLevelCount:1,dimension:xN,baseArrayLayer:0}),c=this.device.createCommandEncoder({}),h=(e,t,r)=>{const s=e.getBindGroupLayout(0),i=this.device.createBindGroup({layout:s,entries:[{binding:0,resource:this.flipYSampler},{binding:1,resource:t}]}),n=c.beginRenderPass({colorAttachments:[{view:r,loadOp:Tv,storeOp:bv,clearValue:[0,0,0,0]}]});n.setPipeline(e),n.setBindGroup(0,i),n.draw(4,1,0,0),n.end()};h(o,l,d),h(a,d,l),this.device.queue.submit([c.finish()]),u.destroy()}generateMipmaps(e,t,r=0){const s=this.get(e);void 0===s.useCount&&(s.useCount=0,s.layers=[]);const i=s.layers[r]||this._mipmapCreateBundles(e,t,r),n=this.device.createCommandEncoder({});this._mipmapRunBundles(n,i),this.device.queue.submit([n.finish()]),0!==s.useCount&&(s.layers[r]=i),s.useCount++}_mipmapCreateBundles(e,t,r){const s=this.getTransferPipeline(t.format),i=s.getBindGroupLayout(0);let n=e.createView({baseMipLevel:0,mipLevelCount:1,dimension:xN,baseArrayLayer:r});const o=[];for(let a=1;a1;for(let o=0;o]*\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/i,VN=/([a-z_0-9]+)\s*:\s*([a-z_0-9]+(?:<[\s\S]+?>)?)/gi,ON={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_depth_multisampled_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 GN extends KT{constructor(e){const{type:t,inputs:r,name:s,inputsCode:i,blockCode:n,outputType:o}=(e=>{const t=(e=e.trim()).match(LN);if(null!==t&&4===t.length){const r=t[2],s=[];let i=null;for(;null!==(i=VN.exec(r));)s.push({name:i[1],type:i[2]});const n=[];for(let e=0;e "+this.outputType:"";return`fn ${e} ( ${this.inputsCode.trim()} ) ${t}`+this.blockCode}}class kN extends qT{parseFunction(e){return new GN(e)}}const zN="undefined"!=typeof self?self.GPUShaderStage:{VERTEX:1,FRAGMENT:2,COMPUTE:4},$N={[Es.READ_ONLY]:"read",[Es.WRITE_ONLY]:"write",[Es.READ_WRITE]:"read_write"},HN={[cr]:"repeat",[hr]:"clamp",[pr]:"mirror"},WN={vertex:zN?zN.VERTEX:1,fragment:zN?zN.FRAGMENT:2,compute:zN?zN.COMPUTE:4},jN={instance:!0,swizzleAssign:!1,storageBuffer:!0},qN={"^^":"tsl_xor"},KN={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",mat3:"mat3x3",mat4:"mat4x4"},XN={},YN={tsl_xor:new my("fn tsl_xor( a : bool, b : bool ) -> bool { return ( a || b ) && !( a && b ); }"),mod_float:new my("fn tsl_mod_float( x : f32, y : f32 ) -> f32 { return x - y * floor( x / y ); }"),mod_vec2:new my("fn tsl_mod_vec2( x : vec2f, y : vec2f ) -> vec2f { return x - y * floor( x / y ); }"),mod_vec3:new my("fn tsl_mod_vec3( x : vec3f, y : vec3f ) -> vec3f { return x - y * floor( x / y ); }"),mod_vec4:new my("fn tsl_mod_vec4( x : vec4f, y : vec4f ) -> vec4f { return x - y * floor( x / y ); }"),equals_bool:new my("fn tsl_equals_bool( a : bool, b : bool ) -> bool { return a == b; }"),equals_bvec2:new my("fn tsl_equals_bvec2( a : vec2f, b : vec2f ) -> vec2 { return vec2( a.x == b.x, a.y == b.y ); }"),equals_bvec3:new my("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 my("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_float:new my("fn tsl_repeatWrapping_float( coord: f32 ) -> f32 { return fract( coord ); }"),mirrorWrapping_float:new my("fn tsl_mirrorWrapping_float( coord: f32 ) -> f32 { let mirrored = fract( coord * 0.5 ) * 2.0; return 1.0 - abs( 1.0 - mirrored ); }"),clampWrapping_float:new my("fn tsl_clampWrapping_float( coord: f32 ) -> f32 { return clamp( coord, 0.0, 1.0 ); }"),biquadraticTexture:new my("\nfn tsl_biquadraticTexture( map : texture_2d, coord : vec2f, iRes : vec2u, level : u32 ) -> vec4f {\n\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, vec2u( iuv + vec2( 0.5, 0.5 ) ) % iRes, level );\n\tlet rg2 = textureLoad( map, vec2u( iuv + vec2( 1.5, 0.5 ) ) % iRes, level );\n\tlet rg3 = textureLoad( map, vec2u( iuv + vec2( 0.5, 1.5 ) ) % iRes, level );\n\tlet rg4 = textureLoad( map, vec2u( 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")},QN={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"};"undefined"!=typeof navigator&&/Windows/g.test(navigator.userAgent)&&(YN.pow_float=new my("fn tsl_pow_float( a : f32, b : f32 ) -> f32 { return select( -pow( -a, b ), pow( a, b ), a > 0.0 ); }"),YN.pow_vec2=new my("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 ) ); }",[YN.pow_float]),YN.pow_vec3=new my("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 ) ); }",[YN.pow_float]),YN.pow_vec4=new my("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 ) ); }",[YN.pow_float]),QN.pow_float="tsl_pow_float",QN.pow_vec2="tsl_pow_vec2",QN.pow_vec3="tsl_pow_vec3",QN.pow_vec4="tsl_pow_vec4");let ZN="";!0!==("undefined"!=typeof navigator&&/Firefox|Deno/g.test(navigator.userAgent))&&(ZN+="diagnostic( off, derivative_uniformity );\n");class JN extends PT{constructor(e,t){super(e,t,new kN),this.uniformGroups={},this.builtins={},this.directives={},this.scopedArrays=new Map}needsToWorkingColorSpace(e){return!0===e.isVideoTexture&&e.colorSpace!==y}_generateTextureSample(e,t,r,s,i=this.shaderStage){return"fragment"===i?s?`textureSample( ${t}, ${t}_sampler, ${r}, ${s} )`:`textureSample( ${t}, ${t}_sampler, ${r} )`:this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,r):this.generateTextureLod(e,t,r,s,"0")}_generateVideoSample(e,t,r=this.shaderStage){if("fragment"===r)return`textureSampleBaseClampToEdge( ${e}, ${e}_sampler, vec2( ${t}.x, 1.0 - ${t}.y ) )`;console.error(`WebGPURenderer: THREE.VideoTexture does not support ${r} shader.`)}_generateTextureSampleLevel(e,t,r,s,i,n=this.shaderStage){return"fragment"!==n&&"compute"!==n||!1!==this.isUnfilterable(e)?this.isFilteredTexture(e)?this.generateFilteredTexture(e,t,r,s):this.generateTextureLod(e,t,r,i,s):`textureSampleLevel( ${t}, ${t}_sampler, ${r}, ${s} )`}generateWrapFunction(e){const t=`tsl_coord_${HN[e.wrapS]}S_${HN[e.wrapT]}_${e.isData3DTexture?"3d":"2d"}T`;let r=XN[t];if(void 0===r){const s=[],i=e.isData3DTexture?"vec3f":"vec2f";let n=`fn ${t}( coord : ${i} ) -> ${i} {\n\n\treturn ${i}(\n`;const o=(e,t)=>{e===cr?(s.push(YN.repeatWrapping_float),n+=`\t\ttsl_repeatWrapping_float( coord.${t} )`):e===hr?(s.push(YN.clampWrapping_float),n+=`\t\ttsl_clampWrapping_float( coord.${t} )`):e===pr?(s.push(YN.mirrorWrapping_float),n+=`\t\ttsl_mirrorWrapping_float( coord.${t} )`):(n+=`\t\tcoord.${t}`,console.warn(`WebGPURenderer: Unsupported texture wrap type "${e}" for vertex shader.`))};o(e.wrapS,"x"),n+=",\n",o(e.wrapT,"y"),e.isData3DTexture&&(n+=",\n",o(e.wrapR,"z")),n+="\n\t);\n\n}\n",XN[t]=r=new my(n,s)}return r.build(this),t}generateTextureDimension(e,t,r){const s=this.getDataFromNode(e,this.shaderStage,this.globalCache);void 0===s.dimensionsSnippet&&(s.dimensionsSnippet={});let i=s.dimensionsSnippet[r];if(void 0===s.dimensionsSnippet[r]){let n,o;const{primarySamples:a}=this.renderer.backend.utils.getTextureSampleData(e),u=a>1;o=e.isData3DTexture?"vec3":"vec2",n=u||e.isVideoTexture||e.isStorageTexture?t:`${t}${r?`, u32( ${r} )`:""}`,i=new Ba(new mu(`textureDimensions( ${n} )`,o)),s.dimensionsSnippet[r]=i,(e.isDataArrayTexture||e.isData3DTexture)&&(s.arrayLayerCount=new Ba(new mu(`textureNumLayers(${t})`,"u32"))),e.isTextureCube&&(s.cubeFaceCount=new Ba(new mu("6u","u32")))}return i.build(this)}generateFilteredTexture(e,t,r,s="0u"){this._include("biquadraticTexture");return`tsl_biquadraticTexture( ${t}, ${this.generateWrapFunction(e)}( ${r} ), ${this.generateTextureDimension(e,t,s)}, u32( ${s} ) )`}generateTextureLod(e,t,r,s,i="0u"){const n=this.generateWrapFunction(e),o=this.generateTextureDimension(e,t,i),a=e.isData3DTexture?"vec3":"vec2",u=`${a}(${n}(${r}) * ${a}(${o}))`;return this.generateTextureLoad(e,t,u,s,i)}generateTextureLoad(e,t,r,s,i="0u"){return!0===e.isVideoTexture||!0===e.isStorageTexture?`textureLoad( ${t}, ${r} )`:s?`textureLoad( ${t}, ${r}, ${s}, u32( ${i} ) )`:`textureLoad( ${t}, ${r}, u32( ${i} ) )`}generateTextureStore(e,t,r,s){return`textureStore( ${t}, ${r}, ${s} )`}isSampleCompare(e){return!0===e.isDepthTexture&&null!==e.compareFunction}isUnfilterable(e){return"float"!==this.getComponentTypeFromTexture(e)||!this.isAvailable("float32Filterable")&&!0===e.isDataTexture&&e.type===E||!1===this.isSampleCompare(e)&&e.minFilter===gr&&e.magFilter===gr||this.renderer.backend.utils.getTextureSampleData(e).primarySamples>1}generateTexture(e,t,r,s,i=this.shaderStage){let n=null;return n=!0===e.isVideoTexture?this._generateVideoSample(t,r,i):this.isUnfilterable(e)?this.generateTextureLod(e,t,r,s,"0",i):this._generateTextureSample(e,t,r,s,i),n}generateTextureGrad(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleGrad( ${t}, ${t}_sampler, ${r}, ${s[0]}, ${s[1]} )`;console.error(`WebGPURenderer: THREE.TextureNode.gradient() does not support ${n} shader.`)}generateTextureCompare(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleCompare( ${t}, ${t}_sampler, ${r}, ${s} )`;console.error(`WebGPURenderer: THREE.DepthTexture.compareFunction() does not support ${n} shader.`)}generateTextureLevel(e,t,r,s,i,n=this.shaderStage){let o=null;return o=!0===e.isVideoTexture?this._generateVideoSample(t,r,n):this._generateTextureSampleLevel(e,t,r,s,i,n),o}generateTextureBias(e,t,r,s,i,n=this.shaderStage){if("fragment"===n)return`textureSampleBias( ${t}, ${t}_sampler, ${r}, ${s} )`;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,r=e.type;return"texture"===r||"cubeTexture"===r||"storageTexture"===r||"texture3D"===r?t:"buffer"===r||"storageBuffer"===r||"indirectStorageBuffer"===r?`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=qN[e];return void 0!==t?(this._include(t),t):null}getNodeAccess(e,t){return"compute"!==t?Es.READ_ONLY:e.access}getStorageAccess(e,t){return $N[this.getNodeAccess(e,t)]}getUniformFromNode(e,t,r,s=null){const i=super.getUniformFromNode(e,t,r,s),n=this.getDataFromNode(e,r,this.globalCache);if(void 0===n.uniformGPU){let s;const o=e.groupNode,a=o.name,u=this.getBindGroupArray(a,r);if("texture"===t||"cubeTexture"===t||"storageTexture"===t||"texture3D"===t){let n=null;const a=this.getNodeAccess(e,r);if("texture"===t||"storageTexture"===t?n=new M_(i.name,i.node,o,a):"cubeTexture"===t?n=new B_(i.name,i.node,o,a):"texture3D"===t&&(n=new U_(i.name,i.node,o,a)),n.store=!0===e.isStorageTextureNode,n.setVisibility(WN[r]),"fragment"!==r&&"compute"!==r||!1!==this.isUnfilterable(e.value)||!1!==n.store)u.push(n),s=[n];else{const e=new EN(`${i.name}_sampler`,i.node,o);e.setVisibility(WN[r]),u.push(e,n),s=[e,n]}}else if("buffer"===t||"storageBuffer"===t||"indirectStorageBuffer"===t){const i=new("buffer"===t?S_:BN)(e,o);i.setVisibility(WN[r]),u.push(i),s=i}else{const e=this.uniformGroups[r]||(this.uniformGroups[r]={});let n=e[a];void 0===n&&(n=new C_(a,o),n.setVisibility(WN[r]),e[a]=n,u.push(n)),s=this.getNodeUniform(i,t),n.addUniform(s)}n.uniformGPU=s}return i}getBuiltin(e,t,r,s=this.shaderStage){const i=this.builtins[s]||(this.builtins[s]=new Map);return!1===i.has(e)&&i.set(e,{name:e,property:t,type:r}),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,r=this.flowShaderNode(e),s=[];for(const e of t.inputs)s.push(e.name+" : "+this.getType(e.type));let i=`fn ${t.name}( ${s.join(", ")} ) -> ${this.getType(t.type)} {\n${r.vars}\n${r.code}\n`;return r.result&&(i+=`\treturn ${r.result};\n`),i+="\n}\n",i}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")}getClipDistance(){return"varyings.hw_clip_distances"}isFlipY(){return!1}enableDirective(e,t=this.shaderStage){(this.directives[t]||(this.directives[t]=new Set)).add(e)}getDirectives(e){const t=[],r=this.directives[e];if(void 0!==r)for(const e of r)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")}enableHardwareClipping(e){this.enableClipDistances(),this.getBuiltin("clip_distances","hw_clip_distances",`array`,"vertex")}getBuiltins(e){const t=[],r=this.builtins[e];if(void 0!==r)for(const{name:e,property:s,type:i}of r.values())t.push(`@builtin( ${e} ) ${s} : ${i}`);return t.join(",\n\t")}getScopedArray(e,t,r,s){return!1===this.scopedArrays.has(e)&&this.scopedArrays.set(e,{name:e,scope:t,bufferType:r,bufferCount:s}),e}getScopedArrays(e){if("compute"!==e)return;const t=[];for(const{name:e,scope:r,bufferType:s,bufferCount:i}of this.scopedArrays.values()){const n=this.getType(s);t.push(`var<${r}> ${e}: array< ${n}, ${i} >;`)}return t.join("\n")}getAttributes(e){const t=[];if("compute"===e&&(this.getBuiltin("global_invocation_id","globalId","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 r=this.getAttributesArray();for(let e=0,s=r.length;e`)}const s=this.getBuiltins("output");return s&&t.push("\t"+s),t.join(",\n")}getStructs(e){const t=[],r=this.structs[e];for(let e=0,s=r.length;e output : ${i};\n\n`)}return t.join("\n\n")}getVar(e,t){return`var ${t} : ${this.getType(e)}`}getVars(e){const t=[],r=this.vars[e];if(void 0!==r)for(const e of r)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 r=this.varyings,s=this.vars[e];for(let i=0;i1&&(n="_multisampled"),!0===t.isCubeTexture)s="texture_cube";else if(!0===t.isDataArrayTexture||!0===t.isCompressedArrayTexture)s="texture_2d_array";else if(!0===t.isDepthTexture)s=`texture_depth${n}_2d`;else if(!0===t.isVideoTexture)s="texture_external";else if(!0===t.isData3DTexture)s="texture_3d";else if(!0===i.node.isStorageTextureNode){s=`texture_storage_2d<${DN(t)}, ${this.getStorageAccess(i.node,e)}>`}else{s=`texture${n}_2d<${this.getComponentTypeFromTexture(t).charAt(0)}32>`}r.push(`@binding( ${o.binding++} ) @group( ${o.group} ) var ${i.name} : ${s};`)}else if("buffer"===i.type||"storageBuffer"===i.type||"indirectStorageBuffer"===i.type){const t=i.node,r=this.getType(t.bufferType),n=t.bufferCount,a=n>0&&"buffer"===i.type?", "+n:"",u=t.isAtomic?`atomic<${r}>`:`${r}`,l=`\t${i.name} : array< ${u}${a} >\n`,d=t.isStorageBufferNode?`storage, ${this.getStorageAccess(t,e)}`:"uniform";s.push(this._getWGSLStructBinding("NodeBuffer_"+t.id,l,d,o.binding++,o.group))}else{const e=this.getType(this.getVectorType(i.type)),t=i.groupNode.name;(n[t]||(n[t]={index:o.binding++,id:o.group,snippets:[]})).snippets.push(`\t${i.name} : ${e}`)}}for(const e in n){const t=n[e];i.push(this._getWGSLStructBinding(e,t.snippets.join(",\n"),"uniform",t.index,t.id))}let o=r.join("\n");return o+=s.join("\n"),o+=i.join("\n"),o}buildCode(){const e=null!==this.material?{fragment:{},vertex:{}}:{compute:{}};this.sortBindingGroups();for(const t in e){const r=e[t];r.uniforms=this.getUniforms(t),r.attributes=this.getAttributes(t),r.varyings=this.getVaryings(t),r.structs=this.getStructs(t),r.vars=this.getVars(t),r.codes=this.getCodes(t),r.directives=this.getDirectives(t),r.scopedArrays=this.getScopedArrays(t);let s="// code\n\n";s+=this.flowCode[t];const i=this.flowNodes[t],n=i[i.length-1],o=n.outputNode,a=void 0!==o&&!0===o.isOutputStructNode;for(const e of i){const i=this.getFlowData(e),u=e.name;if(u&&(s.length>0&&(s+="\n"),s+=`\t// flow -> ${u}\n`),s+=`${i.code}\n\t`,e===n&&"compute"!==t)if(s+="// result\n\n\t","vertex"===t)s+=`varyings.Vertex = ${i.result};`;else if("fragment"===t)if(a)r.returnType=o.nodeType,s+=`return ${i.result};`;else{let e="\t@location(0) color: vec4";const t=this.getBuiltins("output");t&&(e+=",\n\t"+t),r.returnType="OutputStruct",r.structs+=this._getWGSLStruct("OutputStruct",e),r.structs+="\nvar output : OutputStruct;\n\n",s+=`output.color = ${i.result};\n\n\treturn output;`}}r.flow=s}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 r;return null!==t&&(r=this._getWGSLMethod(e+"_"+t)),void 0===r&&(r=this._getWGSLMethod(e)),r||e}getType(e){return KN[e]||e}isAvailable(e){let t=jN[e];return void 0===t&&("float32Filterable"===e?t=this.renderer.hasFeature("float32-filterable"):"clipDistance"===e&&(t=this.renderer.hasFeature("clip-distances")),jN[e]=t),t}_getWGSLMethod(e){return void 0!==YN[e]&&this._include(e),QN[e]}_include(e){const t=YN[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${ZN}\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 = globalId.x + globalId.y * numWorkgroups.x * u32(${t}) + globalId.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,r,s=0,i=0){const n=e+"Struct";return`${this._getWGSLStruct(n,t)}\n@binding( ${s} ) @group( ${i} )\nvar<${r}> ${e} : ${n};`}}class eS{constructor(e){this.backend=e}getCurrentDepthStencilFormat(e){let t;return null!==e.depthTexture?t=this.getTextureFormatGPU(e.depthTexture):e.depth&&e.stencil?t=Cv.Depth24PlusStencil8:e.depth&&(t=Cv.Depth24Plus),t}getTextureFormatGPU(e){return this.backend.get(e).format}getTextureSampleData(e){let t;if(e.isFramebufferTexture)t=1;else if(e.isDepthTexture&&!e.renderTarget){const e=this.backend.renderer,r=e.getRenderTarget();t=r?r.samples:e.samples}else e.renderTarget&&(t=e.renderTarget.samples);t=t||1;const r=t>1&&null!==e.renderTarget&&!0!==e.isDepthTexture&&!0!==e.isFramebufferTexture;return{samples:t,primarySamples:r?1:t,isMSAA:r}}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?nv:e.isLineSegments||e.isMesh&&!0===t.wireframe?ov:e.isLine?av:e.isMesh?uv: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")?Cv.BGRA8Unorm:navigator.gpu.getPreferredCanvasFormat()}}const tS=new Map([[Int8Array,["sint8","snorm8"]],[Uint8Array,["uint8","unorm8"]],[Int16Array,["sint16","snorm16"]],[Uint16Array,["uint16","unorm16"]],[Int32Array,["sint32","snorm32"]],[Uint32Array,["uint32","unorm32"]],[Float32Array,["float32"]]]),rS=new Map([[Le,["float16"]]]),sS=new Map([[Int32Array,"sint32"],[Int16Array,"sint32"],[Uint32Array,"uint32"],[Uint16Array,"uint32"],[Float32Array,"float32"]]);class iS{constructor(e){this.backend=e}createAttribute(e,t){const r=this._getBufferAttribute(e),s=this.backend,i=s.get(r);let n=i.buffer;if(void 0===n){const o=s.device;let a=r.array;if(!1===e.normalized)if(a.constructor===Int16Array)a=new Int32Array(a);else if(a.constructor===Uint16Array&&(a=new Uint32Array(a),t&GPUBufferUsage.INDEX))for(let e=0;e1&&(s.multisampled=!0,r.texture.isDepthTexture||(s.sampleType=pN)),r.texture.isDepthTexture)s.sampleType=gN;else if(r.texture.isDataTexture||r.texture.isDataArrayTexture||r.texture.isData3DTexture){const e=r.texture.type;e===x?s.sampleType=mN:e===b?s.sampleType=fN:e===E&&(this.backend.hasFeature("float32-filterable")?s.sampleType=hN:s.sampleType=pN)}r.isSampledCubeTexture?s.viewDimension=_N:r.texture.isDataArrayTexture||r.texture.isCompressedArrayTexture?s.viewDimension=TN:r.isSampledTexture3D&&(s.viewDimension=vN),e.texture=s}else console.error(`WebGPUBindingUtils: Unsupported binding "${r}".`);s.push(e)}return r.createBindGroupLayout({entries:s})}createBindings(e,t,r,s=0){const{backend:i,bindGroupLayoutCache:n}=this,o=i.get(e);let a,u=n.get(e.bindingsReference);void 0===u&&(u=this.createBindingsLayout(e),n.set(e.bindingsReference,u)),r>0&&(void 0===o.groups&&(o.groups=[],o.versions=[]),o.versions[r]===s&&(a=o.groups[r])),void 0===a&&(a=this.createBindGroup(e,u),r>0&&(o.groups[r]=a,o.versions[r]=s)),o.group=a,o.layout=u}updateBinding(e){const t=this.backend,r=t.device,s=e.buffer,i=t.get(e).buffer;r.queue.writeBuffer(i,0,s,0)}createBindGroup(e,t){const r=this.backend,s=r.device;let i=0;const n=[];for(const t of e.bindings){if(t.isUniformBuffer){const e=r.get(t);if(void 0===e.buffer){const r=t.byteLength,i=GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,n=s.createBuffer({label:"bindingBuffer_"+t.name,size:r,usage:i});e.buffer=n}n.push({binding:i,resource:{buffer:e.buffer}})}else if(t.isStorageBuffer){const e=r.get(t);if(void 0===e.buffer){const s=t.attribute;e.buffer=r.get(s).buffer}n.push({binding:i,resource:{buffer:e.buffer}})}else if(t.isSampler){const e=r.get(t.texture);n.push({binding:i,resource:e.sampler})}else if(t.isSampledTexture){const e=r.get(t.texture);let o;if(void 0!==e.externalTexture)o=s.importExternalTexture({source:e.externalTexture});else{const r=t.store?1:e.texture.mipLevelCount,s=`view-${e.texture.width}-${e.texture.height}-${r}`;if(o=e[s],void 0===o){const i=NN;let n;n=t.isSampledCubeTexture?_N:t.isSampledTexture3D?vN:t.texture.isDataArrayTexture||t.texture.isCompressedArrayTexture?TN:xN,o=e[s]=e.texture.createView({aspect:i,dimension:n,mipLevelCount:r})}}n.push({binding:i,resource:o})}i++}return s.createBindGroup({label:"bindGroup_"+e.name,layout:t,entries:n})}}class oS{constructor(e){this.backend=e}_getSampleCount(e){return this.backend.utils.getSampleCountRenderContext(e)}createRenderPipeline(e,t){const{object:r,material:s,geometry:i,pipeline:n}=e,{vertexProgram:o,fragmentProgram:a}=n,u=this.backend,l=u.device,d=u.utils,c=u.get(n),h=[];for(const t of e.getBindings()){const e=u.get(t);h.push(e.layout)}const p=u.attributeUtils.createShaderVertexBuffers(e);let g;!0===s.transparent&&s.blending!==D&&(g=this._getBlending(s));let m={};!0===s.stencilWrite&&(m={compare:this._getStencilCompare(s),failOp:this._getStencilOperation(s.stencilFail),depthFailOp:this._getStencilOperation(s.stencilZFail),passOp:this._getStencilOperation(s.stencilZPass)});const f=this._getColorWriteMask(s),y=[];if(null!==e.context.textures){const t=e.context.textures;for(let e=0;e1},layout:l.createPipelineLayout({bindGroupLayouts:h})},A={},R=e.context.depth,C=e.context.stencil;if(!0!==R&&!0!==C||(!0===R&&(A.format=v,A.depthWriteEnabled=s.depthWrite,A.depthCompare=_),!0===C&&(A.stencilFront=m,A.stencilBack={},A.stencilReadMask=s.stencilFuncMask,A.stencilWriteMask=s.stencilWriteMask),S.depthStencil=A),null===t)c.pipeline=l.createRenderPipeline(S);else{const e=new Promise((e=>{l.createRenderPipelineAsync(S).then((t=>{c.pipeline=t,e()}))}));t.push(e)}}createBundleEncoder(e){const t=this.backend,{utils:r,device:s}=t,i=r.getCurrentDepthStencilFormat(e),n={label:"renderBundleEncoder",colorFormats:[r.getCurrentColorFormat(e)],depthStencilFormat:i,sampleCount:this._getSampleCount(e)};return s.createRenderBundleEncoder(n)}createComputePipeline(e,t){const r=this.backend,s=r.device,i=r.get(e.computeProgram).module,n=r.get(e),o=[];for(const e of t){const t=r.get(e);o.push(t.layout)}n.pipeline=s.createComputePipeline({compute:i,layout:s.createPipelineLayout({bindGroupLayouts:o})})}_getBlending(e){let t,r;const s=e.blending,i=e.blendSrc,n=e.blendDst,o=e.blendEquation;if(s===yt){const s=null!==e.blendSrcAlpha?e.blendSrcAlpha:i,a=null!==e.blendDstAlpha?e.blendDstAlpha:n,u=null!==e.blendEquationAlpha?e.blendEquationAlpha:o;t={srcFactor:this._getBlendFactor(i),dstFactor:this._getBlendFactor(n),operation:this._getBlendOperation(o)},r={srcFactor:this._getBlendFactor(s),dstFactor:this._getBlendFactor(a),operation:this._getBlendOperation(u)}}else{const i=(e,s,i,n)=>{t={srcFactor:e,dstFactor:s,operation:jv},r={srcFactor:i,dstFactor:n,operation:jv}};if(e.premultipliedAlpha)switch(s){case F:i(Pv,Vv,Pv,Vv);break;case Tt:i(Pv,Pv,Pv,Pv);break;case xt:i(Fv,Dv,Fv,Pv);break;case bt:i(Fv,Iv,Fv,Lv)}else switch(s){case F:i(Lv,Vv,Pv,Vv);break;case Tt:i(Lv,Pv,Lv,Pv);break;case xt:i(Fv,Dv,Fv,Pv);break;case bt:i(Fv,Iv,Fv,Iv)}}if(void 0!==t&&void 0!==r)return{color:t,alpha:r};console.error("THREE.WebGPURenderer: Invalid blending: ",s)}_getBlendFactor(e){let t;switch(e){case st:t=Fv;break;case it:t=Pv;break;case nt:t=Iv;break;case dt:t=Dv;break;case ot:t=Lv;break;case ct:t=Vv;break;case ut:t=Ov;break;case ht:t=Gv;break;case lt:t=kv;break;case pt:t=zv;break;case at:t=$v;break;case 211:t=Hv;break;case 212:t=Wv;break;default:console.error("THREE.WebGPURenderer: Blend factor not supported.",e)}return t}_getStencilCompare(e){let t;const r=e.stencilFunc;switch(r){case Br:t=dv;break;case Mr:t=yv;break;case wr:t=cv;break;case Er:t=pv;break;case Cr:t=hv;break;case Rr:t=fv;break;case Ar:t=gv;break;case Sr:t=mv;break;default:console.error("THREE.WebGPURenderer: Invalid stencil function.",r)}return t}_getStencilOperation(e){let t;switch(e){case Or:t=Jv;break;case Vr:t=eN;break;case Lr:t=tN;break;case Dr:t=rN;break;case Ir:t=sN;break;case Pr:t=iN;break;case Fr:t=nN;break;case Ur:t=oN;break;default:console.error("THREE.WebGPURenderer: Invalid stencil operation.",t)}return t}_getBlendOperation(e){let t;switch(e){case et:t=jv;break;case tt:t=qv;break;case rt:t=Kv;break;case kr:t=Xv;break;case Gr:t=Yv;break;default:console.error("THREE.WebGPUPipelineUtils: Blend equation not supported.",e)}return t}_getPrimitiveState(e,t,r){const s={},i=this.backend.utils;switch(s.topology=i.getPrimitiveTopology(e,r),null!==t.index&&!0===e.isLine&&!0!==e.isLineSegments&&(s.stripIndexFormat=t.index.array instanceof Uint16Array?Av:Rv),r.side){case ke:s.frontFace=_v,s.cullMode=Sv;break;case T:s.frontFace=_v,s.cullMode=Nv;break;case le:s.frontFace=_v,s.cullMode=vv;break;default:console.error("THREE.WebGPUPipelineUtils: Unknown material.side value.",r.side)}return s}_getColorWriteMask(e){return!0===e.colorWrite?Zv:Qv}_getDepthCompare(e){let t;if(!1===e.depthTest)t=yv;else{const r=e.depthFunc;switch(r){case Et:t=dv;break;case Ct:t=yv;break;case Rt:t=cv;break;case At:t=pv;break;case St:t=hv;break;case Nt:t=fv;break;case vt:t=gv;break;case _t:t=mv;break;default:console.error("THREE.WebGPUPipelineUtils: Invalid depth function.",r)}}return t}}class aS extends G_{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 eS(this),this.attributeUtils=new iS(this),this.bindingUtils=new nS(this),this.pipelineUtils=new oS(this),this.textureUtils=new IN(this),this.occludedResolveCache=new Map}async init(e){await super.init(e);const t=this.parameters;let r;if(void 0===t.device){const e={powerPreference:t.powerPreference},s="undefined"!=typeof navigator?await navigator.gpu.requestAdapter(e):null;if(null===s)throw new Error("WebGPUBackend: Unable to create WebGPU adapter.");const i=Object.values(RN),n=[];for(const e of i)s.features.has(e)&&n.push(e);const o={requiredFeatures:n,requiredLimits:t.requiredLimits};r=await s.requestDevice(o)}else r=t.device;r.lost.then((t=>{const r={api:"WebGPU",message:t.message||"Unknown reason",reason:t.reason||null,originalEvent:t};e.onDeviceLost(r)}));const s=void 0!==t.context?t.context:e.domElement.getContext("webgpu");this.device=r,this.context=s;const i=t.alpha?"premultiplied":"opaque";this.trackTimestamp=this.trackTimestamp&&this.hasFeature(RN.TimestampQuery),this.context.configure({device:this.device,format:this.utils.getPreferredCanvasFormat(),usage:GPUTextureUsage.RENDER_ATTACHMENT|GPUTextureUsage.COPY_SRC,alphaMode:i}),this.updateSize()}get coordinateSystem(){return l}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}]},!0!==this.renderer.depth&&!0!==this.renderer.stencil||(e.depthStencilAttachment={view:this.textureUtils.getDepthBuffer(t.depth,t.stencil).createView()});const r=e.colorAttachments[0];this.renderer.samples>0?r.view=this.colorBuffer.createView():r.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,t={}){const r=e.renderTarget,s=this.get(r);let i=s.descriptors;if(void 0===i||s.width!==r.width||s.height!==r.height||s.dimensions!==r.dimensions||s.activeMipmapLevel!==r.activeMipmapLevel||s.activeCubeFace!==e.activeCubeFace||s.samples!==r.samples||s.loadOp!==t.loadOp){i={},s.descriptors=i;const e=()=>{r.removeEventListener("dispose",e),this.delete(r)};r.addEventListener("dispose",e)}const n=e.getCacheKey();let o=i[n];if(void 0===o){const a=e.textures,u=[];let l;for(let s=0;s0&&(t.currentOcclusionQuerySet&&t.currentOcclusionQuerySet.destroy(),t.currentOcclusionQueryBuffer&&t.currentOcclusionQueryBuffer.destroy(),t.currentOcclusionQuerySet=t.occlusionQuerySet,t.currentOcclusionQueryBuffer=t.occlusionQueryBuffer,t.currentOcclusionQueryObjects=t.occlusionQueryObjects,i=r.createQuerySet({type:"occlusion",count:s,label:`occlusionQuerySet_${e.id}`}),t.occlusionQuerySet=i,t.occlusionQueryIndex=0,t.occlusionQueryObjects=new Array(s),t.lastOcclusionObject=null),n=null===e.textures?this._getDefaultRenderPassDescriptor():this._getRenderPassDescriptor(e,{loadOp:xv}),this.initTimestampQuery(e,n),n.occlusionQuerySet=i;const o=n.depthStencilAttachment;if(null!==e.textures){const t=n.colorAttachments;for(let r=0;r0&&t.currentPass.executeBundles(t.renderBundles),r>t.occlusionQueryIndex&&t.currentPass.endOcclusionQuery(),t.currentPass.end(),r>0){const s=8*r;let i=this.occludedResolveCache.get(s);void 0===i&&(i=this.device.createBuffer({size:s,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),this.occludedResolveCache.set(s,i));const n=this.device.createBuffer({size:s,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});t.encoder.resolveQuerySet(t.occlusionQuerySet,0,r,i,0),t.encoder.copyBufferToBuffer(i,0,n,0,s),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?(u.x=Math.min(t.dispatchCount,o),u.y=Math.ceil(t.dispatchCount/o)):u.x=t.dispatchCount,i.dispatchWorkgroups(u.x,u.y,u.z)}finishCompute(e){const t=this.get(e);t.passEncoderGPU.end(),this.prepareTimestampBuffer(e,t.cmdEncoderGPU),this.device.queue.submit([t.cmdEncoderGPU.finish()])}async waitForGPU(){await this.device.queue.onSubmittedWorkDone()}draw(e,t){const{object:r,context:s,pipeline:i}=e,n=e.getBindings(),o=this.get(s),a=this.get(i).pipeline,u=o.currentSets,l=o.currentPass,d=e.getDrawParameters();if(null===d)return;u.pipeline!==a&&(l.setPipeline(a),u.pipeline=a);const c=u.bindingGroups;for(let e=0,t=n.length;e1?0:r;!0===p?l.drawIndexed(t[r],s,e[r]/h.array.BYTES_PER_ELEMENT,0,n):l.draw(t[r],s,e[r],n)}}else if(!0===p){const{vertexCount:s,instanceCount:i,firstVertex:n}=d,o=e.getIndirect();if(null!==o){const e=this.get(o).buffer;l.drawIndexedIndirect(e,0)}else l.drawIndexed(s,i,n,0,0);t.update(r,s,i)}else{const{vertexCount:s,instanceCount:i,firstVertex:n}=d,o=e.getIndirect();if(null!==o){const e=this.get(o).buffer;l.drawIndirect(e,0)}else l.draw(s,i,n,0);t.update(r,s,i)}}needsRenderUpdate(e){const t=this.get(e),{object:r,material:s}=e,i=this.utils,n=i.getSampleCountRenderContext(e.context),o=i.getCurrentColorSpace(e.context),a=i.getCurrentColorFormat(e.context),u=i.getCurrentDepthStencilFormat(e.context),l=i.getPrimitiveTopology(r,s);let d=!1;return t.material===s&&t.materialVersion===s.version&&t.transparent===s.transparent&&t.blending===s.blending&&t.premultipliedAlpha===s.premultipliedAlpha&&t.blendSrc===s.blendSrc&&t.blendDst===s.blendDst&&t.blendEquation===s.blendEquation&&t.blendSrcAlpha===s.blendSrcAlpha&&t.blendDstAlpha===s.blendDstAlpha&&t.blendEquationAlpha===s.blendEquationAlpha&&t.colorWrite===s.colorWrite&&t.depthWrite===s.depthWrite&&t.depthTest===s.depthTest&&t.depthFunc===s.depthFunc&&t.stencilWrite===s.stencilWrite&&t.stencilFunc===s.stencilFunc&&t.stencilFail===s.stencilFail&&t.stencilZFail===s.stencilZFail&&t.stencilZPass===s.stencilZPass&&t.stencilFuncMask===s.stencilFuncMask&&t.stencilWriteMask===s.stencilWriteMask&&t.side===s.side&&t.alphaToCoverage===s.alphaToCoverage&&t.sampleCount===n&&t.colorSpace===o&&t.colorFormat===a&&t.depthStencilFormat===u&&t.primitiveTopology===l&&t.clippingContextCacheKey===e.clippingContextCacheKey||(t.material=s,t.materialVersion=s.version,t.transparent=s.transparent,t.blending=s.blending,t.premultipliedAlpha=s.premultipliedAlpha,t.blendSrc=s.blendSrc,t.blendDst=s.blendDst,t.blendEquation=s.blendEquation,t.blendSrcAlpha=s.blendSrcAlpha,t.blendDstAlpha=s.blendDstAlpha,t.blendEquationAlpha=s.blendEquationAlpha,t.colorWrite=s.colorWrite,t.depthWrite=s.depthWrite,t.depthTest=s.depthTest,t.depthFunc=s.depthFunc,t.stencilWrite=s.stencilWrite,t.stencilFunc=s.stencilFunc,t.stencilFail=s.stencilFail,t.stencilZFail=s.stencilZFail,t.stencilZPass=s.stencilZPass,t.stencilFuncMask=s.stencilFuncMask,t.stencilWriteMask=s.stencilWriteMask,t.side=s.side,t.alphaToCoverage=s.alphaToCoverage,t.sampleCount=n,t.colorSpace=o,t.colorFormat=a,t.depthStencilFormat=u,t.primitiveTopology=l,t.clippingContextCacheKey=e.clippingContextCacheKey,d=!0),d}getRenderCacheKey(e){const{object:t,material:r}=e,s=this.utils,i=e.context;return[r.transparent,r.blending,r.premultipliedAlpha,r.blendSrc,r.blendDst,r.blendEquation,r.blendSrcAlpha,r.blendDstAlpha,r.blendEquationAlpha,r.colorWrite,r.depthWrite,r.depthTest,r.depthFunc,r.stencilWrite,r.stencilFunc,r.stencilFail,r.stencilZFail,r.stencilZPass,r.stencilFuncMask,r.stencilWriteMask,r.side,s.getSampleCountRenderContext(i),s.getCurrentColorSpace(i),s.getCurrentColorFormat(i),s.getCurrentDepthStencilFormat(i),s.getPrimitiveTopology(t,r),e.getGeometryCacheKey(),e.clippingContextCacheKey].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)}async copyTextureToBuffer(e,t,r,s,i,n){return this.textureUtils.copyTextureToBuffer(e,t,r,s,i,n)}initTimestampQuery(e,t){if(!this.trackTimestamp)return;const r=this.get(e);if(!r.timestampQuerySet){const t=e.isComputeNode?"compute":"render";r.timestampQuerySet=this.device.createQuerySet({type:"timestamp",count:2,label:`timestamp_${t}_${e.id}`})}t.timestampWrites={querySet:r.timestampQuerySet,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1}}prepareTimestampBuffer(e,t){if(!this.trackTimestamp)return;const r=this.get(e),s=2*BigUint64Array.BYTES_PER_ELEMENT;void 0===r.currentTimestampQueryBuffers&&(r.currentTimestampQueryBuffers={resolveBuffer:this.device.createBuffer({label:"timestamp resolve buffer",size:s,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),resultBuffer:this.device.createBuffer({label:"timestamp result buffer",size:s,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ})});const{resolveBuffer:i,resultBuffer:n}=r.currentTimestampQueryBuffers;t.resolveQuerySet(r.timestampQuerySet,0,2,i,0),"unmapped"===n.mapState&&t.copyBufferToBuffer(i,0,n,0,s)}async resolveTimestampAsync(e,t="render"){if(!this.trackTimestamp)return;const r=this.get(e);if(void 0===r.currentTimestampQueryBuffers)return;const{resultBuffer:s}=r.currentTimestampQueryBuffers;if("unmapped"===s.mapState){await s.mapAsync(GPUMapMode.READ);const e=new BigUint64Array(s.getMappedRange()),r=Number(e[1]-e[0])/1e6;this.renderer.info.updateTimestamp(t,r),s.unmap()}}createNodeBuilder(e,t){return new JN(e,t)}createProgram(e){this.get(e).module={module:this.device.createShaderModule({code:e.code,label:e.stage+(""!==e.name?`_${e.name}`:"")}),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 r=this.get(e),s=r.currentPass.finish();this.get(t).bundleGPU=s,r.currentSets=r._currentSets,r.currentPass=r._currentPass}addBundle(e,t){this.get(e).renderBundles.push(this.get(t).bundleGPU)}createBindings(e,t,r,s){this.bindingUtils.createBindings(e,t,r,s)}updateBindings(e,t,r,s){this.bindingUtils.createBindings(e,t,r,s)}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)}createIndirectStorageAttribute(e){this.attributeUtils.createAttribute(e,GPUBufferUsage.STORAGE|GPUBufferUsage.INDIRECT|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,r=null,s=null,i=0){let n=0,o=0,a=0,u=0,l=0,d=0,c=e.image.width,h=e.image.height;null!==r&&(u=r.x,l=r.y,d=r.z||0,c=r.width,h=r.height),null!==s&&(n=s.x,o=s.y,a=s.z||0);const p=this.device.createCommandEncoder({label:"copyTextureToTexture_"+e.id+"_"+t.id}),g=this.get(e).texture,m=this.get(t).texture;p.copyTextureToTexture({texture:g,mipLevel:i,origin:{x:u,y:l,z:d}},{texture:m,mipLevel:i,origin:{x:n,y:o,z:a}},[c,h,1]),this.device.queue.submit([p.finish()])}copyFramebufferToTexture(e,t,r){const s=this.get(t);let i=null;i=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 n=this.get(e).texture;if(i.format!==n.format)return void console.error("WebGPUBackend: copyFramebufferToTexture: Source and destination formats do not match.",i.format,n.format);let o;if(s.currentPass?(s.currentPass.end(),o=s.encoder):o=this.device.createCommandEncoder({label:"copyFramebufferToTexture_"+e.id}),o.copyTextureToTexture({texture:i,origin:[r.x,r.y,0]},{texture:n},[r.z,r.w]),e.generateMipmaps&&this.textureUtils.generateMipmaps(e),s.currentPass){const{descriptor:e}=s;for(let t=0;t(console.warn("THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend."),new iv(e)));super(new t(e),e),this.library=new lS,this.isWebGPURenderer=!0}}class cS extends ts{constructor(){super(),this.isBundleGroup=!0,this.type="BundleGroup",this.static=!0,this.version=0}set needsUpdate(e){!0===e&&this.version++}}class hS{constructor(e,t=$i(0,0,1,1)){this.renderer=e,this.outputNode=t,this.outputColorTransform=!0,this.needsUpdate=!0;const r=new nh;r.name="PostProcessing",this._quadMesh=new cf(r)}render(){this._update();const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;e.toneMapping=h,e.outputColorSpace=Re,this._quadMesh.render(e),e.toneMapping=t,e.outputColorSpace=r}dispose(){this._quadMesh.material.dispose()}_update(){if(!0===this.needsUpdate){const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;this._quadMesh.material.fragmentNode=!0===this.outputColorTransform?xu(this.outputNode,t,r):this.outputNode.context({toneMapping:t,outputColorSpace:r}),this._quadMesh.material.needsUpdate=!0,this.needsUpdate=!1}}async renderAsync(){this._update();const e=this.renderer,t=e.toneMapping,r=e.outputColorSpace;e.toneMapping=h,e.outputColorSpace=Re,await this._quadMesh.renderAsync(e),e.toneMapping=t,e.outputColorSpace=r}}class pS extends J{constructor(e=1,t=1){super(),this.image={width:e,height:t},this.magFilter=z,this.minFilter=z,this.isStorageTexture=!0}}class gS extends xf{constructor(e,t){super(e,t,Uint32Array),this.isIndirectStorageBufferAttribute=!0}}class mS extends rs{constructor(e){super(e),this.textures={},this.nodes={}}load(e,t,r,s){const i=new ss(this.manager);i.setPath(this.path),i.setRequestHeader(this.requestHeader),i.setWithCredentials(this.withCredentials),i.load(e,(r=>{try{t(this.parse(JSON.parse(r)))}catch(t){s?s(t):console.error(t),this.manager.itemError(e)}}),r,s)}parseNodes(e){const t={};if(void 0!==e){for(const r of e){const{uuid:e,type:s}=r;t[e]=this.createNodeFromType(s),t[e].uuid=e}const r={nodes:t,textures:this.textures};for(const s of e){s.meta=r;t[s.uuid].deserialize(s),delete s.meta}}return t}parse(e){const t=this.createNodeFromType(e.type);t.uuid=e.uuid;const r={nodes:this.parseNodes(e.nodes),textures:this.textures};return e.meta=r,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),Bi()):Ti(new this.nodes[e])}}class fS extends is{constructor(e){super(e),this.nodes={},this.nodeMaterials={}}parse(e){const t=super.parse(e),r=this.nodes,s=e.inputNodes;for(const e in s){const i=s[e];t[e]=r[i]}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 yS extends ns{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 r=super.parse(e,t);return this._nodesJSON=null,r}parseNodes(e,t){if(void 0!==e){const r=new mS;return r.setNodes(this.nodes),r.setTextures(t),r.parseNodes(e)}return{}}parseMaterials(e,t){const r={};if(void 0!==e){const s=this.parseNodes(this._nodesJSON,t),i=new fS;i.setTextures(t),i.setNodes(s),i.setNodeMaterials(this.nodeMaterials);for(let t=0,s=e.length;t[property:Boolean flatShading] تحديد ما إذا كان يتم عرض المادة بظلال مسطحة. الافتراضي هو خطأ.

-

[property:Boolean fog]

-

ما إذا كانت المادة متأثرة بالضباب. الافتراضي هو `false`.

-

[property:Texture normalMap]

النسيج لإنشاء خريطة طبيعية. تؤثر قيم RGB على السطح الطبيعي لكل قطعة بكسل وتغير طريقة إضاءة اللون. لا تغير خرائط العادية شكل السطح الفعلي ، فقط الإضاءة. في حال كانت المادة تحتوي على خريطة طبيعية مؤلفة باستخدام اتفاقية اليد اليسرى ، يجب إنكار مكون y من normalScale للتعويض عن اختلاف التوجه. diff --git a/docs/api/en/animation/AnimationObjectGroup.html b/docs/api/en/animation/AnimationObjectGroup.html index 4699fe4cecd7b7..6486e4490e6e22 100644 --- a/docs/api/en/animation/AnimationObjectGroup.html +++ b/docs/api/en/animation/AnimationObjectGroup.html @@ -53,7 +53,7 @@

[property:Boolean isAnimationObjectGroup]

[property:Object stats]

- An object that contains some informations of this `AnimationObjectGroup` + An object that contains information of this `AnimationObjectGroup` (total number, number in use, number of bindings per object)

diff --git a/docs/api/en/core/BufferAttribute.html b/docs/api/en/core/BufferAttribute.html index 764273483a8aaf..c3cef46dd6e61e 100644 --- a/docs/api/en/core/BufferAttribute.html +++ b/docs/api/en/core/BufferAttribute.html @@ -70,6 +70,9 @@

[property:Number gpuType]

[property:Boolean isBufferAttribute]

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

+

[property:Integer id]

+

Unique number for this attribute instance.

+

[property:Integer itemSize]

The length of vectors that are being stored in the diff --git a/docs/api/en/materials/Material.html b/docs/api/en/materials/Material.html index 85d5c38b8146cf..d84a2556af27a1 100644 --- a/docs/api/en/materials/Material.html +++ b/docs/api/en/materials/Material.html @@ -417,7 +417,9 @@

An optional callback that is executed immediately before the shader program is compiled. This function is called with the shader source code - as a parameter. Useful for the modification of built-in materials. + as a parameter. Useful for the modification of built-in materials, but the + recommended approach moving forward is to use `WebGPURenderer` with the new + Node Material system and [link:https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language TSL].

Unlike properties, the callback is not supported by [page:Material.clone .clone](), diff --git a/docs/api/en/materials/MeshNormalMaterial.html b/docs/api/en/materials/MeshNormalMaterial.html index 0be71865a70b70..58810c7ea8c340 100644 --- a/docs/api/en/materials/MeshNormalMaterial.html +++ b/docs/api/en/materials/MeshNormalMaterial.html @@ -90,9 +90,6 @@

[property:Boolean flatShading]

false.

-

[property:Boolean fog]

-

Whether the material is affected by fog. Default is `false`.

-

[property:Texture normalMap]

The texture to create a normal map. The RGB values affect the surface diff --git a/docs/api/en/math/Matrix4.html b/docs/api/en/math/Matrix4.html index e97fbc9a05a468..5138ebd2f2e0ae 100644 --- a/docs/api/en/math/Matrix4.html +++ b/docs/api/en/math/Matrix4.html @@ -315,8 +315,8 @@

[method:this lookAt]( [param:Vector3 eye], [param:Vector3 target], [param:Vector3 up] )

- Constructs a rotation matrix, looking from [page:Vector3 eye] towards - [page:Vector3 target] oriented by the [page:Vector3 up] vector. + Sets the rotation component of the transformation matrix, looking from [page:Vector3 eye] towards + [page:Vector3 target], and oriented by the up-direction [page:Vector3 up].

diff --git a/docs/api/en/textures/Texture.html b/docs/api/en/textures/Texture.html index f607111122ff10..db7e0d180f3539 100644 --- a/docs/api/en/textures/Texture.html +++ b/docs/api/en/textures/Texture.html @@ -309,10 +309,7 @@

[method:undefined updateMatrix]()

[method:Texture clone]()

Make copy of the texture. Note this is not a "deep copy", the image is - shared. Besides, cloning a texture does not automatically mark it for a - texture upload. You have to set [page:Texture.needsUpdate .needsUpdate] to - true as soon as its image property (the data source) is fully loaded or - ready. + shared. Cloning the texture automatically marks it for texture upload.

[method:Object toJSON]( [param:Object meta] )

diff --git a/docs/api/en/textures/VideoFrameTexture.html b/docs/api/en/textures/VideoFrameTexture.html new file mode 100644 index 00000000000000..76bdf9c1aed584 --- /dev/null +++ b/docs/api/en/textures/VideoFrameTexture.html @@ -0,0 +1,98 @@ + + + + + + + + + + [page:VideoTexture] → + +

[name]

+ +

+ This class can be used as an alternative way to define video data. Instead of using + an instance of `HTMLVideoElement` like with `VideoTexture`, [name] expects each frame is + defined manaully via [page:.setFrame setFrame](). A typical use case for this module is when + video frames are decoded with the WebCodecs API. +

+ +

Code Example

+ + + const texture = new THREE.VideoFrameTexture(); + texture.setFrame( frame ); + + +

Examples

+ +

+ [example:webgpu_video_frame video / frame] +

+ +

Constructor

+

+ [name]( [param:Constant mapping], [param:Constant wrapS], + [param:Constant wrapT], [param:Constant magFilter], [param:Constant minFilter], + [param:Constant format], [param:Constant type], [param:Number anisotropy] ) +

+

+ [page:Constant mapping] -- How the image is applied to the object. An + object type of [page:Textures THREE.UVMapping]. + See [page:Textures mapping constants] for other choices.
+ + [page:Constant wrapS] -- The default is [page:Textures THREE.ClampToEdgeWrapping]. + See [page:Textures wrap mode constants] for + other choices.
+ + [page:Constant wrapT] -- The default is [page:Textures THREE.ClampToEdgeWrapping]. + See [page:Textures wrap mode constants] for + other choices.
+ + [page:Constant magFilter] -- How the texture is sampled when a texel + covers more than one pixel. The default is [page:Textures THREE.LinearFilter]. + See [page:Textures magnification filter constants] + for other choices.
+ + [page:Constant minFilter] -- How the texture is sampled when a texel + covers less than one pixel. The default is [page:Textures THREE.LinearFilter]. + See [page:Textures minification filter constants] for + other choices.
+ + [page:Constant format] -- The default is [page:Textures THREE.RGBAFormat]. + See [page:Textures format constants] for other choices.
+ + [page:Constant type] -- Default is [page:Textures THREE.UnsignedByteType]. + See [page:Textures type constants] for other choices.
+ + [page:Number anisotropy] -- The number of samples taken along the axis + through the pixel that has the highest density of texels. By default, this + value is `1`. A higher value gives a less blurry result than a basic mipmap, + at the cost of more texture samples being used. Use + [page:WebGLrenderer.getMaxAnisotropy renderer.getMaxAnisotropy]() to find + the maximum valid anisotropy value for the GPU; this value is usually a + power of 2.

+

+ +

Properties

+ +

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

+ +

Methods

+ +

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

+ +

[method:undefined setFrame]( [param:VideoFrame frame] )

+

+ Sets the current frame of the video. This will automatically update the texture + so the data can be used for rendering. +

+ +

Source

+ +

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

+ + diff --git a/docs/api/fr/constants/Textures.html b/docs/api/fr/constants/Textures.html index ee94a9568bd611..90465fdf678a24 100644 --- a/docs/api/fr/constants/Textures.html +++ b/docs/api/fr/constants/Textures.html @@ -48,12 +48,12 @@

Modes d'emballage

Ces constantes définissent les propriétés des textures [page:Texture.wrapS wrapS] et [page:Texture.wrapT wrapT], qui définissent l'emballage de texture horizontal et vertical.

- Avec [page:constant RepeatWrapping] la texure se répétera simplement à l'infini.

+ Avec [page:constant RepeatWrapping] la texture se répétera simplement à l'infini.

[page:constant ClampToEdgeWrapping] est la valeur par défaut. Le dernier pixel de la texture s'étend jusqu'au bord du maillage.

- Avec [page:constant MirroredRepeatWrapping] la texure se répétera à l'infini avec un effet miroir à chaque répétition. + Avec [page:constant MirroredRepeatWrapping] la texture se répétera à l'infini avec un effet miroir à chaque répétition.

Filtres de grossissement

diff --git a/docs/api/fr/materials/Material.html b/docs/api/fr/materials/Material.html index 18bc1ac1135b04..a1ca23496e8de3 100644 --- a/docs/api/fr/materials/Material.html +++ b/docs/api/fr/materials/Material.html @@ -350,7 +350,9 @@

[method:undefined dispose]()

[method:undefined onBeforeCompile]( [param:Shader shader], [param:WebGLRenderer renderer] )

Un callback facultatif qui est exécuté immédiatement avant la compilation du programme shader. - Cette fonction est appelée avec le code source du shader comme paramètre. Utile pour la modification des matériaux intégrés. + Cette fonction est appelée avec le code source du shader comme paramètre. Utile pour la modification des matériaux intégrés, + bien que la nouvelle méthode recommandée soit d'utiliser `WebGPURenderer` avec le nouveau système de Node Material et + [link:https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language TSL].

Contrairement aux propriétés, le callback n'est pas pris en charge par [page:Material.clone .clone](), [page:Material.copy .copy]() et [page:Material.toJSON .toJSON](). diff --git a/docs/api/fr/materials/MeshNormalMaterial.html b/docs/api/fr/materials/MeshNormalMaterial.html index fc781f2e3a958c..f91f0a95230bc1 100644 --- a/docs/api/fr/materials/MeshNormalMaterial.html +++ b/docs/api/fr/materials/MeshNormalMaterial.html @@ -79,9 +79,6 @@

[property:Boolean flatShading]

Définit si le matériau est rendu avec un ombrage plat. La valeur par défaut est false.

-

[property:Boolean fog]

-

Si le matériau est affecté par le brouillard (fog) La valeur par défaut est `false`.

-

[property:Texture normalMap]

La texture pour créer une carte normale. Les valeurs RVB affectent la surface normale pour chaque fragment de pixel et changent diff --git a/docs/api/it/materials/MeshNormalMaterial.html b/docs/api/it/materials/MeshNormalMaterial.html index abcecf3bcb3673..2d8e83736db452 100644 --- a/docs/api/it/materials/MeshNormalMaterial.html +++ b/docs/api/it/materials/MeshNormalMaterial.html @@ -82,9 +82,6 @@

[property:Boolean flatShading]

Definisce se il materiale viene renderizzato con un'ombreggiatura piatta. Il valore predefinito è `false`.

-

[property:Boolean fog]

-

Indica se il materiale è influenzato dalla nebbia. Il valore predefinito è `false`.

-

[property:Texture normalMap]

La texture per creare una mappa normale. I valori RGB influenzano la normale della superficie per ogni frammento di pixel diff --git a/docs/api/it/textures/Texture.html b/docs/api/it/textures/Texture.html index f59aace39ff34d..8473bc5a3b7b15 100644 --- a/docs/api/it/textures/Texture.html +++ b/docs/api/it/textures/Texture.html @@ -14,7 +14,7 @@

[name]

- Nota: Dopo l'utilizzo iniziale di una texture, le sue dimensioni, formato, e il tipo non possono essere cambiati. + Nota: Dopo l'utilizzo iniziale di una texture, le sue dimensioni, formato, e il tipo non possono essere cambiati. Invece, chiama [page:.dispose]() sulla texture e creane una nuova.

@@ -61,8 +61,8 @@

[property:Image image]

Questo può essere qualsiasi tipo di immagine (e.g., PNG, JPG, GIF, DDS) o video (e.g., MP4, OGG/OGV) supportato da three.js.

Per utilizzare il video come texture è necessario disporre di un elemento video HTML5 - in riproduzione come sorgente per l'immagine della texture e aggiornare - continuamente questa texture finchè il video è in riproduzione - + in riproduzione come sorgente per l'immagine della texture e aggiornare + continuamente questa texture finchè il video è in riproduzione - la classe [page:VideoTexture VideoTexture] gestisce questa operazione automaticamente.

@@ -88,7 +88,7 @@

[property:number wrapS]

Questo definisce come la texture è wrappata orizzontalmente e corrisponde a *U* nel mapping UV.
L'impostazione predefinita è [page:Textures THREE.ClampToEdgeWrapping], dove il bordo è fissato ai texel del bordo esterno. - Le altre due scelte sono [page:Textures THREE.RepeatWrapping] e [page:Textures THREE.MirroredRepeatWrapping]. + Le altre due scelte sono [page:Textures THREE.RepeatWrapping] e [page:Textures THREE.MirroredRepeatWrapping]. Vedi la pagina [page:Textures texture constants] per i dettagli.

@@ -122,7 +122,7 @@

[property:number minFilter]

[property:number anisotropy]

Il numero di campioni prelevati lungo l'asse attravero il pixel che ha la densità di texel più alta. - Per impostazione predefinita, questo valore è 1. Un valore più alto fornisce un risultato meno sfuocato rispetto ad una mipmap di base, + Per impostazione predefinita, questo valore è 1. Un valore più alto fornisce un risultato meno sfuocato rispetto ad una mipmap di base, a costo di utilizzare più campioni di texture. Usa [page:WebGLRenderer.capabilities renderer.capabilities.getMaxAnisotropy]() per trovare il valore di anisotropia massimo valido per la GPU; questo valore è solitamente una potenza di 2.

@@ -160,7 +160,7 @@

[property:Vector2 offset]

[property:Vector2 repeat]

- Quante volte la texture è ripetuta sulla superficie, in ogni direzione U e V. Se la proprietà ripeat è + Quante volte la texture è ripetuta sulla superficie, in ogni direzione U e V. Se la proprietà ripeat è impostata su un valore maggiore di 1 in entrambe le direzioni, anche il parametro Wrap corrispondente deve essere impostato su [page:Textures THREE.RepeatWrapping] o [page:Textures THREE.MirroredRepeatWrapping] per ottenere l'effetto di piastrellatura desiderato. @@ -174,14 +174,14 @@

[property:number rotation]

[property:Vector2 center]

- Il punto attorno al quale avviene la rotazione. Un valore (0.5, 0.5) che corrisponde al centro della texture. Il + Il punto attorno al quale avviene la rotazione. Un valore (0.5, 0.5) che corrisponde al centro della texture. Il valore predefinito è (0, 0), in basso a sinistra.

[property:Boolean matrixAutoUpdate]

Indica se aggiornare la [page:Texture.matrix .matrix] uv-transform della texture dalle proprietà della texture - [page:Texture.offset .offset], [page:Texture.repeat .repeat], [page:Texture.rotation .rotation], e [page:Texture.center .center]. + [page:Texture.offset .offset], [page:Texture.repeat .repeat], [page:Texture.rotation .rotation], e [page:Texture.center .center]. Il valore predefinito è `true`. Impostalo a `false` se stai specificando la matrice uv-transform direttamente.

@@ -196,13 +196,13 @@

[property:Matrix3 matrix]

[property:Boolean generateMipmaps]

- Indica se generare mipmap (se possibile) per una texure. Il valore predefinito è `true`. + Indica se generare mipmap (se possibile) per una texture. Il valore predefinito è `true`. Impostalo a false se stai creando il mipmap manualmente.

[property:Boolean premultiplyAlpha]

- Se impostato a `true`, il canale alfa, se presente, viene moltiplicato nei canali del colore + Se impostato a `true`, il canale alfa, se presente, viene moltiplicato nei canali del colore quando la texture viene caricata sulla GPU. Il valore predefinito è `false`.

Si noti che questa proprietà non ha effetto per [link:https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap ImageBitmap]. @@ -220,7 +220,7 @@

[property:Boolean flipY]

[property:number unpackAlignment]

Il valore predefinito è 4. Specifica i requisiti di allineamento per l'inizio di ogni riga di pixel in memoria. - I valori consentiti sono 1 (allineamento di byte), 2 (righe allineate a byte pari), 4 (allineamento di parole) + I valori consentiti sono 1 (allineamento di byte), 2 (righe allineate a byte pari), 4 (allineamento di parole) e 8 (le righe iniziano su limiti di doppia parola). Vedi [link:http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml glPixelStorei] per maggiori informazioni.

@@ -250,8 +250,8 @@

[property:Boolean needsUpdate]

[property:Object userData]

- Un oggetto che può essere utilizzato per memorizzare dati personalizzati della texture. - Non deve contenere riferimenti a funzioni poiché queste non verranno clonate. + Un oggetto che può essere utilizzato per memorizzare dati personalizzati della texture. + Non deve contenere riferimenti a funzioni poiché queste non verranno clonate.

[property:Source source]

@@ -286,7 +286,7 @@

[method:Object toJSON]( [param:Object meta] )

[method:undefined dispose]()

- Libera le risorse relative alla GPU allocate da questa istanza. + Libera le risorse relative alla GPU allocate da questa istanza. Chiama questo metodo ogni volta che questa istanza non viene più utilizzata dall'applicazione.

diff --git a/docs/api/zh/core/BufferAttribute.html b/docs/api/zh/core/BufferAttribute.html index c2ef4b2a35c57d..940681ab7c1f46 100644 --- a/docs/api/zh/core/BufferAttribute.html +++ b/docs/api/zh/core/BufferAttribute.html @@ -58,9 +58,9 @@

[property:Integer count]

[property:Number gpuType]

- Configures the bound GPU type for use in shaders. Either [page:BufferAttribute THREE.FloatType] or [page:BufferAttribute THREE.IntType], default is [page:BufferAttribute THREE.FloatType]. + 配置着色器中使用的绑定 GPU 类型。[page:BufferAttribute THREE.FloatType] 或 [page:BufferAttribute THREE.IntType],默认为 [page:BufferAttribute THREE.FloatType]。 - Note: this only has an effect for integer arrays and is not configurable for float arrays. For lower precision float types, see [page:BufferAttributeTypes THREE.Float16BufferAttribute]. + 注意:这仅对整数数组有效,对于浮点数组不可配置。对于精度较低的浮点类型,请参阅 [page:BufferAttributeTypes THREE.Float16BufferAttribute]。

[property:Boolean isBufferAttribute]

@@ -123,6 +123,16 @@

[method:this applyNormalMatrix]( [param:Matrix3 m] )

[method:this transformDirection]( [param:Matrix4 m] )

将矩阵[page:Matrix4 m]应用到此BufferAttribute的每一个Vector3元素中,并将所有元素解释为方向向量。

+ +

[method:this addUpdateRange]( [param:Integer start], [param:Integer count] )

+

+ 在数据数组中添加要在 GPU 上更新的数据范围。将描述范围的对象添加到 [page:BufferAttribute.updateRanges updateRanges] 数组。 +

+ +

[method:this clearUpdateRanges]()

+

+ 清除 [page:BufferAttribute.updateRanges updateRanges] 数组。 +

[method:BufferAttribute clone]()

返回该 BufferAttribute 的拷贝。

@@ -136,7 +146,7 @@

[method:this copyAt] ( [param:Integer index1], [param:BufferAttribute buffer

将一个矢量从 bufferAttribute[index2] 拷贝到 [page:BufferAttribute.array array][index1] 中。

[method:Number getComponent]( [param:Integer index], [param:Integer component] )

-

Returns the given component of the vector at the given index.

+

返回给定索引处的向量的给定分量。

[method:Number getX]( [param:Integer index] )

获取给定索引的矢量的第一维元素 (即 X 值)。

@@ -167,10 +177,10 @@

[method:this set] ( [param:Array value], [param:Integer offset] )

[method:this setUsage] ( [param:Usage value] )

-

Set [page:BufferAttribute.usage usage] to value. See usage [page:BufferAttributeUsage constants] for all possible input values.

+

设置 [page:BufferAttribute.usage usage] 值。查看所有可能的输入值的 usage [page:BufferAttributeUsage constants]。

[method:Number setComponent]( [param:Integer index], [param:Integer component], [param:Float value] )

-

Sets the given component of the vector at the given index.

+

在给定索引处设置向量的给定分量。

[method:this setX]( [param:Integer index], [param:Float x] )

设置给定索引的矢量的第一维数据(设置 X 值)。

diff --git a/docs/api/zh/core/BufferGeometry.html b/docs/api/zh/core/BufferGeometry.html index a6142f561ccc53..dd33f59c74f34b 100644 --- a/docs/api/zh/core/BufferGeometry.html +++ b/docs/api/zh/core/BufferGeometry.html @@ -37,6 +37,30 @@

代码示例

const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); const mesh = new THREE.Mesh( geometry, material ); + +

代码示例 (索引Index)

+ + + const geometry = new THREE.BufferGeometry(); + + const vertices = new Float32Array( [ + -1.0, -1.0, 1.0, // v0 + 1.0, -1.0, 1.0, // v1 + 1.0, 1.0, 1.0, // v2 + -1.0, 1.0, 1.0, // v3 + ] ); + + const indices = [ + 0, 1, 2, + 2, 3, 0, + ]; + + geometry.setIndex( indices ); + geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); + + const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); + const mesh = new THREE.Mesh( geometry, material ); +

例子

@@ -82,6 +106,8 @@

[property:Object drawRange]

{ start: 0, count: Infinity } + 对于非索引 BufferGeometry,count 是要渲染的顶点数。 + 对于索引 BufferGeometry,count 是要渲染的索引数。

[property:Array groups]

@@ -94,8 +120,8 @@

[property:Array groups]

start 表明当前 draw call 中的没有索引的几何体的几何体的第一个顶点;或者第一个三角面片的索引。 count 指明当前分割包含多少顶点(或 indices)。 materialIndex 指出当前用到的材质队列的索引。

- - 通过 [page:.addGroup] 来增加组,而不是直接更改当前队列。 + 通过 [page:.addGroup] 来增加组,而不是直接更改当前队列。

+ 每个顶点和索引必须恰好属于一个组,不同组之间不得共享顶点或索引,并且不得留下未使用的顶点或索引。

@@ -159,54 +185,52 @@

方法

[page:EventDispatcher EventDispatcher] 在该类上可用的所有方法。

-

[method:this setAttribute]( [param:String name], [param:BufferAttribute attribute] )

-

- 为当前几何体设置一个 attribute 属性。在类的内部,有一个存储 [page:.attributes] 的 hashmap, - 通过该 hashmap,遍历 attributes 的速度会更快。而使用该方法,可以向 hashmap 内部增加 attribute。 - 所以,你需要使用该方法来添加 attributes。 -

-

[method:undefined addGroup]( [param:Integer start], [param:Integer count], [param:Integer materialIndex] )

为当前几何体增加一个 group,详见 [page:BufferGeometry.groups groups] 属性。

-

[method:this applyMatrix4]( [param:Matrix4 matrix] )

用给定矩阵转换几何体的顶点坐标。

+

[method:this applyQuaternion]( [param:Quaternion quaternion] )

+

用给四元数表示的旋转应用于几何体的顶点坐标。

+

[method:this center] ()

根据边界矩形将几何体居中。

+ +

[method:undefined clearGroups]( )

+

清空所有的 groups。

[method:BufferGeometry clone]()

克隆当前的 BufferGeometry。

-

[method:this copy]( [param:BufferGeometry bufferGeometry] )

-

将参数指定的 BufferGeometry 的值拷贝到当前 BufferGeometry 中。

- -

[method:undefined clearGroups]( )

-

清空所有的 groups。

-

[method:undefined computeBoundingBox]()

- 计算当前几何体的的边界矩形,该操作会更新已有 [param:.boundingBox]。
+ 计算当前几何体的的边界矩形,该操作会更新已有 [page:.boundingBox]。
边界矩形不会默认计算,需要调用该接口指定计算边界矩形,否则保持默认值 *null*。

[method:undefined computeBoundingSphere]()

- 计算当前几何体的的边界球形,该操作会更新已有 [param:.boundingSphere]。
+ 计算当前几何体的的边界球形,该操作会更新已有 [page:.boundingSphere]。
边界球形不会默认计算,需要调用该接口指定计算边界球形,否则保持默认值 *null*。

[method:undefined computeTangents]()

计算并向此geometry中添加tangent attribute。
- 只支持索引化的几何体对象,并且必须拥有position(位置),normal(法向)和 uv attributes。如果使用了切线空间法向贴图,最好使用[page:BufferGeometryUtils.computeMikkTSpaceTangents]中的MikkTSpace算法。 + 只支持索引化的几何体对象,并且必须拥有position(位置),normal(法向)和 uv attributes。如果使用了切线空间法向贴图,最好使用 [page:BufferGeometryUtils.computeMikkTSpaceTangents] 中的MikkTSpace算法。

[method:undefined computeVertexNormals]()

-

通过面片法向量的平均值计算每个顶点的法向量。

+

通过面片法向量的平均值计算每个顶点的法向量。对于索引几何体,该方法将每个顶点法线设置为共享该顶点的面的面法线的平均值。对于非索引几何体,顶点不共享,该方法将每个顶点法线设置为与面法线相同。

+ +

[method:this copy]( [param:BufferGeometry bufferGeometry] )

+

将参数指定的 BufferGeometry 的值拷贝到当前 BufferGeometry 中。

+ +

[method:BufferAttribute deleteAttribute]( [param:String name] )

+

删除具有指定名称的 [page:BufferAttribute attribute]。

[method:undefined dispose]()

@@ -235,9 +259,6 @@

[method:undefined normalizeNormals]()

几何体中的每个法向量长度将会为 1。这样操作会更正光线在表面的效果。

-

[method:BufferAttribute deleteAttribute]( [param:String name] )

-

删除具有指定名称的 [page:BufferAttribute attribute]。

-

[method:this rotateX] ( [param:Float radians] )

在 X 轴上旋转几何体。该操作一般在一次处理中完成,不会循环处理。典型的用法是通过调用 [page:Object3D.rotation] 实时旋转几何体。 @@ -258,24 +279,30 @@

[method:this scale] ( [param:Float x], [param:Float y], [param:Float z] ) -

[method:this setIndex] ( [param:BufferAttribute index] )

-

设置缓存的 [page:.index]。

+

[method:this setAttribute]( [param:String name], [param:BufferAttribute attribute] )

+

+ 为当前几何体设置一个 attribute 属性。在类的内部,有一个存储 [page:.attributes] 的 hashmap, + 通过该 hashmap,遍历 attributes 的速度会更快。 +

[method:undefined setDrawRange] ( [param:Integer start], [param:Integer count] )

-

设置缓存的 [page:.drawRange]。详见相关属性说明。

+

设置 [page:.drawRange] 属性。对于非索引 BufferGeometry,count 是要渲染的顶点数。对于索引 BufferGeometry,count 是要渲染的索引数。

[method:this setFromPoints] ( [param:Array points] )

-

通过点队列设置该 BufferGeometry 的 attribute。

+

通过基于给定的 points 设置几何图形的位置属性。该数组可以保存 Vector2 或 Vector3 的实例。使用二维数据时,所有顶点的 z 坐标均设置为 0。如果该方法与现有位置属性一起使用,则顶点数据将被数组中的数据覆盖。数组的长度必须与顶点数匹配。

+ +

[method:this setIndex] ( [param:BufferAttribute index] )

+

设置缓存的 [page:.index]。

[method:Object toJSON]()

-

返回代表该 BufferGeometry 的 JSON 对象。

+

返回代表该 BufferGeometry 符合 [link:https://github.com/mrdoob/three.js/wiki/JSON-Object-Scene-format-4 Object/Scene 规范] 的 JSON 对象。

[method:BufferGeometry toNonIndexed]()

返回已索引的 BufferGeometry 的非索引版本。

[method:this translate] ( [param:Float x], [param:Float y], [param:Float z] )

- 移动几何体。该操作一般在一次处理中完成,不会循环处理。典型的用法是通过调用 [page:Object3D.rotation] 实时旋转几何体。 + 移动几何体。该操作一般在一次处理中完成,不会循环处理。典型的用法是通过调用 [page:Object3D.position] 实时移动几何体。

Source

diff --git a/docs/api/zh/materials/MeshNormalMaterial.html b/docs/api/zh/materials/MeshNormalMaterial.html index 5d6c2e4466edcb..dc771defd7f61c 100644 --- a/docs/api/zh/materials/MeshNormalMaterial.html +++ b/docs/api/zh/materials/MeshNormalMaterial.html @@ -66,9 +66,6 @@

[property:Boolean flatShading]

定义材质是否使用平面着色进行渲染。默认值为false。

-

[property:Boolean fog]

-

材质是否受到雾的影响。默认值为 `false`。

-

[property:Texture normalMap]

用于创建法线贴图的纹理。RGB值会影响每个像素片段的曲面法线,并更改颜色照亮的方式。法线贴图不会改变曲面的实际形状,只会改变光照。 In case the material has a normal map authored using the left handed convention, the y component of normalScale diff --git a/docs/examples/en/animations/CCDIKSolver.html b/docs/examples/en/animations/CCDIKSolver.html index 82b93b565fc93d..533510d8808615 100644 --- a/docs/examples/en/animations/CCDIKSolver.html +++ b/docs/examples/en/animations/CCDIKSolver.html @@ -9,7 +9,7 @@

[name]

-

A solver for IK with `CCD Algorithm`.

+

A solver for IK with `CCD Algorithm`.

[name] solves Inverse Kinematics Problem with CCD Algorithm. [name] is designed to work with [page:SkinnedMesh] but also can be used with [page:GLTFLoader] skeleton.

diff --git a/docs/examples/en/controls/ArcballControls.html b/docs/examples/en/controls/ArcballControls.html index 1fb2609a7cd2ac..32eb17797879de 100644 --- a/docs/examples/en/controls/ArcballControls.html +++ b/docs/examples/en/controls/ArcballControls.html @@ -248,7 +248,7 @@

[method:undefined setGizmosVisible] ( [param:Boolean value] )

[method:undefined setTbRadius] ( [param:Float value] )

- Update the `radiusFactor` value, redraw the gizmo and send a `changeEvent` to visualise the changes. + Update the `radiusFactor` value, redraw the gizmo and send a `changeEvent` to visualize the changes.

[method:Boolean setMouseAction] ( [param:String operation], mouse, key )

diff --git a/docs/examples/en/lines/LineMaterial.html b/docs/examples/en/lines/LineMaterial.html index d988ad641df6d6..fee2a764a28a6e 100644 --- a/docs/examples/en/lines/LineMaterial.html +++ b/docs/examples/en/lines/LineMaterial.html @@ -64,7 +64,7 @@

[property:number gapSize]

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

[property:Float linewidth]

-

Controls line thickness. Default is `1`.

+

Controls line thickness in CSS pixel units when [page:worldUnits] is `false` (default), or in world units when [page:worldUnits] is `true`. Default is `1`.

[property:Vector2 resolution]

diff --git a/docs/examples/en/math/convexhull/ConvexHull.html b/docs/examples/en/math/convexhull/ConvexHull.html index 6ddf07effa9a5e..2cbacc97a25f7e 100644 --- a/docs/examples/en/math/convexhull/ConvexHull.html +++ b/docs/examples/en/math/convexhull/ConvexHull.html @@ -86,7 +86,7 @@

[method:this addNewFaces]( [param:VertexNode eyeVertex], [param:HalfEdge hor

[method:this addVertexToFace]( [param:VertexNode vertex], [param:Face face] )

- [page:VertexNodeNode vertex] - The vertex to add.
+ [page:VertexNode vertex] - The vertex to add.
[page:Face face] - The target face.

Adds a vertex to the 'assigned' list of vertices and assigns it to the given face. diff --git a/docs/examples/zh/animations/CCDIKSolver.html b/docs/examples/zh/animations/CCDIKSolver.html index 08c0ddcfeeaeef..47fedfd48b083a 100644 --- a/docs/examples/zh/animations/CCDIKSolver.html +++ b/docs/examples/zh/animations/CCDIKSolver.html @@ -11,7 +11,7 @@

CCDIK解算器([name])

-

一种基于 `CCD Algorithm` 的 IK +

一种基于 `CCD Algorithm` 的 IK 解算器。

[name] 用 CCD 算法解决逆运动学问题。 [name] 设计用于与 [page:SkinnedMesh] 配合使用,但也可与 [page:GLTFLoader] 配合使用。 diff --git a/docs/examples/zh/math/convexhull/ConvexHull.html b/docs/examples/zh/math/convexhull/ConvexHull.html index 583e79d1c7cf21..1e40d58b1dc170 100644 --- a/docs/examples/zh/math/convexhull/ConvexHull.html +++ b/docs/examples/zh/math/convexhull/ConvexHull.html @@ -88,7 +88,7 @@

[method:this addNewFaces]( [param:VertexNode eyeVertex], [param:HalfEdge hor

[method:this addVertexToFace]( [param:VertexNode vertex], [param:Face face] )

- [page:VertexNodeNode vertex] - 要添加的顶点。
+ [page:VertexNode vertex] - 要添加的顶点。
[page:Face face] - 目标面。

将一个顶点添加到 “分配(assigned)” 顶点列表,并将其分配给给定的面。 diff --git a/docs/list.json b/docs/list.json index eadf2f26603bb0..483a7c1f56316d 100644 --- a/docs/list.json +++ b/docs/list.json @@ -318,6 +318,7 @@ "FramebufferTexture": "api/en/textures/FramebufferTexture", "Source": "api/en/textures/Source", "Texture": "api/en/textures/Texture", + "VideoFrameTexture": "api/en/textures/VideoFrameTexture", "VideoTexture": "api/en/textures/VideoTexture" } diff --git a/docs/manual/en/introduction/Color-management.html b/docs/manual/en/introduction/Color-management.html index 088abde94531fc..882f8112527251 100644 --- a/docs/manual/en/introduction/Color-management.html +++ b/docs/manual/en/introduction/Color-management.html @@ -214,14 +214,10 @@

Output color space

Output to a display device, image, or video may involve conversion from the open domain - Linear-sRGB working color space to another color space. This conversion may be performed in - the main render pass ([page:WebGLRenderer.outputColorSpace]), or during post-processing. + Linear-sRGB working color space to another color space. The conversion is defined by + ([page:WebGLRenderer.outputColorSpace]). When using post-processing, this requires OutputPass.

- -renderer.outputColorSpace = THREE.SRGBColorSpace; // optional with post-processing - -
  • Display: Colors written to a WebGL canvas for display should be in the sRGB diff --git a/editor/js/Config.js b/editor/js/Config.js index 43108ceae73b6c..1f2fb51c8ef8a1 100644 --- a/editor/js/Config.js +++ b/editor/js/Config.js @@ -4,7 +4,7 @@ function Config() { const userLanguage = navigator.language.split( '-' )[ 0 ]; - const suggestedLanguage = [ 'fr', 'ja', 'zh', 'ko' ].includes( userLanguage ) ? userLanguage : 'en'; + const suggestedLanguage = [ 'fr', 'ja', 'zh', 'ko', 'fa' ].includes( userLanguage ) ? userLanguage : 'en'; const storage = { 'language': suggestedLanguage, diff --git a/editor/js/Sidebar.Project.Materials.js b/editor/js/Sidebar.Project.Materials.js index c1ca42917b0b59..6823b435fd6d5b 100644 --- a/editor/js/Sidebar.Project.Materials.js +++ b/editor/js/Sidebar.Project.Materials.js @@ -31,7 +31,7 @@ function SidebarProjectMaterials( editor ) { const oldMaterial = selectedObject.material; - // only assing materials to objects with a material property (e.g. avoid assigning material to THREE.Group) + // only passing materials to objects with a material property (e.g. avoid assigning material to THREE.Group) if ( oldMaterial !== undefined ) { diff --git a/editor/js/Sidebar.Settings.js b/editor/js/Sidebar.Settings.js index c66caab9137807..6756e5d497bf11 100644 --- a/editor/js/Sidebar.Settings.js +++ b/editor/js/Sidebar.Settings.js @@ -17,13 +17,11 @@ function SidebarSettings( editor ) { // language - const options = { - en: 'English', - fr: 'Français', - zh: '中文', - ja: '日本語', - ko: '한국어', - }; + const options = Object.fromEntries( [ 'en', 'fr', 'zh', 'ja', 'ko', 'fa' ].map( locale => { + + return [ locale, new Intl.DisplayNames( locale, { type: 'language' } ).of( locale ) ]; + + } ) ); const languageRow = new UIRow(); const language = new UISelect().setWidth( '150px' ); diff --git a/editor/js/Strings.js b/editor/js/Strings.js index 7a8ce1c570c6d2..4988c893eee888 100644 --- a/editor/js/Strings.js +++ b/editor/js/Strings.js @@ -3,7 +3,406 @@ function Strings( config ) { const language = config.getKey( 'language' ); const values = { +fa: { +'prompt/file/open': 'تمام داده های ذخیره نشده پاک خواهند شد آیا مطمئنید؟', + 'prompt/file/failedToOpenProject': 'خطایی در باز کردن پروژه پیش آمده', + 'prompt/file/export/noMeshSelected': 'هیچ Mesh ای انتخاب نکردید', + 'prompt/file/export/noObjectSelected': 'هیچ آبجکتی انتخاب نکردید!', + 'prompt/script/remove': 'آیا اطمینان دارید؟', + 'prompt/history/clear': 'هیستوری قبل و بعد (undo / redo) پاک خواهند شد آیا مطمئنید؟', + 'prompt/history/preserve': 'The history will be preserved across sessions.\nThis can have an impact on performance when working with textures.', + 'prompt/history/forbid': 'Undo/Redo disabled while scene is playing.', + 'prompt/rendering/realistic/unsupportedMaterial': 'REALISTIC Shading: Only MeshStandardMaterial and MeshPhysicalMaterial are supported', + + 'command/AddObject': 'افزودن آبجکت', + 'command/AddScript': 'افزودن اسکریپت', + 'command/MoveObject': 'جابجایی آبجکت', + 'command/MultiCmds': 'تغییرات گروهی', + 'command/RemoveObject': 'حذف آبجکت', + 'command/RemoveScript': 'حذف اسکریپت', + 'command/SetColor': 'تنظیم رنگ', + 'command/SetGeometry': 'تنظیم ژئومتری', + 'command/SetGeometryValue': 'تنظیم مقدار ژئومتری', + 'command/SetMaterialColor': 'تنظیم رنگ متریال', + 'command/SetMaterial': 'تنظیم متریال', + 'command/SetMaterialMap': 'تنظیم مپ متریال', + 'command/SetMaterialRange': 'تنظیم رنج متریال', + 'command/SetMaterialValue': 'تنظیم مقدار متریال', + 'command/SetMaterialVector': 'تنظیم وکتور متریال', + 'command/SetPosition': 'تنظیم پوزیشن', + 'command/SetRotation': 'تنظیم چرخش', + 'command/SetScale': 'تنظیم اندازه', + 'command/SetScene': 'تنظیم صحنه', + 'command/SetScriptValue': 'تنظیم مقدار اسکریپت', + 'command/SetShadowValue': 'تنظیم مقدار سایه', + 'command/SetUuid': 'تنظیم UUID', + 'command/SetValue': 'تنظیم مقدار', + + 'menubar/file': 'فایل', + 'menubar/file/new': 'جدید', + 'menubar/file/new/empty': 'پروژه خالی', + 'menubar/file/new/Arkanoid': 'آرکانوید', + 'menubar/file/new/Camera': 'دوربین', + 'menubar/file/new/Particles': 'Particles', + 'menubar/file/new/Pong': 'پونگ', + 'menubar/file/new/Shaders': 'Shaders', + 'menubar/file/open': 'باز کردن', + 'menubar/file/save': 'ذخیره تغییرات', + 'menubar/file/import': 'ایمپورت', + 'menubar/file/export': 'اکسپورت', + + 'menubar/edit': 'تغییر', + 'menubar/edit/undo': 'بازگشت', + 'menubar/edit/redo': 'بازگشت به جلو', + 'menubar/edit/center': 'وسط', + 'menubar/edit/clone': 'شبیه سازی', + 'menubar/edit/delete': 'حذف', + + 'menubar/add': 'افزودن', + 'menubar/add/group': 'گروه', + + 'menubar/add/mesh': 'مش', + 'menubar/add/mesh/plane': 'صفحه', + 'menubar/add/mesh/box': 'باکس', + 'menubar/add/mesh/capsule': 'کپسول', + 'menubar/add/mesh/circle': 'دایره', + 'menubar/add/mesh/cylinder': 'سیلندر', + 'menubar/add/mesh/ring': 'حلقه', + 'menubar/add/mesh/sphere': 'کره', + 'menubar/add/mesh/dodecahedron': 'دوازده وجهی', + 'menubar/add/mesh/icosahedron': 'بیست وجهی', + 'menubar/add/mesh/octahedron': 'هشت وجهی', + 'menubar/add/mesh/tetrahedron': 'چهار وجهی', + 'menubar/add/mesh/torus': 'توروس (دونات)', + 'menubar/add/mesh/tube': 'لوله', + 'menubar/add/mesh/torusknot': 'torusknot', + 'menubar/add/mesh/lathe': 'Lathe', + 'menubar/add/mesh/sprite': 'Sprite', + + 'menubar/add/light': 'نور', + 'menubar/add/light/ambient': 'محیط', + 'menubar/add/light/directional': 'جهت دار', + 'menubar/add/light/hemisphere': 'نیمکره', + 'menubar/add/light/point': 'مستقیم', + 'menubar/add/light/spot': 'نقطه ای', + + 'menubar/add/camera': 'دوربین', + 'menubar/add/camera/perspective': 'پرسپکتیو', + 'menubar/add/camera/orthographic': 'اورتوگرافیک', + + 'menubar/status/autosave': 'ذخیره اتوماتیک', + + 'menubar/view': 'نمایش', + 'menubar/view/fullscreen': 'تمام صفحه', + 'menubar/view/gridHelper': 'کمک کننده گرید', + 'menubar/view/cameraHelpers': 'کمک کننده دوربین', + 'menubar/view/lightHelpers': 'کمک کننده نور', + 'menubar/view/skeletonHelpers': 'کمک کننده اسکلتون', + + 'menubar/help': 'کمک', + 'menubar/help/source_code': 'سورس کد', + 'menubar/help/icons': 'پک آیکون', + 'menubar/help/about': 'درباره ما', + 'menubar/help/manual': 'کتابچه راهنما', + + 'sidebar/animations': 'انیمیشن ها', + 'sidebar/animations/play': 'نمایش', + 'sidebar/animations/stop': 'توقف', + 'sidebar/animations/timescale': 'مقیاس زمانی', + + 'sidebar/scene': 'صحنه', + 'sidebar/scene/background': 'پس زمینه', + 'sidebar/scene/environment': 'محیط', + 'sidebar/scene/fog': 'مه', + + 'sidebar/properties/object': 'آبجکت', + 'sidebar/properties/geometry': 'ژئومتری', + 'sidebar/properties/material': 'متریال', + 'sidebar/properties/script': 'اسکریپت', + + 'sidebar/object/type': 'انواع', + 'sidebar/object/new': 'جدید', + 'sidebar/object/uuid': 'UUID', + 'sidebar/object/name': 'نام', + 'sidebar/object/position': 'پوزیشن', + 'sidebar/object/rotation': 'چرخش', + 'sidebar/object/scale': 'مقیاس', + 'sidebar/object/fov': 'زاویه دید', + 'sidebar/object/left': 'چپ', + 'sidebar/object/right': 'راست', + 'sidebar/object/top': 'بالا', + 'sidebar/object/bottom': 'پایین', + 'sidebar/object/near': 'نزدیک', + 'sidebar/object/far': 'دور', + 'sidebar/object/intensity': 'شدت', + 'sidebar/object/color': 'رنگ', + 'sidebar/object/groundcolor': 'رنگ زمینه', + 'sidebar/object/distance': 'مسافت', + 'sidebar/object/angle': 'زاویه', + 'sidebar/object/penumbra': 'نیم سایه', + 'sidebar/object/decay': 'پوسیدگی', + 'sidebar/object/shadow': 'سایه', + 'sidebar/object/shadowIntensity': 'شدت سایه', + 'sidebar/object/shadowBias': 'انحراف سایه', + 'sidebar/object/shadowNormalBias': 'انحراف معمول سایه', + 'sidebar/object/shadowRadius': 'شعاع سایه', + 'sidebar/object/cast': 'سایه انداختن', + 'sidebar/object/receive': 'دریافت', + 'sidebar/object/visible': 'آشکار', + 'sidebar/object/frustumcull': 'فروستوم کال', + 'sidebar/object/renderorder': 'ترتیب رندر', + 'sidebar/object/userdata': 'داده کاربر', + 'sidebar/object/export': 'اکسپورت جیسون', + + 'sidebar/geometry/type': 'انواع', + 'sidebar/geometry/new': 'جدید', + 'sidebar/geometry/uuid': 'UUID', + 'sidebar/geometry/name': 'نام', + 'sidebar/geometry/bounds': 'محدوده', + 'sidebar/geometry/userdata': 'داده کاربر', + 'sidebar/geometry/show_vertex_normals': 'نمایش راس های معمول', + 'sidebar/geometry/compute_vertex_normals': 'محاسبه راس های معمول', + 'sidebar/geometry/compute_vertex_tangents': 'محاسبه مماس ها', + 'sidebar/geometry/center': 'وسط', + 'sidebar/geometry/export': 'اکسپورت جیسون', + + 'sidebar/geometry/box_geometry/width': 'عرض', + 'sidebar/geometry/box_geometry/height': 'ارتفاع', + 'sidebar/geometry/box_geometry/depth': 'عمق', + 'sidebar/geometry/box_geometry/widthseg': 'ارجاع عرض', + 'sidebar/geometry/box_geometry/heightseg': 'ارجاع ارتفاع', + 'sidebar/geometry/box_geometry/depthseg': 'ارجاع عمق', + + 'sidebar/geometry/buffer_geometry/attributes': 'صفات', + 'sidebar/geometry/buffer_geometry/index': 'شاخص', + 'sidebar/geometry/buffer_geometry/morphAttributes': 'صفات شکل (مورف)', + 'sidebar/geometry/buffer_geometry/morphRelative': 'صفات نسبی (رلتیو)', + + 'sidebar/geometry/capsule_geometry/radius': 'شعاع', + 'sidebar/geometry/capsule_geometry/length': 'طول', + 'sidebar/geometry/capsule_geometry/capseg': 'Cap Seg', + 'sidebar/geometry/capsule_geometry/radialseg': 'Radial Seg', + + 'sidebar/geometry/circle_geometry/radius': 'شعاع', + 'sidebar/geometry/circle_geometry/segments': 'بخش ها', + 'sidebar/geometry/circle_geometry/thetastart': 'شروع تتا', + 'sidebar/geometry/circle_geometry/thetalength': 'طول تتا', + + 'sidebar/geometry/cylinder_geometry/radiustop': 'شعاع بالا', + 'sidebar/geometry/cylinder_geometry/radiusbottom': 'شعاع پایین', + 'sidebar/geometry/cylinder_geometry/height': 'ارتفاع', + 'sidebar/geometry/cylinder_geometry/radialsegments': 'بخش های شعاعی', + 'sidebar/geometry/cylinder_geometry/heightsegments': 'بخش های ارتفاع', + 'sidebar/geometry/cylinder_geometry/openended': 'پایان باز', + + 'sidebar/geometry/extrude_geometry/curveSegments': 'بخش های منحنی', + 'sidebar/geometry/extrude_geometry/steps': 'گام ها', + 'sidebar/geometry/extrude_geometry/depth': 'عمق', + 'sidebar/geometry/extrude_geometry/bevelEnabled': 'اریب', + 'sidebar/geometry/extrude_geometry/bevelThickness': 'ضخامت', + 'sidebar/geometry/extrude_geometry/bevelSize': 'سایز', + 'sidebar/geometry/extrude_geometry/bevelOffset': 'افست', + 'sidebar/geometry/extrude_geometry/bevelSegments': 'بخش ها', + 'sidebar/geometry/extrude_geometry/shape': 'تبدیل به شکل', + + 'sidebar/geometry/dodecahedron_geometry/radius': 'شعاع', + 'sidebar/geometry/dodecahedron_geometry/detail': 'جزییات', + + 'sidebar/geometry/icosahedron_geometry/radius': 'شعاع', + 'sidebar/geometry/icosahedron_geometry/detail': 'جزییات', + + 'sidebar/geometry/octahedron_geometry/radius': 'شعاع', + 'sidebar/geometry/octahedron_geometry/detail': 'جزییات', + + 'sidebar/geometry/tetrahedron_geometry/radius': 'شعاع', + 'sidebar/geometry/tetrahedron_geometry/detail': 'جزییات', + + 'sidebar/geometry/lathe_geometry/segments': 'بخش ها', + 'sidebar/geometry/lathe_geometry/phistart': 'شروع فی (°)', + 'sidebar/geometry/lathe_geometry/philength': 'طول فی (°)', + 'sidebar/geometry/lathe_geometry/points': 'امتیاز ها', + + 'sidebar/geometry/plane_geometry/width': 'عرض', + 'sidebar/geometry/plane_geometry/height': 'ارتفاع', + 'sidebar/geometry/plane_geometry/widthsegments': 'بخش عرض', + 'sidebar/geometry/plane_geometry/heightsegments': 'بخش ارتفاع', + + 'sidebar/geometry/ring_geometry/innerRadius': 'شعاع داخلی', + 'sidebar/geometry/ring_geometry/outerRadius': 'شعاع خارجی', + 'sidebar/geometry/ring_geometry/thetaSegments': 'بخش های تتا', + 'sidebar/geometry/ring_geometry/phiSegments': 'بخش های فی', + 'sidebar/geometry/ring_geometry/thetastart': 'شروع تتا', + 'sidebar/geometry/ring_geometry/thetalength': 'طول تتا', + + 'sidebar/geometry/shape_geometry/curveSegments': 'بخش های منحنی', + 'sidebar/geometry/shape_geometry/extrude': 'اکسترود کردن', + + 'sidebar/geometry/sphere_geometry/radius': 'شعاع', + 'sidebar/geometry/sphere_geometry/widthsegments': 'بخش عرض', + 'sidebar/geometry/sphere_geometry/heightsegments': 'بخش ارتفاع', + 'sidebar/geometry/sphere_geometry/phistart': 'شروع فی', + 'sidebar/geometry/sphere_geometry/philength': ' طول فی', + 'sidebar/geometry/sphere_geometry/thetastart': 'شروع تتا', + 'sidebar/geometry/sphere_geometry/thetalength': 'طول تتا', + + 'sidebar/geometry/torus_geometry/radius': 'شعاع', + 'sidebar/geometry/torus_geometry/tube': 'لوله', + 'sidebar/geometry/torus_geometry/radialsegments': 'بخش های شعاعی', + 'sidebar/geometry/torus_geometry/tubularsegments': 'بخش های لوله ای', + 'sidebar/geometry/torus_geometry/arc': 'آرک', + + 'sidebar/geometry/torusKnot_geometry/radius': 'شعاع', + 'sidebar/geometry/torusKnot_geometry/tube': 'لوله', + 'sidebar/geometry/torusKnot_geometry/tubularsegments': 'بخش های لوله ای', + 'sidebar/geometry/torusKnot_geometry/radialsegments': 'بخش های شعاعی', + 'sidebar/geometry/torusKnot_geometry/p': 'P', + 'sidebar/geometry/torusKnot_geometry/q': 'Q', + 'sidebar/geometry/tube_geometry/path': 'مسیر', + 'sidebar/geometry/tube_geometry/radius': 'شعاع', + 'sidebar/geometry/tube_geometry/tube': 'لوله', + 'sidebar/geometry/tube_geometry/tubularsegments': 'بخش های لوله ای', + 'sidebar/geometry/tube_geometry/radialsegments': 'بخش های شعاعی', + 'sidebar/geometry/tube_geometry/closed': 'بسته شده', + 'sidebar/geometry/tube_geometry/curvetype': 'نوع انحنا', + 'sidebar/geometry/tube_geometry/tension': 'تنش', + + 'sidebar/material/new': 'جدید', + 'sidebar/material/copy': 'کپی', + 'sidebar/material/paste': 'پیست', + 'sidebar/material/slot': 'شکاف', + 'sidebar/material/type': 'نوع', + 'sidebar/material/uuid': 'UUID', + 'sidebar/material/name': 'نام', + 'sidebar/material/program': 'برنامه', + 'sidebar/material/info': 'اطلاعات', + 'sidebar/material/vertex': 'راس', + 'sidebar/material/fragment': 'فرگ', + 'sidebar/material/color': 'رنگ', + 'sidebar/material/depthPacking': 'بسته بندی عمق', + 'sidebar/material/roughness': 'زبری', + 'sidebar/material/metalness': 'فلزی بودن', + 'sidebar/material/reflectivity': 'انعکاس', + 'sidebar/material/emissive': 'پرتاب کنندگی', + 'sidebar/material/specular': 'اسپکولار', + 'sidebar/material/shininess': 'درخشندگی', + 'sidebar/material/clearcoat': 'کلیرکت', + 'sidebar/material/clearcoatroughness': 'زبری کلیرکت', + 'sidebar/material/dispersion': 'پراکندگی', + 'sidebar/material/ior': 'IOR', + 'sidebar/material/iridescence': 'رنگین کمانی', + 'sidebar/material/iridescenceIOR': 'IOR تین فیلم', + 'sidebar/material/iridescenceThicknessMax': 'زبری تین فیلم', + 'sidebar/material/sheen': 'درخشش (شین)', + 'sidebar/material/sheenroughness': 'زبری درخشش (شین)', + 'sidebar/material/sheencolor': 'رنگ درخشش (شین)', + 'sidebar/material/transmission': 'انتقال', + 'sidebar/material/attenuationDistance': 'تضعیف فاصله', + 'sidebar/material/attenuationColor': 'تضعیف رنگ', + 'sidebar/material/thickness': 'ضخامت', + 'sidebar/material/vertexcolors': 'رنگ راس ها', + 'sidebar/material/matcap': 'متکپ', + 'sidebar/material/map': 'مپ', + 'sidebar/material/alphamap': 'مپ آلفا', + 'sidebar/material/bumpmap': 'مپ بامپ', + 'sidebar/material/normalmap': 'مپ نرمال', + 'sidebar/material/clearcoatmap': 'مپ کلیرکت', + 'sidebar/material/clearcoatnormalmap': 'مپ معمولی کلیرکت', + 'sidebar/material/clearcoatroughnessmap': 'مپ زبری کلیرکت', + 'sidebar/material/displacementmap': 'مپ جابجایی', + 'sidebar/material/roughnessmap': 'مپ زبری', + 'sidebar/material/metalnessmap': 'مپ فلزی بودن', + 'sidebar/material/specularmap': 'مپ اسپکولار', + 'sidebar/material/iridescencemap': 'مپ رنگین کمانی', + 'sidebar/material/iridescencethicknessmap': 'مپ ضخامت تین فیلم', + 'sidebar/material/sheencolormap': 'مپ رنگ درخشش (شین)', + 'sidebar/material/sheenroughnessmap': 'مپ زبری شین', + 'sidebar/material/envmap': 'مپ محیط', + 'sidebar/material/lightmap': 'مپ نور', + 'sidebar/material/aomap': 'AO مپ', + 'sidebar/material/emissivemap': 'مپ پرتاب کننده', + 'sidebar/material/gradientmap': 'مپ گردینت', + 'sidebar/material/transmissionmap': 'مپ انتقال', + 'sidebar/material/thicknessmap': 'مپ ضخامت', + 'sidebar/material/side': 'سمت', + 'sidebar/material/size': 'سایز', + 'sidebar/material/sizeAttenuation': 'تضعیف سایز', + 'sidebar/material/flatShading': 'سایه زنی تخت', + 'sidebar/material/blending': 'مخلوط کردن', + 'sidebar/material/opacity': 'کدر بودن', + 'sidebar/material/transparent': 'شفاف', + 'sidebar/material/forcesinglepass': 'فورس سینگل پس', + 'sidebar/material/alphatest': 'تست آلفا', + 'sidebar/material/depthtest': 'تست عمق', + 'sidebar/material/depthwrite': 'نوشتن عمق', + 'sidebar/material/wireframe': 'وایرفریم', + 'sidebar/material/userdata': 'داده کاربر', + 'sidebar/material/export': 'اکسپورت جیسون', + + 'sidebar/script/new': 'جدید', + 'sidebar/script/edit': 'ویرایش', + 'sidebar/script/remove': 'حذف', + + 'sidebar/project': 'پروژه ها', + 'sidebar/project/antialias': 'آنتی الآیس', + 'sidebar/project/shadows': 'سایه ها', + 'sidebar/project/toneMapping': 'تون مپینگ', + 'sidebar/project/materials': 'متریال ها', + 'sidebar/project/Assign': 'اختصاص', + + 'sidebar/project/app': 'اپ', + 'sidebar/project/app/play': 'پخش', + 'sidebar/project/app/stop': 'توقف', + 'sidebar/project/app/title': 'تیتر', + 'sidebar/project/app/editable': 'قابل ویرایش', + 'sidebar/project/app/publish': 'انتشار', + + 'sidebar/project/image': 'عکس', + 'sidebar/project/image/samples': 'نمونه ها', + 'sidebar/project/video': 'ویدیو', + + 'sidebar/project/shading': 'سایه زنی', + 'sidebar/project/resolution': 'وضوح', + 'sidebar/project/duration': 'مدت', + 'sidebar/project/render': 'رندر', + + 'sidebar/settings': 'تنظیمات', + 'sidebar/settings/language': 'زبان ها', + + 'sidebar/settings/shortcuts': 'شورت کات ها', + 'sidebar/settings/shortcuts/translate': 'ترجمه', + 'sidebar/settings/shortcuts/rotate': 'چرخش (دوران)', + 'sidebar/settings/shortcuts/scale': 'مقیاس', + 'sidebar/settings/shortcuts/undo': 'بازگشت به عقب', + 'sidebar/settings/shortcuts/focus': 'فوکوس', + + 'sidebar/history': 'هیستوری', + 'sidebar/history/clear': 'پاک کردن', + 'sidebar/history/persistent': 'ماندگار', + + 'toolbar/translate': 'ترجمه', + 'toolbar/rotate': 'چرخش (دوران)', + 'toolbar/scale': 'مقیاس', + 'toolbar/local': 'لوکال', + + 'viewport/controls/grid': 'گرید', + 'viewport/controls/helpers': 'کمک کننده', + + 'viewport/info/object': 'آبجکت', + 'viewport/info/objects': 'آبجکت ها', + 'viewport/info/vertex': 'راس', + 'viewport/info/vertices': 'رئوس', + 'viewport/info/triangle': 'مثلث', + 'viewport/info/triangles': 'مثلث ها', + 'viewport/info/sample': 'نمونه', + 'viewport/info/samples': 'نمونه ها', + 'viewport/info/rendertime': 'زمان رندر', + + 'script/title/vertexShader': 'شیدر راس', + 'script/title/fragmentShader': 'شیدر فرگمنت', + 'script/title/programInfo': 'خواص برنامه' + + }, en: { 'prompt/file/open': 'Any unsaved data will be lost. Are you sure?', diff --git a/examples/files.json b/examples/files.json index 1948537f3331e8..474be30f7c4ef2 100644 --- a/examples/files.json +++ b/examples/files.json @@ -299,6 +299,8 @@ "webgpu_backdrop", "webgpu_backdrop_area", "webgpu_backdrop_water", + "webgpu_camera", + "webgpu_camera_array", "webgpu_camera_logarithmicdepthbuffer", "webgpu_clearcoat", "webgpu_clipping", @@ -407,6 +409,7 @@ "webgpu_procedural_texture", "webgpu_reflection", "webgpu_refraction", + "webgpu_rendertarget_2d-array_3d", "webgpu_rtt", "webgpu_sandbox", "webgpu_shadertoy", @@ -441,6 +444,7 @@ "webgpu_tsl_vfx_flames", "webgpu_tsl_vfx_linkedparticles", "webgpu_tsl_vfx_tornado", + "webgpu_video_frame", "webgpu_video_panorama", "webgpu_volume_cloud", "webgpu_volume_perlin", @@ -512,7 +516,8 @@ "misc_exporter_usdz", "misc_exporter_exr", "misc_exporter_ktx2", - "misc_lookat" + "misc_lookat", + "misc_raycaster_helper" ], "css2d": [ "css2d_label" diff --git a/examples/jsm/animation/CCDIKSolver.js b/examples/jsm/animation/CCDIKSolver.js index d4c8ad3292dd25..c935ac1569392d 100644 --- a/examples/jsm/animation/CCDIKSolver.js +++ b/examples/jsm/animation/CCDIKSolver.js @@ -28,7 +28,7 @@ const _matrix = new Matrix4(); /** * CCD Algorithm - * - https://sites.google.com/site/auraliusproject/ccd-algorithm + * - https://web.archive.org/web/20221206080850/https://sites.google.com/site/auraliusproject/ccd-algorithm * * // ik parameter example * // @@ -330,6 +330,8 @@ class CCDIKHelper extends Object3D { /** * Updates IK bones visualization. + * + * @param {Boolean} force */ updateMatrixWorld( force ) { diff --git a/examples/jsm/controls/ArcballControls.js b/examples/jsm/controls/ArcballControls.js index e61836bae4abe0..00895623c09ca1 100644 --- a/examples/jsm/controls/ArcballControls.js +++ b/examples/jsm/controls/ArcballControls.js @@ -1183,7 +1183,7 @@ class ArcballControls extends Controls { * Remove a mouse action by specifying its mouse/key combination * @param {*} mouse A mouse button (0, 1, 2) or 'WHEEL' for wheel notches * @param {*} key The keyboard modifier ('CTRL', 'SHIFT') or null if key is not needed - * @returns {Boolean} True if the operation has been succesfully removed, false otherwise + * @returns {Boolean} True if the operation has been successfully removed, false otherwise */ unsetMouseAction( mouse, key = null ) { @@ -1452,7 +1452,7 @@ class ArcballControls extends Controls { } /** - * Calculate the trackball radius so that gizmo's diamater will be 2/3 of the minimum side of the camera frustum + * Calculate the trackball radius so that gizmo's diameter will be 2/3 of the minimum side of the camera frustum * @param {Camera} camera * @returns {Number} The trackball radius */ @@ -2225,7 +2225,7 @@ class ArcballControls extends Controls { /** * Set camera fov - * @param {Number} value fov to be setted + * @param {Number} value fov to be set */ setFov( value ) { @@ -2585,7 +2585,7 @@ class ArcballControls extends Controls { /** * Update the trackball FSA * @param {STATE} newState New state of the FSA - * @param {Boolean} updateMatrices If matriices state should be updated + * @param {Boolean} updateMatrices If matrices state should be updated */ updateTbState( newState, updateMatrices ) { diff --git a/examples/jsm/csm/CSMShadowNode.js b/examples/jsm/csm/CSMShadowNode.js index c42154d1aaaa2a..e984bb101d7fc2 100644 --- a/examples/jsm/csm/CSMShadowNode.js +++ b/examples/jsm/csm/CSMShadowNode.js @@ -255,7 +255,7 @@ class CSMShadowNode extends ShadowBaseNode { setupFade() { const cameraNear = reference( 'camera.near', 'float', this ).setGroup( renderGroup ); - const cascades = reference( '_cascades', 'vec2', this ).setGroup( renderGroup ).label( 'cacades' ); + const cascades = reference( '_cascades', 'vec2', this ).setGroup( renderGroup ).label( 'cascades' ); const shadowFar = uniform( 'float' ).setGroup( renderGroup ).label( 'shadowFar' ) .onRenderUpdate( () => Math.min( this.maxFar, this.camera.far ) ); @@ -311,7 +311,7 @@ class CSMShadowNode extends ShadowBaseNode { if ( i === 0 ) { - // dont fade at nearest edge + // don't fade at nearest edge ratio = linearDepth.greaterThan( cascadeCenter ).select( ratio, 1 ); } @@ -331,7 +331,7 @@ class CSMShadowNode extends ShadowBaseNode { setupStandard() { const cameraNear = reference( 'camera.near', 'float', this ).setGroup( renderGroup ); - const cascades = reference( '_cascades', 'vec2', this ).setGroup( renderGroup ).label( 'cacades' ); + const cascades = reference( '_cascades', 'vec2', this ).setGroup( renderGroup ).label( 'cascades' ); const shadowFar = uniform( 'float' ).setGroup( renderGroup ).label( 'shadowFar' ) .onRenderUpdate( () => Math.min( this.maxFar, this.camera.far ) ); diff --git a/examples/jsm/effects/OutlineEffect.js b/examples/jsm/effects/OutlineEffect.js index 3ab6034a8400c9..150a32d25323ee 100644 --- a/examples/jsm/effects/OutlineEffect.js +++ b/examples/jsm/effects/OutlineEffect.js @@ -367,7 +367,7 @@ class OutlineEffect { let keys; - // clear originialMaterials + // clear originalMaterials keys = Object.keys( originalMaterials ); for ( let i = 0, il = keys.length; i < il; i ++ ) { diff --git a/examples/jsm/exporters/PLYExporter.js b/examples/jsm/exporters/PLYExporter.js index b96bb999e6c743..397740af239a6a 100644 --- a/examples/jsm/exporters/PLYExporter.js +++ b/examples/jsm/exporters/PLYExporter.js @@ -124,7 +124,7 @@ class PLYExporter { if ( includeIndices && faceCount !== Math.floor( faceCount ) ) { // point cloud meshes will not have an index array and may not have a - // number of vertices that is divisble by 3 (and therefore representable + // number of vertices that is divisible by 3 (and therefore representable // as triangles) console.error( @@ -206,7 +206,7 @@ class PLYExporter { // 2 uv values at 4 bytes const vertexListLength = vertexCount * ( 4 * 3 + ( includeNormals ? 4 * 3 : 0 ) + ( includeColors ? 3 : 0 ) + ( includeUVs ? 4 * 2 : 0 ) ); - // 1 byte shape desciptor + // 1 byte shape descriptor // 3 vertex indices at ${indexByteCount} bytes const faceListLength = includeIndices ? faceCount * ( indexByteCount * 3 + 1 ) : 0; const output = new DataView( new ArrayBuffer( headerBin.length + vertexListLength + faceListLength ) ); diff --git a/examples/jsm/geometries/InstancedPointsGeometry.js b/examples/jsm/geometries/InstancedPointsGeometry.js deleted file mode 100644 index 8fa2ca328b0172..00000000000000 --- a/examples/jsm/geometries/InstancedPointsGeometry.js +++ /dev/null @@ -1,176 +0,0 @@ -import { - Box3, - Float32BufferAttribute, - InstancedBufferGeometry, - InstancedBufferAttribute, - Sphere, - Vector3 -} from 'three'; - -const _vector = new Vector3(); - -class InstancedPointsGeometry extends InstancedBufferGeometry { - - constructor() { - - super(); - - this.isInstancedPointsGeometry = true; - - this.type = 'InstancedPointsGeometry'; - - const positions = [ - 1, 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; - const uvs = [ 0, 1, 1, 1, 0, 0, 1, 0 ]; - const index = [ 0, 2, 1, 2, 3, 1 ]; - - this.setIndex( index ); - this.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); - this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); - - } - - applyMatrix4( matrix ) { - - const pos = this.attributes.instancePosition; - - if ( pos !== undefined ) { - - pos.applyMatrix4( matrix ); - - pos.needsUpdate = true; - - } - - if ( this.boundingBox !== null ) { - - this.computeBoundingBox(); - - } - - if ( this.boundingSphere !== null ) { - - this.computeBoundingSphere(); - - } - - return this; - - } - - setPositions( array ) { - - let points; - - if ( array instanceof Float32Array ) { - - points = array; - - } else if ( Array.isArray( array ) ) { - - points = new Float32Array( array ); - - } - - this.setAttribute( 'instancePosition', new InstancedBufferAttribute( points, 3 ) ); // xyz - - // - - this.computeBoundingBox(); - this.computeBoundingSphere(); - - this.instanceCount = points.length / 3; - - return this; - - } - - setColors( array ) { - - let colors; - - if ( array instanceof Float32Array ) { - - colors = array; - - } else if ( Array.isArray( array ) ) { - - colors = new Float32Array( array ); - - } - - this.setAttribute( 'instanceColor', new InstancedBufferAttribute( colors, 3 ) ); // rgb - - return this; - - } - - computeBoundingBox() { - - if ( this.boundingBox === null ) { - - this.boundingBox = new Box3(); - - } - - const pos = this.attributes.instancePosition; - - if ( pos !== undefined ) { - - this.boundingBox.setFromBufferAttribute( pos ); - - } - - } - - computeBoundingSphere() { - - if ( this.boundingSphere === null ) { - - this.boundingSphere = new Sphere(); - - } - - if ( this.boundingBox === null ) { - - this.computeBoundingBox(); - - } - - const pos = this.attributes.instancePosition; - - if ( pos !== undefined ) { - - const center = this.boundingSphere.center; - - this.boundingBox.getCenter( center ); - - let maxRadiusSq = 0; - - for ( let i = 0, il = pos.count; i < il; i ++ ) { - - _vector.fromBufferAttribute( pos, i ); - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) ); - - } - - this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); - - if ( isNaN( this.boundingSphere.radius ) ) { - - console.error( 'THREE.InstancedPointsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.', this ); - - } - - } - - } - - toJSON() { - - // todo - - } - -} - -export default InstancedPointsGeometry; diff --git a/examples/jsm/geometries/TextGeometry.js b/examples/jsm/geometries/TextGeometry.js index 9eefd8dbaf1342..9747e04a63cdd0 100644 --- a/examples/jsm/geometries/TextGeometry.js +++ b/examples/jsm/geometries/TextGeometry.js @@ -33,20 +33,9 @@ class TextGeometry extends ExtrudeGeometry { const shapes = font.generateShapes( text, parameters.size ); - // translate parameters to ExtrudeGeometry API - - if ( parameters.depth === undefined && parameters.height !== undefined ) { - - console.warn( 'THREE.TextGeometry: .height is now depreciated. Please use .depth instead' ); // @deprecated, r163 - - } - - parameters.depth = parameters.depth !== undefined ? - parameters.depth : parameters.height !== undefined ? - parameters.height : 50; - // defaults + if ( parameters.depth === undefined ) parameters.depth = 50; if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; diff --git a/examples/jsm/helpers/TextureHelperGPU.js b/examples/jsm/helpers/TextureHelperGPU.js index 225be3f5842098..3f48dd40ddcb59 100644 --- a/examples/jsm/helpers/TextureHelperGPU.js +++ b/examples/jsm/helpers/TextureHelperGPU.js @@ -1,11 +1,13 @@ import { + NodeMaterial, BoxGeometry, BufferAttribute, Mesh, PlaneGeometry, + DoubleSide, Vector3, } from 'three'; -import { NodeMaterial, texture as textureNode, cubeTexture, texture3D, float, vec4 } from 'three/tsl'; +import { texture as textureNode, cubeTexture, texture3D, float, vec4, attribute } from 'three/tsl'; import { mergeGeometries } from '../utils/BufferGeometryUtils.js'; class TextureHelper extends Mesh { @@ -13,17 +15,25 @@ class TextureHelper extends Mesh { constructor( texture, width = 1, height = 1, depth = 1 ) { const material = new NodeMaterial(); + material.side = DoubleSide; + material.transparent = true; material.name = 'TextureHelper'; let colorNode; + const uvw = attribute( 'uvw' ); + if ( texture.isCubeTexture ) { - colorNode = cubeTexture( texture ); + colorNode = cubeTexture( texture ).sample( uvw ); } else if ( texture.isData3DTexture || texture.isCompressed3DTexture ) { - colorNode = texture3D( texture ); + colorNode = texture3D( texture ).sample( uvw ); + + } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { + + colorNode = textureNode( texture ).sample( uvw.xy ).depth( uvw.z ); } else { @@ -122,7 +132,7 @@ function createCubeGeometry( width, height, depth ) { } geometry.deleteAttribute( 'uv' ); - geometry.setAttribute( 'uv', uvw ); + geometry.setAttribute( 'uvw', uvw ); return geometry; @@ -162,7 +172,7 @@ function createSliceGeometry( texture, width, height, depth ) { } geometry.deleteAttribute( 'uv' ); - geometry.setAttribute( 'uv', uvw ); + geometry.setAttribute( 'uvw', uvw ); geometries.push( geometry ); diff --git a/examples/jsm/interactive/InteractiveGroup.js b/examples/jsm/interactive/InteractiveGroup.js index 89ebec3bed6e92..4720f2ffcde7ca 100644 --- a/examples/jsm/interactive/InteractiveGroup.js +++ b/examples/jsm/interactive/InteractiveGroup.js @@ -7,97 +7,154 @@ import { const _pointer = new Vector2(); const _event = { type: '', data: _pointer }; +// TODO: Dispatch pointerevents too + +/** + * The XR events that are mapped to "standard" pointer events + */ +const _events = { + 'move': 'mousemove', + 'select': 'click', + 'selectstart': 'mousedown', + 'selectend': 'mouseup' +}; + const _raycaster = new Raycaster(); class InteractiveGroup extends Group { - listenToPointerEvents( renderer, camera ) { + constructor() { + + super(); + + this.raycaster = new Raycaster(); - const scope = this; - const raycaster = new Raycaster(); + this.element = null; + this.camera = null; - const element = renderer.domElement; + this.controllers = []; - function onPointerEvent( event ) { + this._onPointerEvent = this.onPointerEvent.bind( this ); + this._onXRControllerEvent = this.onXRControllerEvent.bind( this ); - event.stopPropagation(); + } + + onPointerEvent( event ) { - const rect = renderer.domElement.getBoundingClientRect(); + event.stopPropagation(); - _pointer.x = ( event.clientX - rect.left ) / rect.width * 2 - 1; - _pointer.y = - ( event.clientY - rect.top ) / rect.height * 2 + 1; + const rect = this.element.getBoundingClientRect(); - raycaster.setFromCamera( _pointer, camera ); + _pointer.x = ( event.clientX - rect.left ) / rect.width * 2 - 1; + _pointer.y = - ( event.clientY - rect.top ) / rect.height * 2 + 1; - const intersects = raycaster.intersectObjects( scope.children, false ); + this.raycaster.setFromCamera( _pointer, this.camera ); - if ( intersects.length > 0 ) { + const intersects = this.raycaster.intersectObjects( this.children, false ); - const intersection = intersects[ 0 ]; + if ( intersects.length > 0 ) { - const object = intersection.object; - const uv = intersection.uv; + const intersection = intersects[ 0 ]; - _event.type = event.type; - _event.data.set( uv.x, 1 - uv.y ); + const object = intersection.object; + const uv = intersection.uv; - object.dispatchEvent( _event ); + _event.type = event.type; + _event.data.set( uv.x, 1 - uv.y ); - } + object.dispatchEvent( _event ); } - element.addEventListener( 'pointerdown', onPointerEvent ); - element.addEventListener( 'pointerup', onPointerEvent ); - element.addEventListener( 'pointermove', onPointerEvent ); - element.addEventListener( 'mousedown', onPointerEvent ); - element.addEventListener( 'mouseup', onPointerEvent ); - element.addEventListener( 'mousemove', onPointerEvent ); - element.addEventListener( 'click', onPointerEvent ); + } + + onXRControllerEvent( event ) { + + const controller = event.target; + + _raycaster.setFromXRController( controller ); + + const intersections = _raycaster.intersectObjects( this.children, false ); + + if ( intersections.length > 0 ) { + + const intersection = intersections[ 0 ]; + + const object = intersection.object; + const uv = intersection.uv; + + _event.type = _events[ event.type ]; + _event.data.set( uv.x, 1 - uv.y ); + + object.dispatchEvent( _event ); + + } } - listenToXRControllerEvents( controller ) { + listenToPointerEvents( renderer, camera ) { - const scope = this; + this.camera = camera; + this.element = renderer.domElement; - // TODO: Dispatch pointerevents too + this.element.addEventListener( 'pointerdown', this._onPointerEvent ); + this.element.addEventListener( 'pointerup', this._onPointerEvent ); + this.element.addEventListener( 'pointermove', this._onPointerEvent ); + this.element.addEventListener( 'mousedown', this._onPointerEvent ); + this.element.addEventListener( 'mouseup', this._onPointerEvent ); + this.element.addEventListener( 'mousemove', this._onPointerEvent ); + this.element.addEventListener( 'click', this._onPointerEvent ); - const events = { - 'move': 'mousemove', - 'select': 'click', - 'selectstart': 'mousedown', - 'selectend': 'mouseup' - }; + } - function onXRControllerEvent( event ) { + disconnectionPointerEvents() { - const controller = event.target; + if ( this.element !== null ) { - _raycaster.setFromXRController( controller ); + this.element.removeEventListener( 'pointerdown', this._onPointerEvent ); + this.element.removeEventListener( 'pointerup', this._onPointerEvent ); + this.element.removeEventListener( 'pointermove', this._onPointerEvent ); + this.element.removeEventListener( 'mousedown', this._onPointerEvent ); + this.element.removeEventListener( 'mouseup', this._onPointerEvent ); + this.element.removeEventListener( 'mousemove', this._onPointerEvent ); + this.element.removeEventListener( 'click', this._onPointerEvent ); - const intersections = _raycaster.intersectObjects( scope.children, false ); + } - if ( intersections.length > 0 ) { + } - const intersection = intersections[ 0 ]; + listenToXRControllerEvents( controller ) { - const object = intersection.object; - const uv = intersection.uv; + this.controllers.push( controller ); + controller.addEventListener( 'move', this._onXRControllerEvent ); + controller.addEventListener( 'select', this._onXRControllerEvent ); + controller.addEventListener( 'selectstart', this._onXRControllerEvent ); + controller.addEventListener( 'selectend', this._onXRControllerEvent ); - _event.type = events[ event.type ]; - _event.data.set( uv.x, 1 - uv.y ); + } + + disconnectXrControllerEvents() { - object.dispatchEvent( _event ); + for ( const controller of this.controllers ) { - } + controller.removeEventListener( 'move', this._onXRControllerEvent ); + controller.removeEventListener( 'select', this._onXRControllerEvent ); + controller.removeEventListener( 'selectstart', this._onXRControllerEvent ); + controller.removeEventListener( 'selectend', this._onXRControllerEvent ); } - controller.addEventListener( 'move', onXRControllerEvent ); - controller.addEventListener( 'select', onXRControllerEvent ); - controller.addEventListener( 'selectstart', onXRControllerEvent ); - controller.addEventListener( 'selectend', onXRControllerEvent ); + } + + disconnect() { + + this.disconnectionPointerEvents(); + this.disconnectXrControllerEvents(); + + this.camera = null; + this.element = null; + + this.controllers = []; } diff --git a/examples/jsm/libs/demuxer_mp4.js b/examples/jsm/libs/demuxer_mp4.js new file mode 100644 index 00000000000000..d5cd68de2526c0 --- /dev/null +++ b/examples/jsm/libs/demuxer_mp4.js @@ -0,0 +1,109 @@ +import MP4Box from 'https://cdn.jsdelivr.net/npm/mp4box@0.5.3/+esm'; + +// From: https://w3c.github.io/webcodecs/samples/video-decode-display/ + +// Wraps an MP4Box File as a WritableStream underlying sink. +class MP4FileSink { + #setStatus = null; + #file = null; + #offset = 0; + + constructor(file, setStatus) { + this.#file = file; + this.#setStatus = setStatus; + } + + write(chunk) { + // MP4Box.js requires buffers to be ArrayBuffers, but we have a Uint8Array. + const buffer = new ArrayBuffer(chunk.byteLength); + new Uint8Array(buffer).set(chunk); + + // Inform MP4Box where in the file this chunk is from. + buffer.fileStart = this.#offset; + this.#offset += buffer.byteLength; + + // Append chunk. + this.#setStatus("fetch", (this.#offset / (1024 ** 2)).toFixed(1) + " MiB"); + this.#file.appendBuffer(buffer); + } + + close() { + this.#setStatus("fetch", "Done"); + this.#file.flush(); + } +} + +// Demuxes the first video track of an MP4 file using MP4Box, calling +// `onConfig()` and `onChunk()` with appropriate WebCodecs objects. +export class MP4Demuxer { + #onConfig = null; + #onChunk = null; + #setStatus = null; + #file = null; + + constructor(uri, {onConfig, onChunk, setStatus}) { + this.#onConfig = onConfig; + this.#onChunk = onChunk; + this.#setStatus = setStatus; + + // Configure an MP4Box File for demuxing. + this.#file = MP4Box.createFile(); + this.#file.onError = error => setStatus("demux", error); + this.#file.onReady = this.#onReady.bind(this); + this.#file.onSamples = this.#onSamples.bind(this); + + // Fetch the file and pipe the data through. + const fileSink = new MP4FileSink(this.#file, setStatus); + fetch(uri).then(response => { + // highWaterMark should be large enough for smooth streaming, but lower is + // better for memory usage. + response.body.pipeTo(new WritableStream(fileSink, {highWaterMark: 2})); + }); + } + + // Get the appropriate `description` for a specific track. Assumes that the + // track is H.264, H.265, VP8, VP9, or AV1. + #description(track) { + const trak = this.#file.getTrackById(track.id); + for (const entry of trak.mdia.minf.stbl.stsd.entries) { + const box = entry.avcC || entry.hvcC || entry.vpcC || entry.av1C; + if (box) { + const stream = new MP4Box.DataStream(undefined, 0, MP4Box.DataStream.BIG_ENDIAN); + box.write(stream); + return new Uint8Array(stream.buffer, 8); // Remove the box header. + } + } + throw new Error("avcC, hvcC, vpcC, or av1C box not found"); + } + + #onReady(info) { + this.#setStatus("demux", "Ready"); + const track = info.videoTracks[0]; + + // Generate and emit an appropriate VideoDecoderConfig. + this.#onConfig({ + // Browser doesn't support parsing full vp8 codec (eg: `vp08.00.41.08`), + // they only support `vp8`. + codec: track.codec.startsWith('vp08') ? 'vp8' : track.codec, + codedHeight: track.video.height, + codedWidth: track.video.width, + description: this.#description(track), + }); + + // Start demuxing. + this.#file.setExtractionOptions(track.id); + this.#file.start(); + } + + #onSamples(track_id, ref, samples) { + // Generate and emit an EncodedVideoChunk for each demuxed sample. + for (const sample of samples) { + this.#onChunk(new EncodedVideoChunk({ + type: sample.is_sync ? "key" : "delta", + timestamp: 1e6 * sample.cts / sample.timescale, + duration: 1e6 * sample.duration / sample.timescale, + data: sample.data + })); + } + } +} diff --git a/examples/jsm/lights/LightProbeGenerator.js b/examples/jsm/lights/LightProbeGenerator.js index 953db7be999fac..9a068bd40b8ff6 100644 --- a/examples/jsm/lights/LightProbeGenerator.js +++ b/examples/jsm/lights/LightProbeGenerator.js @@ -99,7 +99,7 @@ class LightProbeGenerator { // evaluate SH basis functions in direction dir SphericalHarmonics3.getBasisAt( dir, shBasis ); - // accummuulate + // accumulate for ( let j = 0; j < 9; j ++ ) { shCoefficients[ j ].x += shBasis[ j ] * color.r * weight; @@ -242,7 +242,7 @@ class LightProbeGenerator { // evaluate SH basis functions in direction dir SphericalHarmonics3.getBasisAt( dir, shBasis ); - // accummuulate + // accumulate for ( let j = 0; j < 9; j ++ ) { shCoefficients[ j ].x += shBasis[ j ] * color.r * weight; diff --git a/examples/jsm/loaders/BVHLoader.js b/examples/jsm/loaders/BVHLoader.js index dde85a90df8865..716d1b760bc83d 100644 --- a/examples/jsm/loaders/BVHLoader.js +++ b/examples/jsm/loaders/BVHLoader.js @@ -204,7 +204,7 @@ class BVHLoader extends Loader { } /* - Recursively parses the HIERACHY section of the BVH file + Recursively parses the HIERARCHY section of the BVH file - lines: all lines of the file. lines are consumed as we go along. - firstline: line containing the node type and name e.g. 'JOINT hip' diff --git a/examples/jsm/loaders/ColladaLoader.js b/examples/jsm/loaders/ColladaLoader.js index dbff500338a2e7..1fe527b5f90135 100644 --- a/examples/jsm/loaders/ColladaLoader.js +++ b/examples/jsm/loaders/ColladaLoader.js @@ -299,7 +299,7 @@ class ColladaLoader extends Loader { if ( hasChildren === false ) { - // since 'id' attributes can be optional, it's necessary to generate a UUID for unqiue assignment + // since 'id' attributes can be optional, it's necessary to generate a UUID for unique assignment library.animations[ xml.getAttribute( 'id' ) || MathUtils.generateUUID() ] = data; @@ -977,7 +977,7 @@ class ColladaLoader extends Loader { } // we sort the joints in descending order based on the weights. - // this ensures, we only procced the most important joints of the vertex + // this ensures, we only proceed the most important joints of the vertex vertexSkinData.sort( descending ); @@ -1593,7 +1593,7 @@ class ColladaLoader extends Loader { } - // create texture if image is avaiable + // create texture if image is available if ( image !== null ) { @@ -2392,7 +2392,7 @@ class ColladaLoader extends Loader { break; default: - console.warn( 'THREE.ColladaLoader: Unknow primitive type:', primitive.type ); + console.warn( 'THREE.ColladaLoader: Unknown primitive type:', primitive.type ); } @@ -3434,7 +3434,7 @@ class ColladaLoader extends Loader { let i, j, data; // a skeleton can have multiple root bones. collada expresses this - // situtation with multiple "skeleton" tags per controller instance + // situation with multiple "skeleton" tags per controller instance for ( i = 0; i < skeletons.length; i ++ ) { diff --git a/examples/jsm/loaders/GCodeLoader.js b/examples/jsm/loaders/GCodeLoader.js index c2f12800c4c7f7..3f22064700b9b3 100644 --- a/examples/jsm/loaders/GCodeLoader.js +++ b/examples/jsm/loaders/GCodeLoader.js @@ -123,7 +123,7 @@ class GCodeLoader extends Loader { const tokens = lines[ i ].split( ' ' ); const cmd = tokens[ 0 ].toUpperCase(); - //Argumments + //Arguments const args = {}; tokens.splice( 1 ).forEach( function ( token ) { diff --git a/examples/jsm/loaders/GLTFLoader.js b/examples/jsm/loaders/GLTFLoader.js index a1f456a7816d26..4819cf39bf9009 100644 --- a/examples/jsm/loaders/GLTFLoader.js +++ b/examples/jsm/loaders/GLTFLoader.js @@ -2255,6 +2255,9 @@ const ALPHA_MODES = { /** * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material + * + * @param {Object} cache + * @return {Material} */ function createDefaultMaterial( cache ) { @@ -2753,6 +2756,9 @@ class GLTFParser { * Textures) can be reused directly and are not marked here. * * Example: CesiumMilkTruck sample model reuses "Wheel" meshes. + * + * @param {Object} cache + * @param {Object3D} index */ _addNodeRef( cache, index ) { @@ -2768,7 +2774,14 @@ class GLTFParser { } - /** Returns a reference to a shared resource, cloning it if necessary. */ + /** + * Returns a reference to a shared resource, cloning it if necessary. + * + * @param {Object} cache + * @param {Number} index + * @param {Object} object + * @return {Object} + */ _getNodeRef( cache, index, object ) { if ( cache.refs[ index ] <= 1 ) return object; @@ -3653,7 +3666,12 @@ class GLTFParser { } - /** When Object3D instances are targeted by animation, they need unique names. */ + /** + * When Object3D instances are targeted by animation, they need unique names. + * + * @param {String} originalName + * @return {String} + */ createUniqueName( originalName ) { const sanitizedName = PropertyBinding.sanitizeNodeName( originalName || '' ); diff --git a/examples/jsm/loaders/KTX2Loader.js b/examples/jsm/loaders/KTX2Loader.js index b11ae7424b4f78..547bea42ff32f4 100644 --- a/examples/jsm/loaders/KTX2Loader.js +++ b/examples/jsm/loaders/KTX2Loader.js @@ -790,7 +790,12 @@ KTX2Loader.BasisWorker = function () { } - /** Concatenates N byte arrays. */ + /** + * Concatenates N byte arrays. + * + * @param {Uint8Array[]} arrays + * @return {Uint8Array} + */ function concat( arrays ) { if ( arrays.length === 1 ) return arrays[ 0 ]; diff --git a/examples/jsm/loaders/LDrawLoader.js b/examples/jsm/loaders/LDrawLoader.js index 39bf2c4b511d1d..2de9246b320c9a 100644 --- a/examples/jsm/loaders/LDrawLoader.js +++ b/examples/jsm/loaders/LDrawLoader.js @@ -2266,7 +2266,7 @@ class LDrawLoader extends Loader { if ( this.ConditionalLineMaterial === null ) { - throw new Error( 'THREE.LDrawLoader: ConditionalLineMaterial type must be specificed via .setConditionalLineMaterial().' ); + throw new Error( 'THREE.LDrawLoader: ConditionalLineMaterial type must be specified via .setConditionalLineMaterial().' ); } diff --git a/examples/jsm/loaders/LottieLoader.js b/examples/jsm/loaders/LottieLoader.js index 7d5a7798a928a3..c14fc05bbc58af 100644 --- a/examples/jsm/loaders/LottieLoader.js +++ b/examples/jsm/loaders/LottieLoader.js @@ -33,7 +33,7 @@ class LottieLoader extends Loader { const data = JSON.parse( text ); - // lottie uses container.offetWidth and offsetHeight + // lottie uses container.offsetWidth and offsetHeight // to define width/height const container = document.createElement( 'div' ); diff --git a/examples/jsm/loaders/NRRDLoader.js b/examples/jsm/loaders/NRRDLoader.js index c6c77ff3f60538..efb2ee15c59860 100644 --- a/examples/jsm/loaders/NRRDLoader.js +++ b/examples/jsm/loaders/NRRDLoader.js @@ -232,7 +232,7 @@ class NRRDLoader extends Loader { } - //parse the data when registred as one of this type : 'text', 'ascii', 'txt' + //parse the data when registered as one of this type : 'text', 'ascii', 'txt' function parseDataAsText( data, start, end ) { let number = ''; diff --git a/examples/jsm/loaders/PLYLoader.js b/examples/jsm/loaders/PLYLoader.js index 2e83745d7cf1c3..73f9d206811f12 100644 --- a/examples/jsm/loaders/PLYLoader.js +++ b/examples/jsm/loaders/PLYLoader.js @@ -127,19 +127,19 @@ class PLYLoader extends Loader { const lines = headerText.split( /\r\n|\r|\n/ ); let currentElement; - function make_ply_element_property( propertValues, propertyNameMapping ) { + function make_ply_element_property( propertyValues, propertyNameMapping ) { - const property = { type: propertValues[ 0 ] }; + const property = { type: propertyValues[ 0 ] }; if ( property.type === 'list' ) { - property.name = propertValues[ 3 ]; - property.countType = propertValues[ 1 ]; - property.itemType = propertValues[ 2 ]; + property.name = propertyValues[ 3 ]; + property.countType = propertyValues[ 1 ]; + property.itemType = propertyValues[ 2 ]; } else { - property.name = propertValues[ 1 ]; + property.name = propertyValues[ 1 ]; } @@ -576,7 +576,7 @@ class PLYLoader extends Loader { switch ( type ) { - // corespondences for non-specific length types here match rply: + // correspondences for non-specific length types here match rply: case 'int8': case 'char': return { read: ( at ) => { return dataview.getInt8( at ); diff --git a/examples/jsm/loaders/PVRLoader.js b/examples/jsm/loaders/PVRLoader.js index f39f8e75912fc3..60a32588766634 100644 --- a/examples/jsm/loaders/PVRLoader.js +++ b/examples/jsm/loaders/PVRLoader.js @@ -160,7 +160,7 @@ function _parseV2( pvrDatas ) { pvrDatas.numMipmaps = numMipmaps + 1; // guess cubemap type seems tricky in v2 - // it juste a pvr containing 6 surface (no explicit cubemap type) + // it's just a pvr containing 6 surface (no explicit cubemap type) pvrDatas.isCubemap = ( numSurfs === 6 ); return _extract( pvrDatas ); diff --git a/examples/jsm/loaders/SVGLoader.js b/examples/jsm/loaders/SVGLoader.js index 196e42b3875bb1..db1ea511dfe686 100644 --- a/examples/jsm/loaders/SVGLoader.js +++ b/examples/jsm/loaders/SVGLoader.js @@ -1633,7 +1633,7 @@ class SVGLoader extends Loader { ( curve.aEndAngle - curve.aStartAngle ) % ( 2 * Math.PI ) < Number.EPSILON; // Do not touch angles of a full ellipse because after transformation they - // would converge to a sinle value effectively removing the whole curve + // would converge to a single value effectively removing the whole curve if ( ! isFullEllipse ) { @@ -2124,7 +2124,7 @@ class SVGLoader extends Loader { // check if the center of the bounding box is in the bounding box of the paths. // this is a pruning method to limit the search of intersections in paths that can't envelop of the current path. - // if a path envelops another path. The center of that oter path, has to be inside the bounding box of the enveloping path. + // if a path envelops another path. The center of that other path, has to be inside the bounding box of the enveloping path. if ( path.boundingBox.containsPoint( center ) ) { const intersections = getIntersections( scanline, path.points ); diff --git a/examples/jsm/loaders/TDSLoader.js b/examples/jsm/loaders/TDSLoader.js index 0eeeaf1be71147..c88879f74ecc0e 100644 --- a/examples/jsm/loaders/TDSLoader.js +++ b/examples/jsm/loaders/TDSLoader.js @@ -398,7 +398,7 @@ class TDSLoader extends Loader { } else if ( next.id === MESH_MATRIX ) { - this.debugMessage( ' Tranformation Matrix (TODO)' ); + this.debugMessage( ' Transformation Matrix (TODO)' ); const values = []; for ( let i = 0; i < 12; i ++ ) { diff --git a/examples/jsm/loaders/VRMLLoader.js b/examples/jsm/loaders/VRMLLoader.js index e8e6022d2eca72..9182c906c65d4a 100644 --- a/examples/jsm/loaders/VRMLLoader.js +++ b/examples/jsm/loaders/VRMLLoader.js @@ -250,7 +250,7 @@ class VRMLLoader extends Loader { function createVisitor( BaseVRMLVisitor ) { - // the visitor is created dynmaically based on the given base class + // the visitor is created dynamically based on the given base class class VRMLToASTVisitor extends BaseVRMLVisitor { @@ -1890,7 +1890,7 @@ class VRMLLoader extends Loader { // if the colorIndex field is not empty, then one color is used for each polyline of the IndexedLineSet. - const expandedColorIndex = expandLineIndex( colorIndex ); // compute colors for each line segment (rendering primitve) + const expandedColorIndex = expandLineIndex( colorIndex ); // compute colors for each line segment (rendering primitive) colorAttribute = computeAttributeFromIndexedData( expandedLineIndex, expandedColorIndex, color, 3 ); // compute data on vertex level } else { @@ -1907,8 +1907,8 @@ class VRMLLoader extends Loader { // if the colorIndex field is not empty, then colors are applied to each vertex of the IndexedLineSet - const flattenLineColors = flattenData( color, colorIndex ); // compute colors for each VRML primitve - const expandedLineColors = expandLineData( flattenLineColors, coordIndex ); // compute colors for each line segment (rendering primitve) + const flattenLineColors = flattenData( color, colorIndex ); // compute colors for each VRML primitive + const expandedLineColors = expandLineData( flattenLineColors, coordIndex ); // compute colors for each line segment (rendering primitive) colorAttribute = computeAttributeFromLineData( expandedLineIndex, expandedLineColors ); // compute data on vertex level @@ -1916,7 +1916,7 @@ class VRMLLoader extends Loader { // if the colorIndex field is empty, then the coordIndex field is used to choose colors from the Color node - const expandedLineColors = expandLineData( color, coordIndex ); // compute colors for each line segment (rendering primitve) + const expandedLineColors = expandLineData( color, coordIndex ); // compute colors for each line segment (rendering primitive) colorAttribute = computeAttributeFromLineData( expandedLineIndex, expandedLineColors ); // compute data on vertex level } @@ -2748,7 +2748,7 @@ class VRMLLoader extends Loader { const indices = []; - // since face defintions can have more than three vertices, it's necessary to + // since face definitions can have more than three vertices, it's necessary to // perform a simple triangulation let start = 0; @@ -3123,7 +3123,7 @@ class VRMLLoader extends Loader { * node, but could be applied to other nodes with multiple faces as well. * * When used with the Background node, default is directionIsDown is true if - * interpolating the skyColor down from the Zenith. When interpolationg up from + * interpolating the skyColor down from the Zenith. When interpolating up from * the Nadir i.e. interpolating the groundColor, the directionIsDown is false. * * The first angle is never specified, it is the Zenith (0 rad). Angles are specified diff --git a/examples/jsm/loaders/lwo/IFFParser.js b/examples/jsm/loaders/lwo/IFFParser.js index aec77821ef2da5..65e78f1dcbfb00 100644 --- a/examples/jsm/loaders/lwo/IFFParser.js +++ b/examples/jsm/loaders/lwo/IFFParser.js @@ -463,7 +463,7 @@ class IFFParser { } // holds various data about texture node image state - // Data other thanmipMapLevel unknown + // Data other than mipMapLevel unknown parseImageStateForm() { this.reader.skip( 8 ); // unknown @@ -577,7 +577,7 @@ class IFFParser { fileName: '' }; - // seach STIL block + // search STIL block while ( true ) { var tag = this.reader.getIDTag(); @@ -653,11 +653,11 @@ class IFFParser { var number = this.reader.getUint16(); var flags = this.reader.getUint16(); // If the least significant bit of flags is set, the layer is hidden. - var pivot = this.reader.getFloat32Array( 3 ); // Note: this seems to be superflous, as the geometry is translated when pivot is present + var pivot = this.reader.getFloat32Array( 3 ); // Note: this seems to be superfluous, as the geometry is translated when pivot is present var layer = { number: number, flags: flags, // If the least significant bit of flags is set, the layer is hidden. - pivot: [ - pivot[ 0 ], pivot[ 1 ], pivot[ 2 ] ], // Note: this seems to be superflous, as the geometry is translated when pivot is present + pivot: [ - pivot[ 0 ], pivot[ 1 ], pivot[ 2 ] ], // Note: this seems to be superfluous, as the geometry is translated when pivot is present name: this.reader.getString(), }; diff --git a/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js b/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js index 47f62cf25962f1..4f77d407151e99 100644 --- a/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js +++ b/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js @@ -50,7 +50,7 @@ class LDrawConditionalLineMaterial extends NodeMaterial { varyingProperty( 'float', 'discardFlag' ).assign( discardFlag ); - return modelViewProjection(); + return modelViewProjection; } )(); diff --git a/examples/jsm/materials/MeshGouraudMaterial.js b/examples/jsm/materials/MeshGouraudMaterial.js index 56d45c4f867b23..d2feba83b4aca2 100644 --- a/examples/jsm/materials/MeshGouraudMaterial.js +++ b/examples/jsm/materials/MeshGouraudMaterial.js @@ -319,6 +319,8 @@ class MeshGouraudMaterial extends ShaderMaterial { super(); + console.warn( 'THREE.MeshGouraudMaterial: MeshGouraudMaterial has been deprecated and will be removed with r183. Use THREE.MeshLambertMaterial instead.' ); // @deprecated r173 + this.isMeshGouraudMaterial = true; this.type = 'MeshGouraudMaterial'; diff --git a/examples/jsm/math/ConvexHull.js b/examples/jsm/math/ConvexHull.js index b1368a4ed8ea1a..a62340ceaf019c 100644 --- a/examples/jsm/math/ConvexHull.js +++ b/examples/jsm/math/ConvexHull.js @@ -698,7 +698,7 @@ class ConvexHull { let eyeVertex, maxDistance = 0; - // grap the first available face and start with the first visible vertex of that face + // grab the first available face and start with the first visible vertex of that face const eyeFace = this.assigned.first().face; let vertex = eyeFace.outside; diff --git a/examples/jsm/math/OBB.js b/examples/jsm/math/OBB.js index 29ae1286dc39ba..dd3a4ab59bcc40 100644 --- a/examples/jsm/math/OBB.js +++ b/examples/jsm/math/OBB.js @@ -84,6 +84,10 @@ class OBB { /** * Reference: Closest Point on OBB to Point in Real-Time Collision Detection * by Christer Ericson (chapter 5.1.4) + * + * @param {Vector3} point + * @param {Vector3} result + * @returns {Vector3} */ clampPoint( point, result ) { @@ -146,6 +150,9 @@ class OBB { * Reference: OBB-OBB Intersection in Real-Time Collision Detection * by Christer Ericson (chapter 4.4.1) * + * @param {OBB} obb + * @param {Number} [epsilon=Number.EPSILON] - A small value to prevent arithmetic errors + * @returns {Boolean} */ intersectsOBB( obb, epsilon = Number.EPSILON ) { @@ -285,6 +292,9 @@ class OBB { /** * Reference: Testing Box Against Plane in Real-Time Collision Detection * by Christer Ericson (chapter 5.2.3) + * + * @param {Plane} plane + * @returns {Boolean} */ intersectsPlane( plane ) { @@ -309,6 +319,10 @@ class OBB { /** * Performs a ray/OBB intersection test and stores the intersection point * to the given 3D vector. If no intersection is detected, *null* is returned. + * + * @param {Ray} ray + * @param {Vector3} result + * @return {Vector3?} */ intersectRay( ray, result ) { @@ -347,6 +361,9 @@ class OBB { /** * Performs a ray/OBB intersection test. Returns either true or false if * there is a intersection or not. + * + * @param {Ray} ray + * @returns {Boolean} */ intersectsRay( ray ) { diff --git a/examples/jsm/misc/Volume.js b/examples/jsm/misc/Volume.js index 9725f5328d6675..5e96997316836e 100644 --- a/examples/jsm/misc/Volume.js +++ b/examples/jsm/misc/Volume.js @@ -7,7 +7,7 @@ import { VolumeSlice } from '../misc/VolumeSlice.js'; /** * This class had been written to handle the output of the NRRD loader. - * It contains a volume of data and informations about it. + * It contains a volume of data and information about it. * For now it only handles 3 dimensional data. * See the webgl_loader_nrrd.html example and the loaderNRRD.js file to see how to use this class. * @class diff --git a/examples/jsm/modifiers/CurveModifier.js b/examples/jsm/modifiers/CurveModifier.js index 67b9a71b5af53e..bdff6b7c2b2171 100644 --- a/examples/jsm/modifiers/CurveModifier.js +++ b/examples/jsm/modifiers/CurveModifier.js @@ -139,10 +139,10 @@ export function modifyShader( material, uniforms, numberOfCurves = 1 ) { // chunk import moved in front of modified shader below .replace( '#include ', '' ) - // vec3 transformedNormal declaration overriden below + // vec3 transformedNormal declaration overridden below .replace( '#include ', '' ) - // vec3 transformed declaration overriden below + // vec3 transformed declaration overridden below .replace( '#include ', '' ) // shader override @@ -198,7 +198,7 @@ vec3 transformedNormal = normalMatrix * (basis * objectNormal); } /** - * A helper class for making meshes bend aroudn curves + * A helper class for making meshes bend around curves */ export class Flow { @@ -209,8 +209,8 @@ export class Flow { constructor( mesh, numberOfCurves = 1 ) { const obj3D = mesh.clone(); - const splineTexure = initSplineTexture( numberOfCurves ); - const uniforms = getUniforms( splineTexure ); + const splineTexture = initSplineTexture( numberOfCurves ); + const uniforms = getUniforms( splineTexture ); obj3D.traverse( function ( child ) { if ( @@ -247,7 +247,7 @@ export class Flow { this.curveLengthArray = new Array( numberOfCurves ); this.object3D = obj3D; - this.splineTexure = splineTexure; + this.splineTexture = splineTexture; this.uniforms = uniforms; } @@ -259,7 +259,7 @@ export class Flow { this.uniforms.spineLength.value = curveLength; this.curveLengthArray[ index ] = curveLength; this.curveArray[ index ] = curve; - updateSplineTexture( this.splineTexure, curve, index ); + updateSplineTexture( this.splineTexture, curve, index ); } diff --git a/examples/jsm/modifiers/CurveModifierGPU.js b/examples/jsm/modifiers/CurveModifierGPU.js index f7d89ad3dafc2e..dd2501567651ec 100644 --- a/examples/jsm/modifiers/CurveModifierGPU.js +++ b/examples/jsm/modifiers/CurveModifierGPU.js @@ -157,7 +157,7 @@ export function modifyShader( material, uniforms, numberOfCurves ) { } /** - * A helper class for making meshes bend aroudn curves + * A helper class for making meshes bend around curves */ export class Flow { @@ -168,8 +168,8 @@ export class Flow { constructor( mesh, numberOfCurves = 1 ) { const obj3D = mesh.clone(); - const splineTexure = initSplineTexture( numberOfCurves ); - const uniforms = getUniforms( splineTexure ); + const splineTexture = initSplineTexture( numberOfCurves ); + const uniforms = getUniforms( splineTexture ); obj3D.traverse( function ( child ) { @@ -207,7 +207,7 @@ export class Flow { this.curveLengthArray = new Array( numberOfCurves ); this.object3D = obj3D; - this.splineTexure = splineTexure; + this.splineTexture = splineTexture; this.uniforms = uniforms; } @@ -222,7 +222,7 @@ export class Flow { this.curveLengthArray[ index ] = curveLength; this.curveArray[ index ] = curve; - updateSplineTexture( this.splineTexure, curve, index ); + updateSplineTexture( this.splineTexture, curve, index ); } diff --git a/examples/jsm/modifiers/SimplifyModifier.js b/examples/jsm/modifiers/SimplifyModifier.js index 89fbacfdbc7b96..4408b2efc7d52f 100644 --- a/examples/jsm/modifiers/SimplifyModifier.js +++ b/examples/jsm/modifiers/SimplifyModifier.js @@ -29,7 +29,7 @@ class SimplifyModifier { delete geometry.morphAttributes.normal; const attributes = geometry.attributes; - // this modifier can only process indexed and non-indexed geomtries with at least a position attribute + // this modifier can only process indexed and non-indexed geometries with at least a position attribute for ( const name in attributes ) { @@ -584,7 +584,7 @@ class Vertex { // these will be computed in computeEdgeCostAtVertex() this.collapseCost = 0; // cost of collapsing this vertex, the less the better. aka objdist - this.collapseNeighbor = null; // best candinate for collapsing + this.collapseNeighbor = null; // best candidate for collapsing } diff --git a/examples/jsm/objects/InstancedPoints.js b/examples/jsm/objects/InstancedPoints.js deleted file mode 100644 index 7819dbe95d13b1..00000000000000 --- a/examples/jsm/objects/InstancedPoints.js +++ /dev/null @@ -1,19 +0,0 @@ -import { Mesh, InstancedPointsNodeMaterial } from 'three/webgpu'; - -import InstancedPointsGeometry from '../geometries/InstancedPointsGeometry.js'; - -class InstancedPoints extends Mesh { - - constructor( geometry = new InstancedPointsGeometry(), material = new InstancedPointsNodeMaterial() ) { - - super( geometry, material ); - - this.isInstancedPoints = true; - - this.type = 'InstancedPoints'; - - } - -} - -export default InstancedPoints; diff --git a/examples/jsm/objects/Sky.js b/examples/jsm/objects/Sky.js index 55cdb33a478cc1..8fb0678622a5dd 100644 --- a/examples/jsm/objects/Sky.js +++ b/examples/jsm/objects/Sky.js @@ -77,7 +77,7 @@ Sky.SkyShader = { // wavelength of used primaries, according to preetham const vec3 lambda = vec3( 680E-9, 550E-9, 450E-9 ); - // this pre-calcuation replaces older TotalRayleigh(vec3 lambda) function: + // this pre-calculation replaces older TotalRayleigh(vec3 lambda) function: // (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn)) const vec3 totalRayleigh = vec3( 5.804542996261093E-6, 1.3562911419845635E-5, 3.0265902468824876E-5 ); @@ -120,7 +120,7 @@ Sky.SkyShader = { float rayleighCoefficient = rayleigh - ( 1.0 * ( 1.0 - vSunfade ) ); - // extinction (absorbtion + out scattering) + // extinction (absorption + out scattering) // rayleigh coefficients vBetaR = totalRayleigh * rayleighCoefficient; diff --git a/examples/jsm/objects/SkyMesh.js b/examples/jsm/objects/SkyMesh.js index 45e0f1adb30f66..b77ad7fb7d2156 100644 --- a/examples/jsm/objects/SkyMesh.js +++ b/examples/jsm/objects/SkyMesh.js @@ -47,7 +47,7 @@ class SkyMesh extends Mesh { // wavelength of used primaries, according to preetham // const lambda = vec3( 680E-9, 550E-9, 450E-9 ); - // this pre-calcuation replaces older TotalRayleigh(vec3 lambda) function: + // this pre-calculation replaces older TotalRayleigh(vec3 lambda) function: // (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn)) const totalRayleigh = vec3( 5.804542996261093E-6, 1.3562911419845635E-5, 3.0265902468824876E-5 ); @@ -85,7 +85,7 @@ class SkyMesh extends Mesh { const rayleighCoefficient = this.rayleigh.sub( float( 1.0 ).mul( float( 1.0 ).sub( vSunfade ) ) ); - // extinction (absorbtion + out scattering) + // extinction (absorption + out scattering) // rayleigh coefficients varyingProperty( 'vec3', 'vBetaR' ).assign( totalRayleigh.mul( rayleighCoefficient ) ); @@ -98,7 +98,7 @@ class SkyMesh extends Mesh { // position - const position = modelViewProjection(); + const position = modelViewProjection; position.z.assign( position.w ); // set z to camera.far return position; diff --git a/examples/jsm/objects/Water2.js b/examples/jsm/objects/Water2.js index 354ae4f41c3c1a..ea2a02f2a58ed4 100644 --- a/examples/jsm/objects/Water2.js +++ b/examples/jsm/objects/Water2.js @@ -132,7 +132,7 @@ class Water extends Mesh { this.material.uniforms[ 'reflectivity' ].value = reflectivity; this.material.uniforms[ 'textureMatrix' ].value = textureMatrix; - // inital values + // initial values this.material.uniforms[ 'config' ].value.x = 0; // flowMapOffset0 this.material.uniforms[ 'config' ].value.y = halfCycle; // flowMapOffset1 diff --git a/examples/jsm/objects/WaterMesh.js b/examples/jsm/objects/WaterMesh.js index 267e9975db0c1f..6d9e643745acb5 100644 --- a/examples/jsm/objects/WaterMesh.js +++ b/examples/jsm/objects/WaterMesh.js @@ -2,10 +2,10 @@ import { Color, Mesh, Vector3, - NodeMaterial + MeshLambertNodeMaterial } from 'three/webgpu'; -import { Fn, add, cameraPosition, div, normalize, positionWorld, sub, time, texture, vec2, vec3, vec4, max, dot, reflect, pow, length, float, uniform, reflector, mul, mix } from 'three/tsl'; +import { Fn, add, cameraPosition, div, normalize, positionWorld, sub, time, texture, vec2, vec3, max, dot, reflect, pow, length, float, uniform, reflector, mul, mix, diffuseColor } from 'three/tsl'; /** * Work based on : @@ -18,7 +18,7 @@ class WaterMesh extends Mesh { constructor( geometry, options ) { - const material = new NodeMaterial(); + const material = new MeshLambertNodeMaterial(); super( geometry, material ); @@ -26,7 +26,7 @@ class WaterMesh extends Mesh { this.resolution = options.resolution !== undefined ? options.resolution : 0.5; - // uniforms + // Uniforms this.waterNormals = texture( options.waterNormals ); this.alpha = uniform( options.alpha !== undefined ? options.alpha : 1.0 ); @@ -58,25 +58,32 @@ class WaterMesh extends Mesh { } ); - const fragmentNode = Fn( () => { + const noise = getNoise( positionWorld.xz.mul( this.size ) ); + const surfaceNormal = normalize( noise.xzy.mul( 1.5, 1.0, 1.5 ) ); - const noise = getNoise( positionWorld.xz.mul( this.size ) ); - const surfaceNormal = normalize( noise.xzy.mul( 1.5, 1.0, 1.5 ) ); + const worldToEye = cameraPosition.sub( positionWorld ); + const eyeDirection = normalize( worldToEye ); - const diffuseLight = vec3( 0 ).toVar(); - const specularLight = vec3( 0 ).toVar(); + const reflection = normalize( reflect( this.sunDirection.negate(), surfaceNormal ) ); + const direction = max( 0.0, dot( eyeDirection, reflection ) ); + const specularLight = pow( direction, 100 ).mul( this.sunColor ).mul( 2.0 ); + const diffuseLight = max( dot( this.sunDirection, surfaceNormal ), 0.0 ).mul( this.sunColor ).mul( 0.5 ); - const worldToEye = cameraPosition.sub( positionWorld ); - const eyeDirection = normalize( worldToEye ); + const distance = length( worldToEye ); - const reflection = normalize( reflect( this.sunDirection.negate(), surfaceNormal ) ); - const direction = max( 0.0, dot( eyeDirection, reflection ) ); - specularLight.addAssign( pow( direction, 100 ).mul( this.sunColor ).mul( 2.0 ) ); - diffuseLight.addAssign( max( dot( this.sunDirection, surfaceNormal ), 0.0 ).mul( this.sunColor ).mul( 0.5 ) ); + const distortion = surfaceNormal.xz.mul( float( 0.001 ).add( float( 1.0 ).div( distance ) ) ).mul( this.distortionScale ); - const distance = length( worldToEye ); + // Material - const distortion = surfaceNormal.xz.mul( float( 0.001 ).add( float( 1.0 ).div( distance ) ) ).mul( this.distortionScale ); + material.transparent = true; + + material.opacityNode = this.alpha; + + material.shadowPositionNode = positionWorld.add( distortion ); + + material.setupOutgoingLight = () => diffuseColor.rgb; // backwards compatibility + + material.colorNode = Fn( () => { const mirrorSampler = reflector(); mirrorSampler.uvNode = mirrorSampler.uvNode.add( distortion ); @@ -90,12 +97,10 @@ class WaterMesh extends Mesh { const scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ).mul( this.waterColor ); const albedo = mix( this.sunColor.mul( diffuseLight ).mul( 0.3 ).add( scatter ), mirrorSampler.rgb.mul( specularLight ).add( mirrorSampler.rgb.mul( 0.9 ) ).add( vec3( 0.1 ) ), reflectance ); - return vec4( albedo, this.alpha ); + return albedo; } )(); - material.fragmentNode = fragmentNode; - } } diff --git a/examples/jsm/postprocessing/BloomPass.js b/examples/jsm/postprocessing/BloomPass.js index 14b0554d1bcf88..5649f8de901918 100644 --- a/examples/jsm/postprocessing/BloomPass.js +++ b/examples/jsm/postprocessing/BloomPass.js @@ -71,7 +71,7 @@ class BloomPass extends Pass { if ( maskActive ) renderer.state.buffers.stencil.setTest( false ); - // Render quad with blured scene into texture (convolution pass 1) + // Render quad with blurred scene into texture (convolution pass 1) this.fsQuad.material = this.materialConvolution; @@ -83,7 +83,7 @@ class BloomPass extends Pass { this.fsQuad.render( renderer ); - // Render quad with blured scene into texture (convolution pass 2) + // Render quad with blurred scene into texture (convolution pass 2) this.convolutionUniforms[ 'tDiffuse' ].value = this.renderTargetX.texture; this.convolutionUniforms[ 'uImageIncrement' ].value = BloomPass.blurY; diff --git a/examples/jsm/postprocessing/OutlinePass.js b/examples/jsm/postprocessing/OutlinePass.js index 7ccfc75d72eac9..19d75ed224cd3a 100644 --- a/examples/jsm/postprocessing/OutlinePass.js +++ b/examples/jsm/postprocessing/OutlinePass.js @@ -81,10 +81,10 @@ class OutlinePass extends Pass { const MAX_EDGE_THICKNESS = 4; const MAX_EDGE_GLOW = 4; - this.separableBlurMaterial1 = this.getSeperableBlurMaterial( MAX_EDGE_THICKNESS ); + this.separableBlurMaterial1 = this.getSeparableBlurMaterial( MAX_EDGE_THICKNESS ); this.separableBlurMaterial1.uniforms[ 'texSize' ].value.set( resx, resy ); this.separableBlurMaterial1.uniforms[ 'kernelRadius' ].value = 1; - this.separableBlurMaterial2 = this.getSeperableBlurMaterial( MAX_EDGE_GLOW ); + this.separableBlurMaterial2 = this.getSeparableBlurMaterial( MAX_EDGE_GLOW ); this.separableBlurMaterial2.uniforms[ 'texSize' ].value.set( Math.round( resx / 2 ), Math.round( resy / 2 ) ); this.separableBlurMaterial2.uniforms[ 'kernelRadius' ].value = MAX_EDGE_GLOW; @@ -241,7 +241,7 @@ class OutlinePass extends Pass { } else if ( object.isPoints || object.isLine ) { - // the visibilty of points and lines is always set to false in order to + // the visibility of points and lines is always set to false in order to // not affect the outline computation if ( bVisible === true ) { @@ -521,7 +521,7 @@ class OutlinePass extends Pass { } - getSeperableBlurMaterial( maxRadius ) { + getSeparableBlurMaterial( maxRadius ) { return new ShaderMaterial( { diff --git a/examples/jsm/postprocessing/SSAOPass.js b/examples/jsm/postprocessing/SSAOPass.js index fdf4a13e9e7680..8a82169ca42d44 100644 --- a/examples/jsm/postprocessing/SSAOPass.js +++ b/examples/jsm/postprocessing/SSAOPass.js @@ -167,7 +167,7 @@ class SSAOPass extends Pass { this.copyMaterial.dispose(); this.depthRenderMaterial.dispose(); - // dipsose full screen quad + // dispose full screen quad this.fsQuad.dispose(); diff --git a/examples/jsm/postprocessing/SSRPass.js b/examples/jsm/postprocessing/SSRPass.js index 19f2664879ba70..30c8d7ebe769ec 100644 --- a/examples/jsm/postprocessing/SSRPass.js +++ b/examples/jsm/postprocessing/SSRPass.js @@ -335,7 +335,7 @@ class SSRPass extends Pass { this.copyMaterial.dispose(); this.depthRenderMaterial.dispose(); - // dipsose full screen quad + // dispose full screen quad this.fsQuad.dispose(); diff --git a/examples/jsm/postprocessing/UnrealBloomPass.js b/examples/jsm/postprocessing/UnrealBloomPass.js index 48a244051df0ff..35d6c325cf8229 100644 --- a/examples/jsm/postprocessing/UnrealBloomPass.js +++ b/examples/jsm/postprocessing/UnrealBloomPass.js @@ -92,7 +92,7 @@ class UnrealBloomPass extends Pass { for ( let i = 0; i < this.nMips; i ++ ) { - this.separableBlurMaterials.push( this.getSeperableBlurMaterial( kernelSizeArray[ i ] ) ); + this.separableBlurMaterials.push( this.getSeparableBlurMaterial( kernelSizeArray[ i ] ) ); this.separableBlurMaterials[ i ].uniforms[ 'invSize' ].value = new Vector2( 1 / resx, 1 / resy ); @@ -296,7 +296,7 @@ class UnrealBloomPass extends Pass { } - getSeperableBlurMaterial( kernelRadius ) { + getSeparableBlurMaterial( kernelRadius ) { const coefficients = []; diff --git a/examples/jsm/shaders/BokehShader2.js b/examples/jsm/shaders/BokehShader2.js index 3bb0dcf4061549..ec8d78bc3115be 100644 --- a/examples/jsm/shaders/BokehShader2.js +++ b/examples/jsm/shaders/BokehShader2.js @@ -104,7 +104,7 @@ const BokehShader = { float vignout = 1.3; // vignetting outer border float vignin = 0.0; // vignetting inner border - float vignfade = 22.0; // f-stops till vignete fades + float vignfade = 22.0; // f-stops till vignette fades uniform bool shaderFocus; // disable if you use external focalDepth value diff --git a/examples/jsm/shaders/GodRaysShader.js b/examples/jsm/shaders/GodRaysShader.js index ac4ca6f8ca14fd..d758cd5815fd3f 100644 --- a/examples/jsm/shaders/GodRaysShader.js +++ b/examples/jsm/shaders/GodRaysShader.js @@ -12,7 +12,7 @@ import { * sample count to produce a blur filter with large support. * * My implementation performs 3 passes, similar to the implementation from Sousa. I found - * just 6 samples per pass produced acceptible results. The blur is applied three times, + * just 6 samples per pass produced acceptable results. The blur is applied three times, * with decreasing filter support. The result is equivalent to a single pass with * 6*6*6 = 216 samples. * @@ -136,12 +136,12 @@ const GodRaysGenerateShader = { // - see http://code.google.com/p/chromium/issues/detail?id=153105 /* - // Unrolling didnt do much on my hardware (ATI Mobility Radeon 3450), + // Unrolling didn't do much on my hardware (ATI Mobility Radeon 3450), // so i've just left the loop "for ( float i = 0.0; i < TAPS_PER_PASS; i += 1.0 ) {", - // Accumulate samples, making sure we dont walk past the light source. + // Accumulate samples, making sure we don't walk past the light source. // The check for uv.y < 1 would not be necessary with "border" UV wrap // mode, with a black border color. I don't think this is currently diff --git a/examples/jsm/shaders/SobelOperatorShader.js b/examples/jsm/shaders/SobelOperatorShader.js index 4b8cb9039c18e0..6eb1968fa68748 100644 --- a/examples/jsm/shaders/SobelOperatorShader.js +++ b/examples/jsm/shaders/SobelOperatorShader.js @@ -79,7 +79,7 @@ const SobelOperatorShader = { Gy[0][1] * tx0y1 + Gy[1][1] * tx1y1 + Gy[2][1] * tx2y1 + Gy[0][2] * tx0y2 + Gy[1][2] * tx1y2 + Gy[2][2] * tx2y2; - // magnitute of the total gradient + // magnitude of the total gradient float G = sqrt( ( valueGx * valueGx ) + ( valueGy * valueGy ) ); diff --git a/examples/jsm/tsl/display/AfterImageNode.js b/examples/jsm/tsl/display/AfterImageNode.js index 5f7cb8644194b7..4367b25dcdd59f 100644 --- a/examples/jsm/tsl/display/AfterImageNode.js +++ b/examples/jsm/tsl/display/AfterImageNode.js @@ -1,11 +1,18 @@ -import { RenderTarget, Vector2, QuadMesh, NodeMaterial, PostProcessingUtils, TempNode, NodeUpdateType } from 'three/webgpu'; +import { RenderTarget, Vector2, QuadMesh, NodeMaterial, RendererUtils, TempNode, NodeUpdateType } from 'three/webgpu'; import { nodeObject, Fn, float, vec4, uv, texture, passTexture, uniform, sign, max, convertToTexture } from 'three/tsl'; +/** @module AfterImageNode **/ + const _size = /*@__PURE__*/ new Vector2(); const _quadMeshComp = /*@__PURE__*/ new QuadMesh(); let _rendererState; +/** + * Post processing node for creating an after image effect. + * + * @augments TempNode + */ class AfterImageNode extends TempNode { static get type() { @@ -14,32 +21,91 @@ class AfterImageNode extends TempNode { } + /** + * Constructs a new after image node. + * + * @param {TextureNode} textureNode - The texture node that represents the input of the effect. + * @param {Number} [damp=0.96] - The damping intensity. A higher value means a stronger after image effect. + */ constructor( textureNode, damp = 0.96 ) { super( 'vec4' ); + /** + * The texture node that represents the input of the effect. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The texture represents the pervious frame. + * + * @type {TextureNode} + */ this.textureNodeOld = texture(); + + /** + * The damping intensity as a uniform node. + * + * @type {UniformNode} + */ this.damp = uniform( damp ); + /** + * The render target used for compositing the effect. + * + * @private + * @type {RenderTarget} + */ this._compRT = new RenderTarget( 1, 1, { depthBuffer: false } ); this._compRT.texture.name = 'AfterImageNode.comp'; + /** + * The render target that represents the previous frame. + * + * @private + * @type {RenderTarget} + */ this._oldRT = new RenderTarget( 1, 1, { depthBuffer: false } ); this._oldRT.texture.name = 'AfterImageNode.old'; + /** + * The result of the effect is represented as a separate texture node. + * + * @private + * @type {PassTextureNode} + */ this._textureNode = passTexture( this, this._compRT.texture ); + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders + * its effect once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; } + /** + * Returns the result of the effect as a texture node. + * + * @return {PassTextureNode} A texture node that represents the result of the effect. + */ getTextureNode() { return this._textureNode; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + */ setSize( width, height ) { this._compRT.setSize( width, height ); @@ -47,11 +113,16 @@ class AfterImageNode extends TempNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); // @@ -86,10 +157,16 @@ class AfterImageNode extends TempNode { textureNode.value = currentTexture; - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { const textureNode = this.textureNode; @@ -141,6 +218,10 @@ class AfterImageNode extends TempNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { this._compRT.dispose(); @@ -150,6 +231,14 @@ class AfterImageNode extends TempNode { } +/** + * TSL function for creating an after image node for post processing. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @param {Number} [damp=0.96] - The damping intensity. A higher value means a stronger after image effect. + * @returns {AfterImageNode} + */ export const afterImage = ( node, damp ) => nodeObject( new AfterImageNode( convertToTexture( node ), damp ) ); export default AfterImageNode; diff --git a/examples/jsm/tsl/display/AnaglyphPassNode.js b/examples/jsm/tsl/display/AnaglyphPassNode.js index bbc5c488afa56a..ba5bb2282b98aa 100644 --- a/examples/jsm/tsl/display/AnaglyphPassNode.js +++ b/examples/jsm/tsl/display/AnaglyphPassNode.js @@ -2,6 +2,13 @@ import { Matrix3, NodeMaterial } from 'three/webgpu'; import { clamp, nodeObject, Fn, vec4, uv, uniform, max } from 'three/tsl'; import StereoCompositePassNode from './StereoCompositePassNode.js'; +/** @module AnaglyphPassNode **/ + +/** + * A render pass node that creates an anaglyph effect. + * + * @augments StereoCompositePassNode + */ class AnaglyphPassNode extends StereoCompositePassNode { static get type() { @@ -10,20 +17,43 @@ class AnaglyphPassNode extends StereoCompositePassNode { } + /** + * Constructs a new anaglyph pass node. + * + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + */ constructor( scene, camera ) { super( scene, camera ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ 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 + /** + * Color matrix node for the left eye. + * + * @type {UniformNode} + */ this._colorMatrixLeft = uniform( new Matrix3().fromArray( [ 0.456100, - 0.0400822, - 0.0152161, 0.500484, - 0.0378246, - 0.0205971, 0.176381, - 0.0157589, - 0.00546856 ] ) ); + /** + * Color matrix node for the right eye. + * + * @type {UniformNode} + */ this._colorMatrixRight = uniform( new Matrix3().fromArray( [ - 0.0434706, 0.378476, - 0.0721527, - 0.0879388, 0.73364, - 0.112961, @@ -32,6 +62,12 @@ class AnaglyphPassNode extends StereoCompositePassNode { } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { const uvNode = uv(); @@ -60,4 +96,12 @@ class AnaglyphPassNode extends StereoCompositePassNode { export default AnaglyphPassNode; +/** + * TSL function for creating an anaglyph pass node. + * + * @function + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + * @returns {AnaglyphPassNode} + */ export const anaglyphPass = ( scene, camera ) => nodeObject( new AnaglyphPassNode( scene, camera ) ); diff --git a/examples/jsm/tsl/display/AnamorphicNode.js b/examples/jsm/tsl/display/AnamorphicNode.js index 170d0ca319519a..70c3b7c39f781c 100644 --- a/examples/jsm/tsl/display/AnamorphicNode.js +++ b/examples/jsm/tsl/display/AnamorphicNode.js @@ -1,10 +1,17 @@ -import { RenderTarget, Vector2, TempNode, QuadMesh, NodeMaterial, PostProcessingUtils } from 'three/webgpu'; +import { RenderTarget, Vector2, TempNode, QuadMesh, NodeMaterial, RendererUtils } from 'three/webgpu'; import { nodeObject, Fn, float, NodeUpdateType, uv, passTexture, uniform, convertToTexture, vec2, vec3, Loop, mix, luminance } from 'three/tsl'; +/** @module AnamorphicNode **/ + const _quadMesh = /*@__PURE__*/ new QuadMesh(); let _rendererState; +/** + * Post processing node for adding an anamorphic flare effect. + * + * @augments TempNode + */ class AnamorphicNode extends TempNode { static get type() { @@ -13,34 +20,113 @@ class AnamorphicNode extends TempNode { } + /** + * Constructs a new anamorphic node. + * + * @param {TextureNode} textureNode - The texture node that represents the input of the effect. + * @param {Node} tresholdNode - The threshold is one option to control the intensity and size of the effect. + * @param {Node} scaleNode - Defines the vertical scale of the flares. + * @param {Number} samples - More samples result in larger flares and a more expensive runtime behavior. + */ constructor( textureNode, tresholdNode, scaleNode, samples ) { super( 'vec4' ); + /** + * The texture node that represents the input of the effect. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The threshold is one option to control the intensity and size of the effect. + * + * @type {Node} + */ this.tresholdNode = tresholdNode; + + /** + * Defines the vertical scale of the flares. + * + * @type {Node} + */ this.scaleNode = scaleNode; + + /** + * The color of the flares. + * + * @type {Node} + */ this.colorNode = vec3( 0.1, 0.0, 1.0 ); + + /** + * More samples result in larger flares and a more expensive runtime behavior. + * + * @type {Node} + */ this.samples = samples; + + /** + * The resolution scale. + * + * @type {Vector2} + */ this.resolution = new Vector2( 1, 1 ); + /** + * The internal render target of the effect. + * + * @private + * @type {RenderTarget} + */ this._renderTarget = new RenderTarget( 1, 1, { depthBuffer: false } ); this._renderTarget.texture.name = 'anamorphic'; + /** + * A uniform node holding the inverse resolution value. + * + * @private + * @type {UniformNode} + */ this._invSize = uniform( new Vector2() ); + /** + * The result of the effect is represented as a separate texture node. + * + * @private + * @type {PassTextureNode} + */ this._textureNode = passTexture( this, this._renderTarget.texture ); + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders + * its effect once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; } + /** + * Returns the result of the effect as a texture node. + * + * @return {PassTextureNode} A texture node that represents the result of the effect. + */ getTextureNode() { return this._textureNode; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + */ setSize( width, height ) { this._invSize.value.set( 1 / width, 1 / height ); @@ -52,11 +138,16 @@ class AnamorphicNode extends TempNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); // @@ -81,10 +172,16 @@ class AnamorphicNode extends TempNode { textureNode.value = currentTexture; - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { const textureNode = this.textureNode; @@ -134,6 +231,10 @@ class AnamorphicNode extends TempNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { this._renderTarget.dispose(); @@ -142,6 +243,16 @@ class AnamorphicNode extends TempNode { } +/** + * TSL function for creating an anamorphic flare effect. + * + * @function + * @param {TextureNode} node - The node that represents the input of the effect. + * @param {Node | Number} [threshold=0.9] - The threshold is one option to control the intensity and size of the effect. + * @param {Node | Number} [scale=3] - Defines the vertical scale of the flares. + * @param {Number} [samples=32] - More samples result in larger flares and a more expensive runtime behavior. + * @returns {AnamorphicNode} + */ export const anamorphic = ( node, threshold = .9, scale = 3, samples = 32 ) => nodeObject( new AnamorphicNode( convertToTexture( node ), nodeObject( threshold ), nodeObject( scale ), samples ) ); export default AnamorphicNode; diff --git a/examples/jsm/tsl/display/BleachBypass.js b/examples/jsm/tsl/display/BleachBypass.js index d3f94eaab09527..473705368c1820 100644 --- a/examples/jsm/tsl/display/BleachBypass.js +++ b/examples/jsm/tsl/display/BleachBypass.js @@ -1,5 +1,15 @@ import { float, Fn, vec3, vec4, min, max, mix, luminance } from 'three/tsl'; +/** @module BleachBypass **/ + +/** + * Applies a bleach bypass effect to the given color node. + * + * @function + * @param {Node} color - The color node to apply the sepia for. + * @param {Node} [opacity=1] - Influences how strong the effect is blended with the original color. + * @return {Node} The updated color node. + */ export const bleach = /*@__PURE__*/ Fn( ( [ color, opacity = 1 ] ) => { const base = color; diff --git a/examples/jsm/tsl/display/BloomNode.js b/examples/jsm/tsl/display/BloomNode.js index 7168d1f683b6f2..fe5b4785c3bb94 100644 --- a/examples/jsm/tsl/display/BloomNode.js +++ b/examples/jsm/tsl/display/BloomNode.js @@ -1,6 +1,8 @@ -import { HalfFloatType, RenderTarget, Vector2, Vector3, TempNode, QuadMesh, NodeMaterial, PostProcessingUtils, NodeUpdateType } from 'three/webgpu'; +import { HalfFloatType, RenderTarget, Vector2, Vector3, TempNode, QuadMesh, NodeMaterial, RendererUtils, NodeUpdateType } from 'three/webgpu'; import { nodeObject, Fn, float, uv, passTexture, uniform, Loop, texture, luminance, smoothstep, mix, vec4, uniformArray, add, int } from 'three/tsl'; +/** @module BloomNode **/ + const _quadMesh = /*@__PURE__*/ new QuadMesh(); const _size = /*@__PURE__*/ new Vector2(); @@ -9,6 +11,38 @@ const _BlurDirectionY = /*@__PURE__*/ new Vector2( 0.0, 1.0 ); let _rendererState; +/** + * Post processing node for creating a bloom effect. + * ```js + * const postProcessing = new THREE.PostProcessing( renderer ); + * + * const scenePass = pass( scene, camera ); + * const scenePassColor = scenePass.getTextureNode( 'output' ); + * + * const bloomPass = bloom( scenePassColor ); + * + * postProcessing.outputNode = scenePassColor.add( bloomPass ); + * ``` + * By default, the node affects the entire image. For a selective bloom, + * use the `emissive` material property to control which objects should + * contribute to bloom or not. This can be achieved via MRT. + * ```js + * const postProcessing = new THREE.PostProcessing( renderer ); + * + * const scenePass = pass( scene, camera ); + * scenePass.setMRT( mrt( { + * output, + * emissive + * } ) ); + * + * const scenePassColor = scenePass.getTextureNode( 'output' ); + * const emissivePass = scenePass.getTextureNode( 'emissive' ); + * + * const bloomPass = bloom( emissivePass ); + * postProcessing.outputNode = scenePassColor.add( bloomPass ); + * ``` + * @augments TempNode + */ class BloomNode extends TempNode { static get type() { @@ -17,29 +51,89 @@ class BloomNode extends TempNode { } + /** + * Constructs a new bloom node. + * + * @param {Node} inputNode - The node that represents the input of the effect. + * @param {Number} [strength=1] - The strength of the bloom. + * @param {Number} [radius=0] - The radius of the bloom. + * @param {Number} [threshold=0] - The luminance threshold limits which bright areas contribute to the bloom effect. + */ constructor( inputNode, strength = 1, radius = 0, threshold = 0 ) { super( 'vec4' ); + /** + * The node that represents the input of the effect. + * + * @type {Node} + */ this.inputNode = inputNode; + + /** + * The strength of the bloom. + * + * @type {UniformNode} + */ this.strength = uniform( strength ); + + /** + * The radius of the bloom. + * + * @type {UniformNode} + */ this.radius = uniform( radius ); + + /** + * The luminance threshold limits which bright areas contribute to the bloom effect. + * + * @type {UniformNode} + */ this.threshold = uniform( threshold ); + /** + * Can be used to tweak the extracted luminance from the scene. + * + * @type {UniformNode} + */ this.smoothWidth = uniform( 0.01 ); - // - + /** + * An array that holds the render targets for the horizontal blur passes. + * + * @private + * @type {Array} + */ this._renderTargetsHorizontal = []; + + /** + * An array that holds the render targets for the vertical blur passes. + * + * @private + * @type {Array} + */ this._renderTargetsVertical = []; - this._nMips = 5; - // render targets + /** + * The number if blur mips. + * + * @private + * @type {Number} + */ + this._nMips = 5; + /** + * The render target for the luminance pass. + * + * @private + * @type {RenderTarget} + */ this._renderTargetBright = new RenderTarget( 1, 1, { depthBuffer: false, 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, { depthBuffer: false, type: HalfFloatType } ); @@ -58,33 +152,114 @@ class BloomNode extends TempNode { } - // materials - + /** + * The material for the composite pass. + * + * @private + * @type {NodeMaterial?} + */ this._compositeMaterial = null; + + /** + * The material for the luminance pass. + * + * @private + * @type {NodeMaterial?} + */ this._highPassFilterMaterial = null; - this._separableBlurMaterials = []; - // pass and texture nodes + /** + * The materials for the blur pass. + * + * @private + * @type {Array} + */ + this._separableBlurMaterials = []; + /** + * The result of the luminance pass as a texture node for further processing. + * + * @private + * @type {TextureNode} + */ this._textureNodeBright = texture( this._renderTargetBright.texture ); + + /** + * The result of the first blur pass as a texture node for further processing. + * + * @private + * @type {TextureNode} + */ this._textureNodeBlur0 = texture( this._renderTargetsVertical[ 0 ].texture ); + + /** + * The result of the second blur pass as a texture node for further processing. + * + * @private + * @type {TextureNode} + */ this._textureNodeBlur1 = texture( this._renderTargetsVertical[ 1 ].texture ); + + /** + * The result of the third blur pass as a texture node for further processing. + * + * @private + * @type {TextureNode} + */ this._textureNodeBlur2 = texture( this._renderTargetsVertical[ 2 ].texture ); + + /** + * The result of the fourth blur pass as a texture node for further processing. + * + * @private + * @type {TextureNode} + */ this._textureNodeBlur3 = texture( this._renderTargetsVertical[ 3 ].texture ); + + /** + * The result of the fifth blur pass as a texture node for further processing. + * + * @private + * @type {TextureNode} + */ this._textureNodeBlur4 = texture( this._renderTargetsVertical[ 4 ].texture ); + /** + * The result of the effect is represented as a separate texture node. + * + * @private + * @type {PassTextureNode} + */ this._textureOutput = passTexture( this, this._renderTargetsHorizontal[ 0 ].texture ); + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders + * its effect once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; } + /** + * Returns the result of the effect as a texture node. + * + * @return {PassTextureNode} A texture node that represents the result of the effect. + */ getTextureNode() { return this._textureOutput; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + */ setSize( width, height ) { let resx = Math.round( width / 2 ); @@ -106,24 +281,29 @@ class BloomNode extends TempNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); // const size = renderer.getDrawingBufferSize( _size ); this.setSize( size.width, size.height ); - // 1. Extract Bright Areas + // 1. Extract bright areas renderer.setRenderTarget( this._renderTargetBright ); _quadMesh.material = this._highPassFilterMaterial; _quadMesh.render( renderer ); - // 2. Blur All the mips progressively + // 2. Blur all the mips progressively let inputRenderTarget = this._renderTargetBright; @@ -145,7 +325,7 @@ class BloomNode extends TempNode { } - // 3. Composite All the mips + // 3. Composite all the mips renderer.setRenderTarget( this._renderTargetsHorizontal[ 0 ] ); _quadMesh.material = this._compositeMaterial; @@ -153,10 +333,16 @@ class BloomNode extends TempNode { // restore - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { // luminosity high pass material @@ -183,7 +369,7 @@ class BloomNode extends TempNode { for ( let i = 0; i < this._nMips; i ++ ) { - this._separableBlurMaterials.push( this._getSeperableBlurMaterial( builder, kernelSizeArray[ i ] ) ); + this._separableBlurMaterials.push( this._getSeparableBlurMaterial( builder, kernelSizeArray[ i ] ) ); } @@ -232,6 +418,10 @@ class BloomNode extends TempNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { for ( let i = 0; i < this._renderTargetsHorizontal.length; i ++ ) { @@ -250,7 +440,14 @@ class BloomNode extends TempNode { } - _getSeperableBlurMaterial( builder, kernelRadius ) { + /** + * Create a separable blur material for the given kernel radius. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Number} kernelRadius - The kernel radius. + * @return {NodeMaterial} + */ + _getSeparableBlurMaterial( builder, kernelRadius ) { const coefficients = []; @@ -270,7 +467,7 @@ class BloomNode extends TempNode { const uvNode = uv(); const sampleTexel = ( uv ) => colorTexture.sample( uv ); - const seperableBlurPass = Fn( () => { + const separableBlurPass = Fn( () => { const weightSum = gaussianCoefficients.element( 0 ).toVar(); const diffuseSum = sampleTexel( uvNode ).rgb.mul( weightSum ).toVar(); @@ -291,22 +488,32 @@ class BloomNode extends TempNode { } ); - const seperableBlurMaterial = new NodeMaterial(); - seperableBlurMaterial.fragmentNode = seperableBlurPass().context( builder.getSharedContext() ); - seperableBlurMaterial.name = 'Bloom_seperable'; - seperableBlurMaterial.needsUpdate = true; + const separableBlurMaterial = new NodeMaterial(); + separableBlurMaterial.fragmentNode = separableBlurPass().context( builder.getSharedContext() ); + separableBlurMaterial.name = 'Bloom_separable'; + separableBlurMaterial.needsUpdate = true; // uniforms - seperableBlurMaterial.colorTexture = colorTexture; - seperableBlurMaterial.direction = direction; - seperableBlurMaterial.invSize = invSize; + separableBlurMaterial.colorTexture = colorTexture; + separableBlurMaterial.direction = direction; + separableBlurMaterial.invSize = invSize; - return seperableBlurMaterial; + return separableBlurMaterial; } } +/** + * TSL function for creating a bloom effect. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @param {Number} [strength=1] - The strength of the bloom. + * @param {Number} [radius=0] - The radius of the bloom. + * @param {Number} [threshold=0] - The luminance threshold limits which bright areas contribute to the bloom effect. + * @returns {BloomNode} + */ export const bloom = ( node, strength, radius, threshold ) => nodeObject( new BloomNode( nodeObject( node ), strength, radius, threshold ) ); export default BloomNode; diff --git a/examples/jsm/tsl/display/DenoiseNode.js b/examples/jsm/tsl/display/DenoiseNode.js index a50ef68cc3e630..1a5fbbf2beeee0 100644 --- a/examples/jsm/tsl/display/DenoiseNode.js +++ b/examples/jsm/tsl/display/DenoiseNode.js @@ -2,6 +2,18 @@ import { DataTexture, RepeatWrapping, Vector2, Vector3, TempNode } from 'three/w import { texture, getNormalFromDepth, getViewPosition, convertToTexture, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, luminance, vec2, vec3, vec4, uniformArray, int, dot, max, pow, abs, If, textureSize, sin, cos, mat2, PI } from 'three/tsl'; import { SimplexNoise } from '../../math/SimplexNoise.js'; +/** @module DenoiseNode **/ + +/** + * Post processing node for denoising data like raw screen-space ambient occlusion output. + * Denoise can noticeably improve the quality of ambient occlusion but also add quite some + * overhead to the post processing setup. It's best to make its usage optional (e.g. via + * graphic settings). + * + * Reference: {@link https://openaccess.thecvf.com/content/WACV2021/papers/Khademi_Self-Supervised_Poisson-Gaussian_Denoising_WACV_2021_paper.pdf}. + * + * @augments TempNode + */ class DenoiseNode extends TempNode { static get type() { @@ -10,32 +22,123 @@ class DenoiseNode extends TempNode { } + /** + * Constructs a new denoise node. + * + * @param {TextureNode} textureNode - The texture node that represents the input of the effect (e.g. AO). + * @param {Node} depthNode - A node that represents the scene's depth. + * @param {Node?} normalNode - A node that represents the scene's normals. + * @param {Camera} camera - The camera the scene is rendered with. + */ constructor( textureNode, depthNode, normalNode, camera ) { super( 'vec4' ); + /** + * The texture node that represents the input of the effect (e.g. AO). + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * A node that represents the scene's depth. + * + * @type {Node} + */ this.depthNode = depthNode; + + /** + * A node that represents the scene's normals. If no normals are passed to the + * constructor (because MRT is not available), normals can be automatically + * reconstructed from depth values in the shader. + * + * @type {Node?} + */ this.normalNode = normalNode; + /** + * The node represents the internal noise texture. + * + * @type {TextureNode} + */ this.noiseNode = texture( generateDefaultNoise() ); + /** + * The luma Phi value. + * + * @type {UniformNode} + */ this.lumaPhi = uniform( 5 ); + + /** + * The depth Phi value. + * + * @type {UniformNode} + */ this.depthPhi = uniform( 5 ); + + /** + * The normal Phi value. + * + * @type {UniformNode} + */ this.normalPhi = uniform( 5 ); + + /** + * The radius. + * + * @type {UniformNode} + */ this.radius = uniform( 5 ); + + /** + * The index. + * + * @type {UniformNode} + */ this.index = uniform( 0 ); + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node updates + * its internal uniforms once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; - // uniforms - + /** + * The resolution of the effect. + * + * @private + * @type {UniformNode} + */ this._resolution = uniform( new Vector2() ); - this._sampleVectors = uniformArray( generatePdSamplePointInitializer( 16, 2, 1 ) ); + + /** + * An array of sample vectors. + * + * @private + * @type {UniformArrayNode} + */ + this._sampleVectors = uniformArray( generateDenoiseSamples( 16, 2, 1 ) ); + + /** + * Represents the inverse projection matrix of the scene's camera. + * + * @private + * @type {UniformNode} + */ this._cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); } + /** + * This method is used to update internal uniforms once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore() { const map = this.textureNode.value; @@ -44,7 +147,13 @@ class DenoiseNode extends TempNode { } - setup() { + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ + setup( /* builder */ ) { const uvNode = uv(); @@ -149,23 +258,14 @@ class DenoiseNode extends TempNode { export default DenoiseNode; -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; - -} - +/** + * Generates denoise samples based on the given parameters. + * + * @param {Number} numSamples - The number of samples. + * @param {Number} numRings - The number of rings. + * @param {Number} radiusExponent - The radius exponent. + * @return {Array} The denoise samples. + */ function generateDenoiseSamples( numSamples, numRings, radiusExponent ) { const samples = []; @@ -182,6 +282,12 @@ function generateDenoiseSamples( numSamples, numRings, radiusExponent ) { } +/** + * Generates a default noise texture for the given size. + * + * @param {Number} [size=64] - The texture size. + * @return {DataTexture} The generated noise texture. + */ function generateDefaultNoise( size = 64 ) { const simplex = new SimplexNoise(); @@ -214,4 +320,14 @@ function generateDefaultNoise( size = 64 ) { } +/** + * TSL function for creating a denoise effect. + * + * @function + * @param {Node} node - The node that represents the input of the effect (e.g. AO). + * @param {Node} depthNode - A node that represents the scene's depth. + * @param {Node?} normalNode - A node that represents the scene's normals. + * @param {Camera} camera - The camera the scene is rendered with. + * @returns {DenoiseNode} + */ export const denoise = ( node, depthNode, normalNode, camera ) => nodeObject( new DenoiseNode( convertToTexture( node ), nodeObject( depthNode ), nodeObject( normalNode ), camera ) ); diff --git a/examples/jsm/tsl/display/DepthOfFieldNode.js b/examples/jsm/tsl/display/DepthOfFieldNode.js index bd02401e822fcf..52202310d2b03f 100644 --- a/examples/jsm/tsl/display/DepthOfFieldNode.js +++ b/examples/jsm/tsl/display/DepthOfFieldNode.js @@ -1,6 +1,13 @@ import { TempNode, NodeUpdateType } from 'three/webgpu'; import { convertToTexture, nodeObject, Fn, uv, uniform, vec2, vec4, clamp } from 'three/tsl'; +/** @module DepthOfFieldNode **/ + +/** + * Post processing node for creating depth of field (DOF) effect. + * + * @augments TempNode + */ class DepthOfFieldNode extends TempNode { static get type() { @@ -9,23 +16,78 @@ class DepthOfFieldNode extends TempNode { } + /** + * Constructs a new DOF node. + * + * @param {TextureNode} textureNode - The texture node that represents the input of the effect. + * @param {Node} viewZNode - Represents the viewZ depth values of the scene. + * @param {Node} focusNode - Defines the effect's focus which is the distance along the camera's look direction in world units. + * @param {Node} apertureNode - Defines the effect's aperture. + * @param {Node} maxblurNode - Defines the effect's maximum blur. + */ constructor( textureNode, viewZNode, focusNode, apertureNode, maxblurNode ) { super( 'vec4' ); + /** + * The texture node that represents the input of the effect. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * Represents the viewZ depth values of the scene. + * + * @type {Node} + */ this.viewZNode = viewZNode; + /** + * Defines the effect's focus which is the distance along the camera's look direction in world units. + * + * @type {Node} + */ this.focusNode = focusNode; + + /** + * Defines the effect's aperture. + * + * @type {Node} + */ this.apertureNode = apertureNode; + + /** + * Defines the effect's maximum blur. + * + * @type {Node} + */ this.maxblurNode = maxblurNode; + /** + * Represents the input's aspect ratio. + * + * @private + * @type {UniformNode} + */ this._aspect = uniform( 0 ); + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node updates + * its internal uniforms once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; } + /** + * This method is used to update the effect's uniforms once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore() { const map = this.textureNode.value; @@ -34,6 +96,12 @@ class DepthOfFieldNode extends TempNode { } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ setup() { const textureNode = this.textureNode; @@ -116,4 +184,15 @@ class DepthOfFieldNode extends TempNode { export default DepthOfFieldNode; +/** + * TSL function for creating a depth-of-field effect (DOF) for post processing. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @param {Node} viewZNode - Represents the viewZ depth values of the scene. + * @param {Node | Number} focus - Defines the effect's focus which is the distance along the camera's look direction in world units. + * @param {Node | Number} aperture - Defines the effect's aperture. + * @param {Node | Number} maxblur - Defines the effect's maximum blur. + * @returns {DepthOfFieldNode} + */ export const dof = ( node, viewZNode, focus = 1, aperture = 0.025, maxblur = 1 ) => nodeObject( new DepthOfFieldNode( convertToTexture( node ), nodeObject( viewZNode ), nodeObject( focus ), nodeObject( aperture ), nodeObject( maxblur ) ) ); diff --git a/examples/jsm/tsl/display/DotScreenNode.js b/examples/jsm/tsl/display/DotScreenNode.js index a8f15c225f71ef..a8fe8fa7814960 100644 --- a/examples/jsm/tsl/display/DotScreenNode.js +++ b/examples/jsm/tsl/display/DotScreenNode.js @@ -1,6 +1,13 @@ -import { Vector2, TempNode } from 'three/webgpu'; +import { TempNode } from 'three/webgpu'; import { nodeObject, Fn, uv, uniform, vec2, vec3, sin, cos, add, vec4, screenSize } from 'three/tsl'; +/** @module DotScreenNode **/ + +/** + * Post processing node for creating dot-screen effect. + * + * @augments TempNode + */ class DotScreenNode extends TempNode { static get type() { @@ -9,17 +16,46 @@ class DotScreenNode extends TempNode { } - constructor( inputNode, center = new Vector2( 0.5, 0.5 ), angle = 1.57, scale = 1 ) { + /** + * Constructs a new dot screen node. + * + * @param {Node} inputNode - The node that represents the input of the effect. + * @param {Number} [angle=1.57] - The rotation of the effect in radians. + * @param {Number} [scale=1] - The scale of the effect. A higher value means smaller dots. + */ + constructor( inputNode, angle = 1.57, scale = 1 ) { super( 'vec4' ); + /** + * The node that represents the input of the effect. + * + * @type {Node} + */ this.inputNode = inputNode; - this.center = uniform( center ); + + /** + * A uniform node that represents the rotation of the effect in radians. + * + * @type {UniformNode} + */ this.angle = uniform( angle ); + + /** + * A uniform node that represents the scale of the effect. A higher value means smaller dots. + * + * @type {UniformNode} + */ this.scale = uniform( scale ); } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ setup() { const inputNode = this.inputNode; @@ -29,7 +65,7 @@ class DotScreenNode extends TempNode { const s = sin( this.angle ); const c = cos( this.angle ); - const tex = uv().mul( screenSize ).sub( this.center ); + const tex = uv().mul( screenSize ); 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 ); @@ -56,4 +92,13 @@ class DotScreenNode extends TempNode { export default DotScreenNode; -export const dotScreen = ( node, center, angle, scale ) => nodeObject( new DotScreenNode( nodeObject( node ), center, angle, scale ) ); +/** + * TSL function for creating a dot-screen node for post processing. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @param {Number} [angle=1.57] - The rotation of the effect in radians. + * @param {Number} [scale=1] - The scale of the effect. A higher value means smaller dots. + * @returns {DotScreenNode} + */ +export const dotScreen = ( node, angle, scale ) => nodeObject( new DotScreenNode( nodeObject( node ), angle, scale ) ); diff --git a/examples/jsm/tsl/display/FXAANode.js b/examples/jsm/tsl/display/FXAANode.js index bcc5df482422c9..cc502fb527ea28 100644 --- a/examples/jsm/tsl/display/FXAANode.js +++ b/examples/jsm/tsl/display/FXAANode.js @@ -1,6 +1,14 @@ import { Vector2, TempNode } from 'three/webgpu'; import { nodeObject, Fn, uniformArray, select, float, NodeUpdateType, uv, dot, clamp, uniform, convertToTexture, smoothstep, bool, vec2, vec3, If, Loop, max, min, Break, abs } from 'three/tsl'; +/** @module FXAANode **/ + +/** + * Post processing node for applying FXAA. This node requires sRGB input + * so tone mapping and color space conversion must happen before the anti-aliasing. + * + * @augments TempNode + */ class FXAANode extends TempNode { static get type() { @@ -9,19 +17,47 @@ class FXAANode extends TempNode { } + /** + * Constructs a new FXAA node. + * + * @param {TextureNode} textureNode - The texture node that represents the input of the effect. + */ constructor( textureNode ) { super( 'vec4' ); + /** + * The texture node that represents the input of the effect. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node updates + * its internal uniforms once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; + /** + * A uniform node holding the inverse resolution value. + * + * @private + * @type {UniformNode} + */ this._invSize = uniform( new Vector2() ); } - updateBefore() { + /** + * This method is used to update the effect's uniforms once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ + updateBefore( /* frame */ ) { const map = this.textureNode.value; @@ -29,7 +65,13 @@ class FXAANode extends TempNode { } - setup() { + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ + setup( /* builder */ ) { const textureNode = this.textureNode.bias( - 100 ); const uvNode = textureNode.uvNode || uv(); @@ -313,4 +355,11 @@ class FXAANode extends TempNode { export default FXAANode; +/** + * TSL function for creating a FXAA node for anti-aliasing via post processing. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @returns {FXAANode} + */ export const fxaa = ( node ) => nodeObject( new FXAANode( convertToTexture( node ) ) ); diff --git a/examples/jsm/tsl/display/FilmNode.js b/examples/jsm/tsl/display/FilmNode.js index 067ec6ab37903d..8d353c6b7cddf0 100644 --- a/examples/jsm/tsl/display/FilmNode.js +++ b/examples/jsm/tsl/display/FilmNode.js @@ -1,6 +1,13 @@ import { TempNode } from 'three/webgpu'; import { rand, Fn, fract, time, uv, clamp, mix, vec4, nodeProxy } from 'three/tsl'; +/** @module FilmNode **/ + +/** + * Post processing node for creating a film grain effect. + * + * @augments TempNode + */ class FilmNode extends TempNode { static get type() { @@ -9,17 +16,47 @@ class FilmNode extends TempNode { } + /** + * Constructs a new film node. + * + * @param {Node} inputNode - The node that represents the input of the effect. + * @param {Node?} [intensityNode=null] - A node that represents the effect's intensity. + * @param {Node?} [uvNode=null] - A node that allows to pass custom (e.g. animated) uv data. + */ constructor( inputNode, intensityNode = null, uvNode = null ) { super( 'vec4' ); + /** + * The node that represents the input of the effect. + * + * @type {Node} + */ this.inputNode = inputNode; + + /** + * A node that represents the effect's intensity. + * + * @type {Node} + */ this.intensityNode = intensityNode; + + /** + * A node that allows to pass custom (e.g. animated) uv data. + * + * @type {Node} + */ this.uvNode = uvNode; } - setup() { + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ + setup( /* builder */ ) { const uvNode = this.uvNode || uv(); @@ -50,4 +87,13 @@ class FilmNode extends TempNode { export default FilmNode; +/** + * TSL function for creating a film node for post processing. + * + * @function + * @param {Node} inputNode - The node that represents the input of the effect. + * @param {Node?} [intensityNode=null] - A node that represents the effect's intensity. + * @param {Node?} [uvNode=null] - A node that allows to pass custom (e.g. animated) uv data. + * @returns {FilmNode} + */ export const film = /*@__PURE__*/ nodeProxy( FilmNode ); diff --git a/examples/jsm/tsl/display/GTAONode.js b/examples/jsm/tsl/display/GTAONode.js index c266eb52bcf820..0a9fe188cf0353 100644 --- a/examples/jsm/tsl/display/GTAONode.js +++ b/examples/jsm/tsl/display/GTAONode.js @@ -1,14 +1,36 @@ -import { DataTexture, RenderTarget, RepeatWrapping, Vector2, Vector3, TempNode, QuadMesh, NodeMaterial, PostProcessingUtils } from 'three/webgpu'; +import { DataTexture, RenderTarget, RepeatWrapping, Vector2, Vector3, TempNode, QuadMesh, NodeMaterial, RendererUtils } from 'three/webgpu'; import { reference, logarithmicDepthToViewZ, viewZToPerspectiveDepth, getNormalFromDepth, getScreenPosition, getViewPosition, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, vec2, vec3, vec4, int, dot, max, pow, abs, If, textureSize, sin, cos, PI, texture, passTexture, mat3, add, normalize, mul, cross, div, mix, sqrt, sub, acos, clamp } from 'three/tsl'; +/** @module GTAONode **/ + const _quadMesh = /*@__PURE__*/ new QuadMesh(); const _size = /*@__PURE__*/ new Vector2(); let _rendererState; /** - * References: - * https://www.activision.com/cdn/research/Practical_Real_Time_Strategies_for_Accurate_Indirect_Occlusion_NEW%20VERSION_COLOR.pdf + * Post processing node for applying Ground Truth Ambient Occlusion (GTAO) to a scene. + * ```js + * const postProcessing = new THREE.PostProcessing( renderer ); + * + * const scenePass = pass( scene, camera ); + * scenePass.setMRT( mrt( { + * output: output, + * normal: normalView + * } ) ); + * + * const scenePassColor = scenePass.getTextureNode( 'output' ); + * const scenePassNormal = scenePass.getTextureNode( 'normal' ); + * const scenePassDepth = scenePass.getTextureNode( 'depth' ); + * + * const aoPass = ao( scenePassDepth, scenePassNormal, camera ); + * + * postProcessing.outputNod = aoPass.getTextureNode().mul( scenePassColor ); + * ``` + * + * Reference: {@link https://www.activision.com/cdn/research/Practical_Real_Time_Strategies_for_Accurate_Indirect_Occlusion_NEW%20VERSION_COLOR.pdf}. + * + * @augments TempNode */ class GTAONode extends TempNode { @@ -18,55 +40,193 @@ class GTAONode extends TempNode { } + /** + * Constructs a new GTAO node. + * + * @param {Node} depthNode - A node that represents the scene's depth. + * @param {Node?} normalNode - A node that represents the scene's normals. + * @param {Camera} camera - The camera the scene is rendered with. + */ constructor( depthNode, normalNode, camera ) { super( 'vec4' ); + /** + * A node that represents the scene's depth. + * + * @type {Node} + */ this.depthNode = depthNode; + + /** + * A node that represents the scene's normals. If no normals are passed to the + * constructor (because MRT is not available), normals can be automatically + * reconstructed from depth values in the shader. + * + * @type {Node?} + */ this.normalNode = normalNode; + /** + * The resolution scale. By default the effect is rendered in full resolution + * for best quality but a value of `0.5` should be sufficient for most scenes. + * + * @type {Number} + * @default 1 + */ this.resolutionScale = 1; + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders + * its effect once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; - // render targets - + /** + * The render target the ambient occlusion is rendered into. + * + * @private + * @type {RenderTarget} + */ this._aoRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false } ); this._aoRenderTarget.texture.name = 'GTAONode.AO'; // uniforms + /** + * The radius of the ambient occlusion. + * + * @type {UniformNode} + */ this.radius = uniform( 0.25 ); + + /** + * The resolution of the effect. Can be scaled via + * `resolutionScale`. + * + * @type {UniformNode} + */ this.resolution = uniform( new Vector2() ); + + /** + * The thickness of the ambient occlusion. + * + * @type {UniformNode} + */ this.thickness = uniform( 1 ); + + /** + * Another option to tweak the occlusion. The recommended range is + * `[1,2]` for attenuating the AO. + * + * @type {UniformNode} + */ this.distanceExponent = uniform( 1 ); + + /** + * The distance fall off value of the ambient occlusion. + * A lower value leads to a larger AO effect. The value + * should lie in the range `[0,1]`. + * + * @type {UniformNode} + */ this.distanceFallOff = uniform( 1 ); + + /** + * The scale of the ambient occlusion. + * + * @type {UniformNode} + */ this.scale = uniform( 1 ); + + /** + * How many samples are used to compute the AO. + * A higher value results in better quality but also + * in a more expensive runtime behavior. + * + * @type {UniformNode} + */ this.samples = uniform( 16 ); + /** + * The node represents the internal noise texture used by the AO. + * + * @private + * @type {TextureNode} + */ this._noiseNode = texture( generateMagicSquareNoise() ); + + /** + * Represents the projection matrix of the scene's camera. + * + * @private + * @type {UniformNode} + */ this._cameraProjectionMatrix = uniform( camera.projectionMatrix ); + + /** + * Represents the inverse projection matrix of the scene's camera. + * + * @private + * @type {UniformNode} + */ this._cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); + + /** + * Represents the near value of the scene's camera. + * + * @private + * @type {ReferenceNode} + */ this._cameraNear = reference( 'near', 'float', camera ); - this._cameraFar = reference( 'far', 'float', camera ); - // materials + /** + * Represents the far value of the scene's camera. + * + * @private + * @type {ReferenceNode} + */ + this._cameraFar = reference( 'far', 'float', camera ); + /** + * The material that is used to render the effect. + * + * @private + * @type {NodeMaterial} + */ this._material = new NodeMaterial(); this._material.name = 'GTAO'; - // - + /** + * The result of the effect is represented as a separate texture node. + * + * @private + * @type {PassTextureNode} + */ this._textureNode = passTexture( this, this._aoRenderTarget.texture ); } + /** + * Returns the result of the effect as a texture node. + * + * @return {PassTextureNode} A texture node that represents the result of the effect. + */ getTextureNode() { return this._textureNode; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + */ setSize( width, height ) { width = Math.round( this.resolutionScale * width ); @@ -77,11 +237,16 @@ class GTAONode extends TempNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); // @@ -101,10 +266,16 @@ class GTAONode extends TempNode { // restore - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { const uvNode = uv(); @@ -227,6 +398,10 @@ class GTAONode extends TempNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { this._aoRenderTarget.dispose(); @@ -239,6 +414,12 @@ class GTAONode extends TempNode { export default GTAONode; +/** + * Generates the AO's noise texture for the given size. + * + * @param {Number} [size=5] - The noise size. + * @return {DataTexture} The generated noise texture. + */ function generateMagicSquareNoise( size = 5 ) { const noiseSize = Math.floor( size ) % 2 === 0 ? Math.floor( size ) + 1 : Math.floor( size ); @@ -271,6 +452,12 @@ function generateMagicSquareNoise( size = 5 ) { } +/** + * Computes an array of magic square values required to generate the noise texture. + * + * @param {Number} size - The noise size. + * @return {Array} The magic square values. + */ function generateMagicSquare( size ) { const noiseSize = Math.floor( size ) % 2 === 0 ? Math.floor( size ) + 1 : Math.floor( size ); @@ -323,4 +510,13 @@ function generateMagicSquare( size ) { } +/** + * TSL function for creating a Ground Truth Ambient Occlusion (GTAO) effect. + * + * @function + * @param {Node} depthNode - A node that represents the scene's depth. + * @param {Node?} normalNode - A node that represents the scene's normals. + * @param {Camera} camera - The camera the scene is rendered with. + * @returns {GTAONode} + */ export const ao = ( depthNode, normalNode, camera ) => nodeObject( new GTAONode( nodeObject( depthNode ), nodeObject( normalNode ), camera ) ); diff --git a/examples/jsm/tsl/display/GaussianBlurNode.js b/examples/jsm/tsl/display/GaussianBlurNode.js index f5e80e5243c605..e1a08928767636 100644 --- a/examples/jsm/tsl/display/GaussianBlurNode.js +++ b/examples/jsm/tsl/display/GaussianBlurNode.js @@ -1,8 +1,7 @@ -import { RenderTarget, Vector2, NodeMaterial, PostProcessingUtils, QuadMesh, TempNode, NodeUpdateType } from 'three/webgpu'; +import { RenderTarget, Vector2, NodeMaterial, RendererUtils, QuadMesh, TempNode, NodeUpdateType } from 'three/webgpu'; import { nodeObject, Fn, If, float, uv, uniform, convertToTexture, vec2, vec4, passTexture, mul } from 'three/tsl'; -// 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. +/** @module GaussianBlurNode **/ const _quadMesh = /*@__PURE__*/ new QuadMesh(); @@ -34,6 +33,11 @@ const unpremult = /*@__PURE__*/ Fn( ( [ color ] ) => { ] } ); +/** + * Post processing node for creating a gaussian blur effect. + * + * @augments TempNode + */ class GaussianBlurNode extends TempNode { static get type() { @@ -42,33 +46,116 @@ class GaussianBlurNode extends TempNode { } + /** + * Constructs a new gaussian blur node. + * + * @param {TextureNode} textureNode - The texture node that represents the input of the effect. + * @param {Node} directionNode - Defines the direction and radius of the blur. + * @param {Number} sigma - Controls the kernel of the blur filter. Higher values mean a wider blur radius. + */ constructor( textureNode, directionNode = null, sigma = 2 ) { super( 'vec4' ); + /** + * The texture node that represents the input of the effect. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * Defines the direction and radius of the blur. + * + * @type {Node} + */ this.directionNode = directionNode; + + /** + * Controls the kernel of the blur filter. Higher values mean a wider blur radius. + * + * @type {Number} + */ this.sigma = sigma; + /** + * A uniform node holding the inverse resolution value. + * + * @private + * @type {UniformNode} + */ this._invSize = uniform( new Vector2() ); + + /** + * Gaussian blur is applied in two passes (horizontal, vertical). + * This node controls the direction of each pass. + * + * @private + * @type {UniformNode} + */ this._passDirection = uniform( new Vector2() ); + /** + * The render target used for the horizontal pass. + * + * @private + * @type {RenderTarget} + */ this._horizontalRT = new RenderTarget( 1, 1, { depthBuffer: false } ); this._horizontalRT.texture.name = 'GaussianBlurNode.horizontal'; + + /** + * The render target used for the vertical pass. + * + * @private + * @type {RenderTarget} + */ this._verticalRT = new RenderTarget( 1, 1, { depthBuffer: false } ); this._verticalRT.texture.name = 'GaussianBlurNode.vertical'; + /** + * The result of the effect is represented as a separate texture node. + * + * @private + * @type {PassTextureNode} + */ this._textureNode = passTexture( this, this._verticalRT.texture ); this._textureNode.uvNode = textureNode.uvNode; + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders + * its effect once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; + /** + * Controls the resolution of the effect. + * + * @type {Vector2} + * @default (1,1) + */ this.resolution = new Vector2( 1, 1 ); + /** + * Whether the effect should use premultiplied alpha or not. Set this to `true` + * if you are going to blur texture input with transparency. + * + * @type {Boolean} + * @default false + */ this.premultipliedAlpha = false; } + /** + * Sets the given premultiplied alpha value. + * + * @param {Boolean} value - Whether the effect should use premultiplied alpha or not. + * @return {GaussianBlurNode} height - A reference to this node. + */ setPremultipliedAlpha( value ) { this.premultipliedAlpha = value; @@ -77,12 +164,23 @@ class GaussianBlurNode extends TempNode { } + /** + * Returns the premultiplied alpha value. + * + * @return {Boolean} Whether the effect should use premultiplied alpha or not. + */ getPremultipliedAlpha() { return this.premultipliedAlpha; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + */ setSize( width, height ) { width = Math.max( Math.round( width * this.resolution.x ), 1 ); @@ -94,11 +192,16 @@ class GaussianBlurNode extends TempNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); // @@ -137,23 +240,34 @@ class GaussianBlurNode extends TempNode { textureNode.value = currentTexture; - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } + /** + * Returns the result of the effect as a texture node. + * + * @return {PassTextureNode} A texture node that represents the result of the effect. + */ getTextureNode() { return this._textureNode; } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { const textureNode = this.textureNode; // - const uvNode = textureNode.uvNode || uv(); + const uvNode = uv(); const directionNode = vec2( this.directionNode || 1 ); let sampleTexture, output; @@ -220,6 +334,10 @@ class GaussianBlurNode extends TempNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { this._horizontalRT.dispose(); @@ -227,6 +345,13 @@ class GaussianBlurNode extends TempNode { } + /** + * Computes gaussian coefficients depending on the given kernel radius. + * + * @private + * @param {Number} kernelRadius - The kernel radius. + * @return {Array} + */ _getCoefficients( kernelRadius ) { const coefficients = []; @@ -245,5 +370,24 @@ class GaussianBlurNode extends TempNode { export default GaussianBlurNode; +/** + * TSL function for creating a gaussian blur node for post processing. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @param {Node} directionNode - Defines the direction and radius of the blur. + * @param {Number} sigma - Controls the kernel of the blur filter. Higher values mean a wider blur radius. + * @returns {GaussianBlurNode} + */ export const gaussianBlur = ( node, directionNode, sigma ) => nodeObject( new GaussianBlurNode( convertToTexture( node ), directionNode, sigma ) ); + +/** + * TSL function for creating a gaussian blur node for post processing with enabled premultiplied alpha. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @param {Node} directionNode - Defines the direction and radius of the blur. + * @param {Number} sigma - Controls the kernel of the blur filter. Higher values mean a wider blur radius. + * @returns {GaussianBlurNode} + */ export const premultipliedGaussianBlur = ( node, directionNode, sigma ) => nodeObject( new GaussianBlurNode( convertToTexture( node ), directionNode, sigma ).setPremultipliedAlpha( true ) ); diff --git a/examples/jsm/tsl/display/LensflareNode.js b/examples/jsm/tsl/display/LensflareNode.js index 8717c2ebff4b51..96f7b5826e2b5e 100644 --- a/examples/jsm/tsl/display/LensflareNode.js +++ b/examples/jsm/tsl/display/LensflareNode.js @@ -1,14 +1,21 @@ -import { RenderTarget, Vector2, TempNode, NodeUpdateType, QuadMesh, PostProcessingUtils, NodeMaterial } from 'three/webgpu'; +import { RenderTarget, Vector2, TempNode, NodeUpdateType, QuadMesh, RendererUtils, NodeMaterial } from 'three/webgpu'; import { convertToTexture, nodeObject, Fn, passTexture, uv, vec2, vec3, vec4, max, float, sub, int, Loop, fract, pow, distance } from 'three/tsl'; +/** @module LensflareNode **/ + const _quadMesh = /*@__PURE__*/ new QuadMesh(); const _size = /*@__PURE__*/ new Vector2(); let _rendererState; /** + * Post processing node for adding a bloom-based lens flare effect. This effect + * requires that you extract the bloom of the scene via a bloom pass first. + * * References: - * https://john-chapman-graphics.blogspot.com/2013/02/pseudo-lens-flare.html - * https://john-chapman.github.io/2017/11/05/pseudo-lens-flare.html + * - {@link https://john-chapman-graphics.blogspot.com/2013/02/pseudo-lens-flare.html}. + * - {@link https://john-chapman.github.io/2017/11/05/pseudo-lens-flare.html}. + * + * @augments TempNode */ class LensflareNode extends TempNode { @@ -18,10 +25,27 @@ class LensflareNode extends TempNode { } + /** + * Constructs a new lens flare node. + * + * @param {TextureNode} textureNode - The texture node that represents the scene's bloom. + * @param {Object} params - The parameter object for configuring the effect. + * @param {Node | Color} [params.ghostTint=vec3(1, 1, 1)] - Defines the tint of the flare/ghosts. + * @param {Node | Number} [params.threshold=float(0.5)] - Controls the size and strength of the effect. A higher threshold results in smaller flares. + * @param {Node | Number} [params.ghostSamples=float(4)] - Represents the number of flares/ghosts per bright spot which pivot around the center. + * @param {Node | Number} [params.ghostSpacing=float(0.25)] - Defines the spacing of the flares/ghosts. + * @param {Node | Number} [params.ghostAttenuationFactor=float(25)] - Defines the attenuation factor of flares/ghosts. + * @param {Number} [params.downSampleRatio=4] - Defines how downsampling since the effect is usually not rendered at full resolution. + */ constructor( textureNode, params = {} ) { super( 'vec4' ); + /** + * The texture node that represents the scene's bloom. + * + * @type {TextureNode} + */ this.textureNode = textureNode; const { @@ -33,37 +57,102 @@ class LensflareNode extends TempNode { downSampleRatio = 4 } = params; + /** + * Defines the tint of the flare/ghosts. + * + * @type {Node} + */ this.ghostTintNode = nodeObject( ghostTint ); + + /** + * Controls the size and strength of the effect. A higher threshold results in smaller flares. + * + * @type {Node} + */ this.thresholdNode = nodeObject( threshold ); + + /** + * Represents the number of flares/ghosts per bright spot which pivot around the center. + * + * @type {Node} + */ this.ghostSamplesNode = nodeObject( ghostSamples ); + + /** + * Defines the spacing of the flares/ghosts. + * + * @type {Node} + */ this.ghostSpacingNode = nodeObject( ghostSpacing ); + + /** + * Defines the attenuation factor of flares/ghosts. + * + * @type {Node} + */ this.ghostAttenuationFactorNode = nodeObject( ghostAttenuationFactor ); + + /** + * Defines how downsampling since the effect is usually not rendered at full resolution. + * + * @type {Number} + */ this.downSampleRatio = downSampleRatio; + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders + * its effect once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; - // render targets - + /** + * The internal render target of the effect. + * + * @private + * @type {RenderTarget} + */ this._renderTarget = new RenderTarget( 1, 1, { depthBuffer: false } ); this._renderTarget.texture.name = 'LensflareNode'; - // materials - + /** + * The node material that holds the effect's TSL code. + * + * @private + * @type {NodeMaterial} + */ this._material = new NodeMaterial(); this._material.name = 'LensflareNode'; - // - + /** + * The result of the effect is represented as a separate texture node. + * + * @private + * @type {PassTextureNode} + */ this._textureNode = passTexture( this, this._renderTarget.texture ); } + /** + * Returns the result of the effect as a texture node. + * + * @return {PassTextureNode} A texture node that represents the result of the effect. + */ getTextureNode() { return this._textureNode; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + */ setSize( width, height ) { const resx = Math.round( width / this.downSampleRatio ); @@ -73,6 +162,11 @@ class LensflareNode extends TempNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; @@ -80,7 +174,7 @@ class LensflareNode extends TempNode { const size = renderer.getDrawingBufferSize( _size ); this.setSize( size.width, size.height ); - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); _quadMesh.material = this._material; @@ -95,10 +189,16 @@ class LensflareNode extends TempNode { // restore - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { const lensflare = Fn( () => { @@ -147,6 +247,10 @@ class LensflareNode extends TempNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { this._renderTarget.dispose(); @@ -158,4 +262,18 @@ class LensflareNode extends TempNode { export default LensflareNode; -export const lensflare = ( inputNode, params ) => nodeObject( new LensflareNode( convertToTexture( inputNode ), params ) ); +/** + * TSL function for creating a bloom-based lens flare effect. + * + * @function + * @param {TextureNode} node - The node that represents the scene's bloom. + * @param {Object} params - The parameter object for configuring the effect. + * @param {Node | Color} [params.ghostTint=vec3(1, 1, 1)] - Defines the tint of the flare/ghosts. + * @param {Node | Number} [params.threshold=float(0.5)] - Controls the size and strength of the effect. A higher threshold results in smaller flares. + * @param {Node | Number} [params.ghostSamples=float(4)] - Represents the number of flares/ghosts per bright spot which pivot around the center. + * @param {Node | Number} [params.ghostSpacing=float(0.25)] - Defines the spacing of the flares/ghosts. + * @param {Node | Number} [params.ghostAttenuationFactor=float(25)] - Defines the attenuation factor of flares/ghosts. + * @param {Number} [params.downSampleRatio=4] - Defines how downsampling since the effect is usually not rendered at full resolution. + * @returns {LensflareNode} + */ +export const lensflare = ( node, params ) => nodeObject( new LensflareNode( convertToTexture( node ), params ) ); diff --git a/examples/jsm/tsl/display/Lut3DNode.js b/examples/jsm/tsl/display/Lut3DNode.js index 49687b76531d72..1c3fac61ffe227 100644 --- a/examples/jsm/tsl/display/Lut3DNode.js +++ b/examples/jsm/tsl/display/Lut3DNode.js @@ -1,6 +1,13 @@ import { TempNode } from 'three/webgpu'; import { nodeObject, Fn, float, uniform, vec3, vec4, mix } from 'three/tsl'; +/** @module Lut3DNode **/ + +/** + * A post processing node for color grading via lookup tables. + * + * @augments TempNode + */ class Lut3DNode extends TempNode { static get type() { @@ -9,17 +16,54 @@ class Lut3DNode extends TempNode { } + /** + * Constructs a new LUT node. + * + * @param {Node} inputNode - The node that represents the input of the effect. + * @param {TextureNode} lutNode - A texture node that represents the lookup table. + * @param {Number} size - The size of the lookup table. + * @param {Node} intensityNode - Controls the intensity of the effect. + */ constructor( inputNode, lutNode, size, intensityNode ) { super( 'vec4' ); + /** + * The node that represents the input of the effect. + * + * @type {Node} + */ this.inputNode = inputNode; + + /** + * A texture node that represents the lookup table. + * + * @type {TextureNode} + */ this.lutNode = lutNode; + + /** + * The size of the lookup table. + * + * @type {UniformNode} + */ this.size = uniform( size ); + + /** + * Controls the intensity of the effect. + * + * @type {Node} + */ this.intensityNode = intensityNode; } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ setup() { const { inputNode, lutNode } = this; @@ -52,4 +96,14 @@ class Lut3DNode extends TempNode { export default Lut3DNode; +/** + * TSL function for creating a LUT node for color grading via post processing. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @param {TextureNode} lut - A texture node that represents the lookup table. + * @param {Number} size - The size of the lookup table. + * @param {Node | Number} intensity - Controls the intensity of the effect. + * @returns {Lut3DNode} + */ export const lut3D = ( node, lut, size, intensity ) => nodeObject( new Lut3DNode( nodeObject( node ), nodeObject( lut ), size, nodeObject( intensity ) ) ); diff --git a/examples/jsm/tsl/display/MotionBlur.js b/examples/jsm/tsl/display/MotionBlur.js index 20402df5173dde..85d72903daf7a2 100644 --- a/examples/jsm/tsl/display/MotionBlur.js +++ b/examples/jsm/tsl/display/MotionBlur.js @@ -1,6 +1,16 @@ - import { Fn, float, uv, Loop, int } from 'three/tsl'; +/** @module MotionBlur **/ + +/** + * Applies a motion blur effect to the given input node. + * + * @function + * @param {Node} inputNode - The input node to apply the motion blur for. + * @param {Node} velocity - The motion vectors of the beauty pass. + * @param {Node} [numSamples=int(16)] - How many samples the effect should use. A higher value results in better quality but is also more expensive. + * @return {Node} The input node with the motion blur effect applied. + */ export const motionBlur = /*@__PURE__*/ Fn( ( [ inputNode, velocity, numSamples = int( 16 ) ] ) => { const sampleColor = ( uv ) => inputNode.sample( uv ); diff --git a/examples/jsm/tsl/display/OutlineNode.js b/examples/jsm/tsl/display/OutlineNode.js index 8b3868684e54b9..d563c485a52f52 100644 --- a/examples/jsm/tsl/display/OutlineNode.js +++ b/examples/jsm/tsl/display/OutlineNode.js @@ -1,5 +1,7 @@ -import { Color, DepthTexture, FloatType, RenderTarget, Vector2, TempNode, QuadMesh, NodeMaterial, PostProcessingUtils, NodeUpdateType } from 'three/webgpu'; -import { Loop, int, exp, min, float, mul, uv, vec2, vec3, Fn, textureSize, orthographicDepthToViewZ, screenUV, nodeObject, uniform, vec4, passTexture, texture, perspectiveDepthToViewZ, positionView } from 'three/tsl'; +import { DepthTexture, FloatType, RenderTarget, Vector2, TempNode, QuadMesh, NodeMaterial, RendererUtils, NodeUpdateType } from 'three/webgpu'; +import { Loop, int, exp, min, float, mul, uv, vec2, vec3, Fn, textureSize, orthographicDepthToViewZ, screenUV, nodeObject, uniform, vec4, passTexture, texture, perspectiveDepthToViewZ, positionView, reference } from 'three/tsl'; + +/** @module OutlineNode **/ const _quadMesh = /*@__PURE__*/ new QuadMesh(); const _size = /*@__PURE__*/ new Vector2(); @@ -8,6 +10,39 @@ const _BLUR_DIRECTION_Y = /*@__PURE__*/ new Vector2( 0.0, 1.0 ); let _rendererState; +/** + * Post processing node for rendering outlines around selected objects. The node + * gives you great flexibility in composing the final outline look depending on + * your requirements. + * ```js + * const postProcessing = new THREE.PostProcessing( renderer ); + * + * const scenePass = pass( scene, camera ); + * + * // outline parameter + * + * const edgeStrength = uniform( 3.0 ); + * const edgeGlow = uniform( 0.0 ); + * const edgeThickness = uniform( 1.0 ); + * const visibleEdgeColor = uniform( new THREE.Color( 0xffffff ) ); + * const hiddenEdgeColor = uniform( new THREE.Color( 0x4e3636 ) ); + * + * outlinePass = outline( scene, camera, { + * selectedObjects, + * edgeGlow, + * edgeThickness + * } ); + * + * // compose custom outline + * + * const { visibleEdge, hiddenEdge } = outlinePass; + * const outlineColor = visibleEdge.mul( visibleEdgeColor ).add( hiddenEdge.mul( hiddenEdgeColor ) ).mul( edgeStrength ); + * + * postProcessing.outputNode = outlineColor.add( scenePass ); + * ``` + * + * @augments TempNode + */ class OutlineNode extends TempNode { static get type() { @@ -16,6 +51,17 @@ class OutlineNode extends TempNode { } + /** + * Constructs a new outline node. + * + * @param {Scene} scene - A reference to the scene. + * @param {Camera} camera - The camera the scene is rendered with. + * @param {Object} params - The configuration parameters. + * @param {Array} params.selectedObjects - An array of selected objects. + * @param {Node} [params.edgeThickness=float(1)] - The thickness of the edges. + * @param {Node} [params.edgeGlow=float(0)] - Can be used for an animated glow/pulse effects. + * @param {Number} [params.downSampleRatio=2] - The downsample ratio. + */ constructor( scene, camera, params = {} ) { super( 'vec4' ); @@ -27,101 +73,341 @@ class OutlineNode extends TempNode { downSampleRatio = 2 } = params; + /** + * A reference to the scene. + * + * @type {Scene} + */ this.scene = scene; + + /** + * The camera the scene is rendered with. + * + * @type {Camera} + */ this.camera = camera; + + /** + * An array of selected objects. + * + * @type {Array} + */ this.selectedObjects = selectedObjects; + + /** + * The thickness of the edges. + * + * @type {Node} + */ this.edgeThicknessNode = nodeObject( edgeThickness ); + + /** + * Can be used for an animated glow/pulse effect. + * + * @type {Node} + */ this.edgeGlowNode = nodeObject( edgeGlow ); + + /** + * The downsample ratio. + * + * @type {Number} + * @default 2 + */ this.downSampleRatio = downSampleRatio; + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders + * its effect once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; // render targets + /** + * The render target for the depth pre-pass. + * + * @private + * @type {RenderTarget} + */ this._renderTargetDepthBuffer = new RenderTarget(); this._renderTargetDepthBuffer.depthTexture = new DepthTexture(); this._renderTargetDepthBuffer.depthTexture.type = FloatType; + /** + * The render target for the mask pass. + * + * @private + * @type {RenderTarget} + */ this._renderTargetMaskBuffer = new RenderTarget(); + + /** + * The render target for the mask downsample. + * + * @private + * @type {RenderTarget} + */ this._renderTargetMaskDownSampleBuffer = new RenderTarget( 1, 1, { depthBuffer: false } ); + + /** + * The first render target for the edge detection. + * + * @private + * @type {RenderTarget} + */ this._renderTargetEdgeBuffer1 = new RenderTarget( 1, 1, { depthBuffer: false } ); + + /** + * The second render target for the edge detection. + * + * @private + * @type {RenderTarget} + */ this._renderTargetEdgeBuffer2 = new RenderTarget( 1, 1, { depthBuffer: false } ); + + /** + * The first render target for the blur pass. + * + * @private + * @type {RenderTarget} + */ this._renderTargetBlurBuffer1 = new RenderTarget( 1, 1, { depthBuffer: false } ); + + /** + * The second render target for the blur pass. + * + * @private + * @type {RenderTarget} + */ this._renderTargetBlurBuffer2 = new RenderTarget( 1, 1, { depthBuffer: false } ); + + /** + * The render target for the final composite. + * + * @private + * @type {RenderTarget} + */ this._renderTargetComposite = new RenderTarget( 1, 1, { depthBuffer: false } ); // uniforms - this._cameraNear = uniform( camera.near ); - this._cameraFar = uniform( camera.far ); + /** + * Represents the near value of the scene's camera. + * + * @private + * @type {ReferenceNode} + */ + this._cameraNear = reference( 'near', 'float', camera ); + + /** + * Represents the far value of the scene's camera. + * + * @private + * @type {ReferenceNode} + */ + this._cameraFar = reference( 'far', 'float', camera ); + + /** + * Uniform that represents the blur direction of the pass. + * + * @private + * @type {UniformNode} + */ this._blurDirection = uniform( new Vector2() ); + /** + * Texture node that holds the data from the depth pre-pass. + * + * @private + * @type {TextureNode} + */ this._depthTextureUniform = texture( this._renderTargetDepthBuffer.depthTexture ); + + /** + * Texture node that holds the data from the mask pass. + * + * @private + * @type {TextureNode} + */ this._maskTextureUniform = texture( this._renderTargetMaskBuffer.texture ); + + /** + * Texture node that holds the data from the mask downsample pass. + * + * @private + * @type {TextureNode} + */ this._maskTextureDownsSampleUniform = texture( this._renderTargetMaskDownSampleBuffer.texture ); + + /** + * Texture node that holds the data from the first edge detection pass. + * + * @private + * @type {TextureNode} + */ this._edge1TextureUniform = texture( this._renderTargetEdgeBuffer1.texture ); + + /** + * Texture node that holds the data from the second edge detection pass. + * + * @private + * @type {TextureNode} + */ this._edge2TextureUniform = texture( this._renderTargetEdgeBuffer2.texture ); + + /** + * Texture node that holds the current blurred color data. + * + * @private + * @type {TextureNode} + */ this._blurColorTextureUniform = texture( this._renderTargetEdgeBuffer1.texture ); // constants + /** + * Visible edge color. + * + * @private + * @type {Node} + */ this._visibleEdgeColor = vec3( 1, 0, 0 ); + + /** + * Hidden edge color. + * + * @private + * @type {Node} + */ this._hiddenEdgeColor = vec3( 0, 1, 0 ); // materials + /** + * The material for the depth pre-pass. + * + * @private + * @type {NodeMaterial} + */ this._depthMaterial = new NodeMaterial(); this._depthMaterial.fragmentNode = vec4( 0, 0, 0, 1 ); this._depthMaterial.name = 'OutlineNode.depth'; + /** + * The material for preparing the mask. + * + * @private + * @type {NodeMaterial} + */ this._prepareMaskMaterial = new NodeMaterial(); this._prepareMaskMaterial.name = 'OutlineNode.prepareMask'; + /** + * The copy material + * + * @private + * @type {NodeMaterial} + */ this._materialCopy = new NodeMaterial(); this._materialCopy.name = 'OutlineNode.copy'; + /** + * The edge detection material. + * + * @private + * @type {NodeMaterial} + */ this._edgeDetectionMaterial = new NodeMaterial(); this._edgeDetectionMaterial.name = 'OutlineNode.edgeDetection'; + /** + * The material that is used to render in the blur pass. + * + * @private + * @type {NodeMaterial} + */ this._separableBlurMaterial = new NodeMaterial(); this._separableBlurMaterial.name = 'OutlineNode.separableBlur'; + /** + * The material that is used to render in the blur pass. + * + * @private + * @type {NodeMaterial} + */ this._separableBlurMaterial2 = new NodeMaterial(); this._separableBlurMaterial2.name = 'OutlineNode.separableBlur2'; + /** + * The final composite material. + * + * @private + * @type {NodeMaterial} + */ this._compositeMaterial = new NodeMaterial(); this._compositeMaterial.name = 'OutlineNode.composite'; - // - + /** + * A set to cache selected objects in the scene. + * + * @private + * @type {Set} + */ this._selectionCache = new Set(); - this._tempPulseColor1 = new Color(); - this._tempPulseColor2 = new Color(); - - // + /** + * The result of the effect is represented as a separate texture node. + * + * @private + * @type {PassTextureNode} + */ this._textureNode = passTexture( this, this._renderTargetComposite.texture ); } + /** + * A mask value that represents the visible edge. + * + * @return {Node} The visible edge. + */ get visibleEdge() { return this.r; } + /** + * A mask value that represents the hidden edge. + * + * @return {Node} The hidden edge. + */ get hiddenEdge() { return this.g; } + /** + * Returns the result of the effect as a texture node. + * + * @return {PassTextureNode} A texture node that represents the result of the effect. + */ getTextureNode() { return this._textureNode; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + */ setSize( width, height ) { this._renderTargetDepthBuffer.setSize( width, height ); @@ -147,12 +433,17 @@ class OutlineNode extends TempNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; const { camera, scene } = this; - _rendererState = PostProcessingUtils.resetRendererAndSceneState( renderer, scene, _rendererState ); + _rendererState = RendererUtils.resetRendererAndSceneState( renderer, scene, _rendererState ); // @@ -255,10 +546,16 @@ class OutlineNode extends TempNode { // restore - PostProcessingUtils.restoreRendererAndSceneState( renderer, scene, _rendererState ); + RendererUtils.restoreRendererAndSceneState( renderer, scene, _rendererState ); } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup() { // prepare mask material @@ -320,7 +617,7 @@ class OutlineNode extends TempNode { this._edgeDetectionMaterial.fragmentNode = edgeDetection(); this._edgeDetectionMaterial.needsUpdate = true; - // seperable blur material + // separable blur material const MAX_RADIUS = 4; @@ -330,7 +627,7 @@ class OutlineNode extends TempNode { } ); - const seperableBlur = Fn( ( [ kernelRadius ] ) => { + const separableBlur = Fn( ( [ kernelRadius ] ) => { const resolution = textureSize( this._maskTextureDownsSampleUniform ); const invSize = vec2( 1 ).div( resolution ).toVar(); @@ -360,10 +657,10 @@ class OutlineNode extends TempNode { } ); - this._separableBlurMaterial.fragmentNode = seperableBlur( this.edgeThicknessNode ); + this._separableBlurMaterial.fragmentNode = separableBlur( this.edgeThicknessNode ); this._separableBlurMaterial.needsUpdate = true; - this._separableBlurMaterial2.fragmentNode = seperableBlur( MAX_RADIUS ); + this._separableBlurMaterial2.fragmentNode = separableBlur( MAX_RADIUS ); this._separableBlurMaterial2.needsUpdate = true; // composite material @@ -387,6 +684,10 @@ class OutlineNode extends TempNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { this.selectedObjects.length = 0; @@ -410,8 +711,11 @@ class OutlineNode extends TempNode { } - // - + /** + * Updates the selection cache based on the selected objects. + * + * @private + */ _updateSelectionCache() { for ( let i = 0; i < this.selectedObjects.length; i ++ ) { @@ -431,4 +735,17 @@ class OutlineNode extends TempNode { export default OutlineNode; +/** + * TSL function for creating an outline effect around selected objects. + * + * @function + * @param {Scene} scene - A reference to the scene. + * @param {Camera} camera - The camera the scene is rendered with. + * @param {Object} params - The configuration parameters. + * @param {Array} params.selectedObjects - An array of selected objects. + * @param {Node} [params.edgeThickness=float(1)] - The thickness of the edges. + * @param {Node} [params.edgeGlow=float(0)] - Can be used for animated glow/pulse effects. + * @param {Number} [params.downSampleRatio=2] - The downsample ratio. + * @returns {OutlineNode} + */ export const outline = ( scene, camera, params ) => nodeObject( new OutlineNode( scene, camera, params ) ); diff --git a/examples/jsm/tsl/display/ParallaxBarrierPassNode.js b/examples/jsm/tsl/display/ParallaxBarrierPassNode.js index 43da8b02cfd7df..774b4420df9111 100644 --- a/examples/jsm/tsl/display/ParallaxBarrierPassNode.js +++ b/examples/jsm/tsl/display/ParallaxBarrierPassNode.js @@ -2,6 +2,13 @@ import { NodeMaterial } from 'three/webgpu'; import { nodeObject, Fn, vec4, uv, If, mod, screenCoordinate } from 'three/tsl'; import StereoCompositePassNode from './StereoCompositePassNode.js'; +/** @module ParallaxBarrierPassNode **/ + +/** + * A render pass node that creates a parallax barrier effect. + * + * @augments StereoCompositePassNode + */ class ParallaxBarrierPassNode extends StereoCompositePassNode { static get type() { @@ -10,14 +17,33 @@ class ParallaxBarrierPassNode extends StereoCompositePassNode { } + /** + * Constructs a new parallax barrier pass node. + * + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + */ constructor( scene, camera ) { super( scene, camera ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isParallaxBarrierPassNode = true; } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { const uvNode = uv(); @@ -52,4 +78,12 @@ class ParallaxBarrierPassNode extends StereoCompositePassNode { export default ParallaxBarrierPassNode; +/** + * TSL function for creating an parallax barrier pass node. + * + * @function + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + * @returns {ParallaxBarrierPassNode} + */ export const parallaxBarrierPass = ( scene, camera ) => nodeObject( new ParallaxBarrierPassNode( scene, camera ) ); diff --git a/examples/jsm/tsl/display/PixelationPassNode.js b/examples/jsm/tsl/display/PixelationPassNode.js index 59b5aa53623ebd..77258e30553bea 100644 --- a/examples/jsm/tsl/display/PixelationPassNode.js +++ b/examples/jsm/tsl/display/PixelationPassNode.js @@ -1,6 +1,14 @@ import { NearestFilter, Vector4, TempNode, NodeUpdateType, PassNode } from 'three/webgpu'; import { nodeObject, Fn, float, uv, uniform, convertToTexture, vec2, vec3, clamp, floor, dot, smoothstep, If, sign, step, mrt, output, normalView, property } from 'three/tsl'; +/** @module PixelationPassNode **/ + +/** + * A inner node definition that implements the actual pixelation TSL code. + * + * @inner + * @augments TempNode + */ class PixelationNode extends TempNode { static get type() { @@ -9,30 +17,85 @@ class PixelationNode extends TempNode { } + /** + * Constructs a new pixelation node. + * + * @param {TextureNode} textureNode - The texture node that represents the beauty pass. + * @param {TextureNode} depthNode - The texture that represents the beauty's depth. + * @param {TextureNode} normalNode - The texture that represents the beauty's normals. + * @param {Node} pixelSize - The pixel size. + * @param {Node} normalEdgeStrength - The normal edge strength. + * @param {Node} depthEdgeStrength - The depth edge strength. + */ constructor( textureNode, depthNode, normalNode, pixelSize, normalEdgeStrength, depthEdgeStrength ) { super( 'vec4' ); - // Input textures - + /** + * The texture node that represents the beauty pass. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The texture that represents the beauty's depth. + * + * @type {TextureNode} + */ this.depthNode = depthNode; - this.normalNode = normalNode; - // Input uniforms + /** + * The texture that represents the beauty's normals. + * + * @type {TextureNode} + */ + this.normalNode = normalNode; + /** + * The pixel size. + * + * @type {Node} + */ this.pixelSize = pixelSize; + + /** + * The pixel size. + * + * @type {Node} + */ this.normalEdgeStrength = normalEdgeStrength; - this.depthEdgeStrength = depthEdgeStrength; - // Private uniforms + /** + * The depth edge strength. + * + * @type {Node} + */ + this.depthEdgeStrength = depthEdgeStrength; + /** + * Uniform node that represents the resolution. + * + * @type {Node} + */ this._resolution = uniform( new Vector4() ); + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node updates + * its internal uniforms once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; } + /** + * This method is used to update uniforms once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore() { const map = this.textureNode.value; @@ -44,6 +107,12 @@ class PixelationNode extends TempNode { } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ setup() { const { textureNode, depthNode, normalNode } = this; @@ -148,6 +217,11 @@ class PixelationNode extends TempNode { 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 ) ) ); +/** + * A special render pass node that renders the scene with a pixelation effect. + * + * @augments PassNode + */ class PixelationPassNode extends PassNode { static get type() { @@ -156,14 +230,50 @@ class PixelationPassNode extends PassNode { } + /** + * Constructs a new pixelation pass node. + * + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + * @param {Node | Number} [pixelSize=6] - The pixel size. + * @param {Node | Number} [normalEdgeStrength=03] - The normal edge strength. + * @param {Node | Number} [depthEdgeStrength=03] - The depth edge strength. + */ constructor( scene, camera, pixelSize = 6, normalEdgeStrength = 0.3, depthEdgeStrength = 0.4 ) { super( PassNode.COLOR, scene, camera, { minFilter: NearestFilter, magFilter: NearestFilter } ); + /** + * The pixel size. + * + * @type {Number} + * @default 6 + */ this.pixelSize = pixelSize; + + /** + * The normal edge strength. + * + * @type {Number} + * @default 0.3 + */ this.normalEdgeStrength = normalEdgeStrength; + + /** + * The depth edge strength. + * + * @type {Number} + * @default 0.4 + */ this.depthEdgeStrength = depthEdgeStrength; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isPixelationPassNode = true; this._mrt = mrt( { @@ -173,6 +283,12 @@ class PixelationPassNode extends PassNode { } + /** + * Sets the size of the pass. + * + * @param {Number} width - The width of the pass. + * @param {Number} height - The height of the pass. + */ setSize( width, height ) { const pixelSize = this.pixelSize.value ? this.pixelSize.value : this.pixelSize; @@ -184,6 +300,12 @@ class PixelationPassNode extends PassNode { } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PixelationNode} + */ setup() { const color = super.getTextureNode( 'output' ); @@ -196,6 +318,17 @@ class PixelationPassNode extends PassNode { } +/** + * TSL function for creating a pixelation render pass node for post processing. + * + * @function + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + * @param {Node | Number} [pixelSize=6] - The pixel size. + * @param {Node | Number} [normalEdgeStrength=03] - The normal edge strength. + * @param {Node | Number} [depthEdgeStrength=03] - The depth edge strength. + * @returns {PixelationPassNode} + */ export const pixelationPass = ( scene, camera, pixelSize, normalEdgeStrength, depthEdgeStrength ) => nodeObject( new PixelationPassNode( scene, camera, pixelSize, normalEdgeStrength, depthEdgeStrength ) ); export default PixelationPassNode; diff --git a/examples/jsm/tsl/display/RGBShiftNode.js b/examples/jsm/tsl/display/RGBShiftNode.js index 1f311dee94931a..1548ab697d20da 100644 --- a/examples/jsm/tsl/display/RGBShiftNode.js +++ b/examples/jsm/tsl/display/RGBShiftNode.js @@ -1,6 +1,14 @@ import { TempNode } from 'three/webgpu'; import { nodeObject, Fn, uv, uniform, vec2, sin, cos, vec4, convertToTexture } from 'three/tsl'; +/** @module RGBShiftNode **/ + +/** + * Post processing node for shifting/splitting RGB color channels. The effect + * separates color channels and offsets them from each other. + * + * @augments TempNode + */ class RGBShiftNode extends TempNode { static get type() { @@ -9,17 +17,47 @@ class RGBShiftNode extends TempNode { } + /** + * Constructs a new RGB shift node. + * + * @param {TextureNode} textureNode - The texture node that represents the input of the effect. + * @param {Number} [amount=0.005] - The amount of the RGB shift. + * @param {Number} [angle=0] - Defines the orientation in which colors are shifted. + */ constructor( textureNode, amount = 0.005, angle = 0 ) { super( 'vec4' ); + /** + * The texture node that represents the input of the effect. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The amount of the RGB shift. + * + * @type {UniformNode} + */ this.amount = uniform( amount ); + + /** + * Defines in which direction colors are shifted. + * + * @type {UniformNode} + */ this.angle = uniform( angle ); } - setup() { + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ + setup( /* builder */ ) { const { textureNode } = this; @@ -46,4 +84,13 @@ class RGBShiftNode extends TempNode { export default RGBShiftNode; +/** + * TSL function for creating a RGB shift or split effect for post processing. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @param {Number} [amount=0.005] - The amount of the RGB shift. + * @param {Number} [angle=0] - Defines in which direction colors are shifted. + * @returns {RGBShiftNode} + */ export const rgbShift = ( node, amount, angle ) => nodeObject( new RGBShiftNode( convertToTexture( node ), amount, angle ) ); diff --git a/examples/jsm/tsl/display/SMAANode.js b/examples/jsm/tsl/display/SMAANode.js index 9ac0b8bfd1aaa6..1d003e710df53c 100644 --- a/examples/jsm/tsl/display/SMAANode.js +++ b/examples/jsm/tsl/display/SMAANode.js @@ -1,17 +1,23 @@ -import { HalfFloatType, LinearFilter, NearestFilter, RenderTarget, Texture, Vector2, QuadMesh, NodeMaterial, TempNode, PostProcessingUtils } from 'three/webgpu'; +import { HalfFloatType, LinearFilter, NearestFilter, RenderTarget, Texture, Vector2, QuadMesh, NodeMaterial, TempNode, RendererUtils } from 'three/webgpu'; import { abs, nodeObject, Fn, NodeUpdateType, uv, uniform, convertToTexture, varyingProperty, vec2, vec4, modelViewProjection, passTexture, max, step, dot, float, texture, If, Loop, int, Break, sqrt, sign, mix } from 'three/tsl'; +/** @module SMAANode **/ + const _quadMesh = /*@__PURE__*/ new QuadMesh(); const _size = /*@__PURE__*/ new Vector2(); let _rendererState; /** - * Port of Subpixel Morphological Antialiasing (SMAA) v2.8 - * Preset: SMAA 1x Medium (with color edge detection) - * https://github.com/iryoku/smaa/releases/tag/v2.8 + * Post processing node for applying SMAA. Unlike FXAA, this node + * should be applied before converting colors to sRGB. SMAA should produce + * better results than FXAA but is also more expensive to execute. + * + * Used Preset: SMAA 1x Medium (with color edge detection) + * Reference: {@link https://github.com/iryoku/smaa/releases/tag/v2.8}. + * + * @augments TempNode */ - class SMAANode extends TempNode { static get type() { @@ -20,22 +26,55 @@ class SMAANode extends TempNode { } + /** + * Constructs a new SMAA node. + * + * @param {TextureNode} textureNode - The texture node that represents the input of the effect. + */ constructor( textureNode ) { super( 'vec4' ); + /** + * The texture node that represents the input of the effect. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders + * its effect once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; - // render targets - + /** + * The render target used for the edges pass. + * + * @private + * @type {RenderTarget} + */ this._renderTargetEdges = new RenderTarget( 1, 1, { depthBuffer: false, type: HalfFloatType } ); this._renderTargetEdges.texture.name = 'SMAANode.edges'; + /** + * The render target used for the weights pass. + * + * @private + * @type {RenderTarget} + */ this._renderTargetWeights = new RenderTarget( 1, 1, { depthBuffer: false, type: HalfFloatType } ); this._renderTargetWeights.texture.name = 'SMAANode.weights'; + /** + * The render target used for the blend pass. + * + * @private + * @type {RenderTarget} + */ this._renderTargetBlend = new RenderTarget( 1, 1, { depthBuffer: false, type: HalfFloatType } ); this._renderTargetBlend.texture.name = 'SMAANode.blend'; @@ -44,7 +83,7 @@ class SMAANode extends TempNode { const scope = this; const areaTextureImage = new Image(); - areaTextureImage.src = this.getAreaTexture(); + areaTextureImage.src = this._getAreaTexture(); areaTextureImage.onload = function () { // assigning data to HTMLImageElement.src is asynchronous (see #15162) @@ -52,6 +91,12 @@ class SMAANode extends TempNode { }; + /** + * Represents the "area" texture used by the SMAA implementation. + * + * @private + * @type {RenderTarget} + */ this._areaTexture = new Texture(); this._areaTexture.name = 'SMAANode.area'; this._areaTexture.image = areaTextureImage; @@ -60,7 +105,7 @@ class SMAANode extends TempNode { this._areaTexture.flipY = false; const searchTextureImage = new Image(); - searchTextureImage.src = this.getSearchTexture(); + searchTextureImage.src = this._getSearchTexture(); searchTextureImage.onload = function () { // assigning data to HTMLImageElement.src is asynchronous (see #15162) @@ -68,6 +113,12 @@ class SMAANode extends TempNode { }; + /** + * Represents the "search" texture used by the SMAA implementation. + * + * @private + * @type {RenderTarget} + */ this._searchTexture = new Texture(); this._searchTexture.name = 'SMAANode.search'; this._searchTexture.image = searchTextureImage; @@ -76,37 +127,100 @@ class SMAANode extends TempNode { this._searchTexture.generateMipmaps = false; this._searchTexture.flipY = false; - // uniforms - + /** + * A uniform node holding the inverse resolution value. + * + * @private + * @type {UniformNode} + */ this._invSize = uniform( new Vector2() ); + + /** + * A uniform texture node holding the area texture. + * + * @private + * @type {TextureNode} + */ this._areaTextureUniform = texture( this._areaTexture ); + + /** + * A uniform texture node holding the search texture. + * + * @private + * @type {TextureNode} + */ this._searchTextureUniform = texture( this._searchTexture ); + + /** + * A uniform texture node representing the edges pass. + * + * @private + * @type {TextureNode} + */ this._edgesTextureUniform = texture( this._renderTargetEdges.texture ); - this._weightsTextureUniform = texture( this._renderTargetWeights.texture ); - // materials + /** + * A uniform texture node representing the weights pass. + * + * @private + * @type {TextureNode} + */ + this._weightsTextureUniform = texture( this._renderTargetWeights.texture ); + /** + * The node material that holds the TSL for rendering the edges pass. + * + * @private + * @type {NodeMaterial} + */ this._materialEdges = new NodeMaterial(); this._materialEdges.name = 'SMAANode.edges'; + /** + * The node material that holds the TSL for rendering the weights pass. + * + * @private + * @type {NodeMaterial} + */ this._materialWeights = new NodeMaterial(); this._materialWeights.name = 'SMAANode.weights'; + /** + * The node material that holds the TSL for rendering the blend pass. + * + * @private + * @type {NodeMaterial} + */ this._materialBlend = new NodeMaterial(); this._materialBlend.name = 'SMAANode.blend'; - // - + /** + * The result of the effect is represented as a separate texture node. + * + * @private + * @type {PassTextureNode} + */ this._textureNode = passTexture( this, this._renderTargetBlend.texture ); } + /** + * Returns the result of the effect as a texture node. + * + * @return {PassTextureNode} A texture node that represents the result of the effect. + */ getTextureNode() { return this._textureNode; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + */ setSize( width, height ) { this._invSize.value.set( 1 / width, 1 / height ); @@ -117,11 +231,16 @@ class SMAANode extends TempNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); // @@ -151,10 +270,16 @@ class SMAANode extends TempNode { // restore - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { const SMAA_THRESHOLD = 0.1; @@ -178,7 +303,7 @@ class SMAANode extends TempNode { varyingProperty( 'vec4', 'vOffset1' ).assign( vOffset1 ); varyingProperty( 'vec4', 'vOffset2' ).assign( vOffset2 ); - return modelViewProjection(); + return modelViewProjection; } ); @@ -405,7 +530,7 @@ class SMAANode extends TempNode { varyingProperty( 'vec4', 'vOffset1' ).assign( vOffset1 ); varyingProperty( 'vec4', 'vOffset2' ).assign( vOffset2 ); - return modelViewProjection(); + return modelViewProjection; } ); @@ -507,7 +632,7 @@ class SMAANode extends TempNode { //varyingProperty( 'vec4', 'vOffset0' ).assign( vOffset0 ); varyingProperty( 'vec4', 'vOffset1' ).assign( vOffset1 ); - return modelViewProjection(); + return modelViewProjection; } ); @@ -586,6 +711,10 @@ class SMAANode extends TempNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { this._renderTargetEdges.dispose(); @@ -601,13 +730,25 @@ class SMAANode extends TempNode { } - getAreaTexture() { + /** + * Returns the area texture as a Base64 string. + * + * @private + * @return {String} The area texture. + */ + _getAreaTexture() { return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAIwCAIAAACOVPcQAACBeklEQVR42u39W4xlWXrnh/3WWvuciIzMrKxrV8/0rWbY0+SQFKcb4owIkSIFCjY9AC1BT/LYBozRi+EX+cV+8IMsYAaCwRcBwjzMiw2jAWtgwC8WR5Q8mDFHZLNHTarZGrLJJllt1W2qKrsumZWZcTvn7L3W54e1vrXX3vuciLPPORFR1XE2EomorB0nVuz//r71re/y/1eMvb4Cb3N11xV/PP/2v4UBAwJG/7H8urx6/25/Gf8O5hypMQ0EEEQwAqLfoN/Z+97f/SW+/NvcgQk4sGBJK6H7N4PFVL+K+e0N11yNfkKvwUdwdlUAXPHHL38oa15f/i/46Ih6SuMSPmLAYAwyRKn7dfMGH97jaMFBYCJUgotIC2YAdu+LyW9vvubxAP8kAL8H/koAuOKP3+q6+xGnd5kdYCeECnGIJViwGJMAkQKfDvB3WZxjLKGh8VSCCzhwEWBpMc5/kBbjawT4HnwJfhr+pPBIu7uu+OOTo9vsmtQcniMBGkKFd4jDWMSCRUpLjJYNJkM+IRzQ+PQvIeAMTrBS2LEiaiR9b/5PuT6Ap/AcfAFO4Y3dA3DFH7/VS+M8k4baEAQfMI4QfbVDDGIRg7GKaIY52qAjTAgTvGBAPGIIghOCYAUrGFNgzA7Q3QhgCwfwAnwe5vDejgG44o/fbm1C5ZlYQvQDARPAIQGxCWBM+wWl37ZQESb4gImexGMDouhGLx1Cst0Saa4b4AqO4Hk4gxo+3DHAV/nx27p3JziPM2pVgoiia5MdEzCGULprIN7gEEeQ5IQxEBBBQnxhsDb5auGmAAYcHMA9eAAz8PBol8/xij9+C4Djlim4gJjWcwZBhCBgMIIYxGAVIkH3ZtcBuLdtRFMWsPGoY9rN+HoBji9VBYdwD2ZQg4cnO7OSq/z4rU5KKdwVbFAjNojCQzTlCLPFSxtamwh2jMUcEgg2Wm/6XgErIBhBckQtGN3CzbVacERgCnfgLswhnvqf7QyAq/z4rRZm1YglYE3affGITaZsdIe2FmMIpnOCap25I6jt2kCwCW0D1uAD9sZctNGXcQIHCkINDQgc78aCr+zjtw3BU/ijdpw3zhCwcaONwBvdeS2YZKkJNJsMPf2JKEvC28RXxxI0ASJyzQCjCEQrO4Q7sFArEzjZhaFc4cdv+/JFdKULM4px0DfUBI2hIsy06BqLhGTQEVdbfAIZXYMPesq6VoCHICzUyjwInO4Y411//LYLs6TDa9wvg2CC2rElgAnpTBziThxaL22MYhzfkghz6GAs2VHbbdM91VZu1MEEpupMMwKyVTb5ij9+u4VJG/5EgEMMmFF01cFai3isRbKbzb+YaU/MQbAm2XSMoUPAmvZzbuKYRIFApbtlrfFuUGd6vq2hXNnH78ZLh/iFhsQG3T4D1ib7k5CC6vY0DCbtrohgLEIClXiGtl10zc0CnEGIhhatLBva7NP58Tvw0qE8yWhARLQ8h4+AhQSP+I4F5xoU+VilGRJs6wnS7ruti/4KvAY/CfdgqjsMy4pf8fodQO8/gnuX3f/3xi3om1/h7THr+co3x93PP9+FBUfbNUjcjEmhcrkT+8K7ml7V10Jo05mpIEFy1NmCJWx9SIKKt+EjAL4Ez8EBVOB6havuT/rByPvHXK+9zUcfcbb254+9fydJknYnRr1oGfdaiAgpxu1Rx/Rek8KISftx3L+DfsLWAANn8Hvw0/AFeAGO9DFV3c6D+CcWbL8Dj9e7f+T1k8AZv/d7+PXWM/Z+VvdCrIvuAKO09RpEEQJM0Ci6+B4xhTWr4cZNOvhktabw0ta0rSJmqz3Yw5/AKXwenod7cAhTmBSPKf6JBdvH8IP17h95pXqw50/+BFnj88fev4NchyaK47OPhhtI8RFSvAfDSNh0Ck0p2gLxGkib5NJj/JWCr90EWQJvwBzO4AHcgztwAFN1evHPUVGwfXON+0debT1YeGON9Yy9/63X+OguiwmhIhQhD7l4sMqlG3D86Suc3qWZ4rWjI1X7u0Ytw6x3rIMeIOPDprfe2XzNgyj6PahhBjO4C3e6puDgXrdg+/5l948vF3bqwZetZ+z9Rx9zdIY5pInPK4Nk0t+l52xdK2B45Qd87nM8fsD5EfUhIcJcERw4RdqqH7Yde5V7m1vhNmtedkz6EDzUMF/2jJYWbC+4fzzA/Y+/8PPH3j9dcBAPIRP8JLXd5BpAu03aziOL3VVHZzz3CXWDPWd+SH2AnxIqQoTZpo9Ckc6HIrFbAbzNmlcg8Ag8NFDDAhbJvTBZXbC94P7t68EXfv6o+21gUtPETU7bbkLxvNKRFG2+KXzvtObonPP4rBvsgmaKj404DlshFole1Glfh02fE7bYR7dZ82oTewIBGn1Md6CG6YUF26X376oevOLzx95vhUmgblI6LBZwTCDY7vMq0op5WVXgsObOXJ+1x3qaBl9j1FeLxbhU9w1F+Wiba6s1X/TBz1LnUfuYDi4r2C69f1f14BWfP+p+W2GFKuC9phcELMYRRLur9DEZTUdEH+iEqWdaM7X4WOoPGI+ZYD2+wcQ+y+ioHUZ9dTDbArzxmi/bJI9BND0Ynd6lBdve/butBw8+f/T9D3ABa3AG8W3VPX4hBin+bj8dMMmSpp5pg7fJ6xrBFE2WQQEWnV8Qg3FbAWzYfM1rREEnmvkN2o1+acG2d/9u68GDzx91v3mAjb1zkpqT21OipPKO0b9TO5W0nTdOmAQm0TObts3aBKgwARtoPDiCT0gHgwnbArzxmtcLc08HgF1asN0C4Ms/fvD5I+7PhfqyXE/b7RbbrGyRQRT9ARZcwAUmgdoz0ehJ9Fn7QAhUjhDAQSw0bV3T3WbNa59jzmiP6GsWbGXDX2ytjy8+f9T97fiBPq9YeLdBmyuizZHaqXITnXiMUEEVcJ7K4j3BFPurtB4bixW8wTpweL8DC95szWMOqucFYGsWbGU7p3TxxxefP+r+oTVktxY0v5hbq3KiOKYnY8ddJVSBxuMMVffNbxwIOERShst73HZ78DZrHpmJmH3K6sGz0fe3UUj0eyRrSCGTTc+rjVNoGzNSv05srAxUBh8IhqChiQgVNIIBH3AVPnrsnXQZbLTm8ammv8eVXn/vWpaTem5IXRlt+U/LA21zhSb9cye6jcOfCnOwhIAYXAMVTUNV0QhVha9xjgA27ODJbLbmitt3tRN80lqG6N/khgot4ZVlOyO4WNg3OIMzhIZQpUEHieg2im6F91hB3I2tubql6BYNN9Hj5S7G0G2tahslBWKDnOiIvuAEDzakDQKDNFQT6gbn8E2y4BBubM230YIpBnDbMa+y3dx0n1S0BtuG62lCCXwcY0F72T1VRR3t2ONcsmDjbmzNt9RFs2LO2hQNyb022JisaI8rAWuw4HI3FuAIhZdOGIcdjLJvvObqlpqvWTJnnQbyi/1M9O8UxWhBs//H42I0q1Yb/XPGONzcmm+ri172mHKvZBpHkJaNJz6v9jxqiklDj3U4CA2ugpAaYMWqNXsdXbmJNd9egCnJEsphXNM+MnK3m0FCJ5S1kmJpa3DgPVbnQnPGWIDspW9ozbcO4K/9LkfaQO2KHuqlfFXSbdNzcEcwoqNEFE9zcIXu9/6n/ym/BC/C3aJLzEKPuYVlbFnfhZ8kcWxV3dbv4bKl28566wD+8C53aw49lTABp9PWbsB+knfc/Li3eVizf5vv/xmvnPKg5ihwKEwlrcHqucuVcVOxEv8aH37E3ZqpZypUulrHEtIWKUr+txHg+ojZDGlwnqmkGlzcVi1dLiNSJiHjfbRNOPwKpx9TVdTn3K05DBx4psIk4Ei8aCkJahRgffk4YnEXe07T4H2RR1u27E6wfQsBDofUgjFUFnwC2AiVtA+05J2zpiDK2Oa0c5fmAecN1iJzmpqFZxqYBCYhFTCsUNEmUnIcZ6aEA5rQVhEywG6w7HSW02XfOoBlQmjwulOFQAg66SvJblrTEX1YtJ3uG15T/BH1OfOQeuR8g/c0gdpT5fx2SKbs9EfHTKdM8A1GaJRHLVIwhcGyydZsbifAFVKl5EMKNU2Hryo+06BeTgqnxzYjThVySDikbtJPieco75lYfKAJOMEZBTjoITuWHXXZVhcUDIS2hpiXHV9Ku4u44bN5OYLDOkJo8w+xJSMbhBRHEdEs9JZUCkQrPMAvaHyLkxgkEHxiNkx/x2YB0mGsQ8EUWj/stW5YLhtS5SMu+/YBbNPDCkGTUybN8krRLBGPlZkVOA0j+a1+rkyQKWGaPHPLZOkJhioQYnVZ2hS3zVxMtgC46KuRwbJNd9nV2PHgb36F194ecf/Yeu2vAFe5nm/bRBFrnY4BauE8ERmZRFUn0k8hbftiVYSKMEme2dJCJSCGYAlNqh87bXOPdUkGy24P6d1ll21MBqqx48Fvv8ZHH8HZFY7j/uAq1xMJUFqCSUlJPmNbIiNsmwuMs/q9CMtsZsFO6SprzCS1Z7QL8xCQClEelpjTduDMsmWD8S1PT152BtvmIGvUeDA/yRn83u/x0/4qxoPHjx+PXY9pqX9bgMvh/Nz9kpP4pOe1/fYf3axUiMdHLlPpZCNjgtNFAhcHEDxTumNONhHrBduW+vOyY++70WWnPXj98eA4kOt/mj/5E05l9+O4o8ePx67HFqyC+qSSnyselqjZGaVK2TadbFLPWAQ4NBhHqDCCV7OTpo34AlSSylPtIdd2AJZlyzYQrDJ5lcWGNceD80CunPLGGzsfD+7wRb95NevJI5docQ3tgCyr5bGnyaPRlmwNsFELViOOx9loebGNq2moDOKpHLVP5al2cymWHbkfzGXL7kfRl44H9wZy33tvt+PB/Xnf93e+nh5ZlU18wCiRUa9m7kib9LYuOk+hudQNbxwm0AQqbfloimaB2lM5fChex+ylMwuTbfmXQtmWlenZljbdXTLuOxjI/fDDHY4Hjx8/Hrse0zXfPFxbUN1kKqSCCSk50m0Ajtx3ub9XHBKHXESb8iO6E+qGytF4nO0OG3SXzbJlhxBnKtKyl0NwybjvYCD30aMdjgePHz8eu56SVTBbgxJMliQ3Oauwg0QHxXE2Ez/EIReLdQj42Gzb4CLS0YJD9xUx7bsi0vJi5mUbW1QzL0h0PFk17rtiIPfJk52MB48fPx67npJJwyrBa2RCCQRTbGZSPCxTPOiND4G2pYyOQ4h4jINIJh5wFU1NFZt+IsZ59LSnDqBjZ2awbOku+yInunLcd8VA7rNnOxkPHj9+PGY9B0MWJJNozOJmlglvDMXDEozdhQWbgs/U6oBanGzLrdSNNnZFjOkmbi5bNt1lX7JLLhn3vXAg9/h4y/Hg8ePHI9dzQMEkWCgdRfYykYKnkP7D4rIujsujaKPBsB54vE2TS00ccvFY/Tth7JXeq1hz+qgVy04sAJawTsvOknHfCwdyT062HA8eP348Zj0vdoXF4pilKa2BROed+9fyw9rWRXeTFXESMOanvDZfJuJaSXouQdMdDJZtekZcLLvEeK04d8m474UDuaenW44Hjx8/Xns9YYqZpszGWB3AN/4VHw+k7WSFtJ3Qicuqb/NlVmgXWsxh570xg2UwxUw3WfO6B5nOuO8aA7lnZxuPB48fPx6znm1i4bsfcbaptF3zNT78eFPtwi1OaCNOqp1x3zUGcs/PN++AGD1+fMXrSVm2baTtPhPahbPhA71wIHd2bXzRa69nG+3CraTtPivahV/55tXWg8fyRY/9AdsY8VbSdp8V7cKrrgdfM//z6ILQFtJ2nxHtwmuoB4/kf74+gLeRtvvMaBdeSz34+vifx0YG20jbfTa0C6+tHrwe//NmOG0L8EbSdp8R7cLrrQe/996O+ai3ujQOskpTNULa7jOjXXj99eCd8lHvoFiwsbTdZ0a78PrrwTvlo966pLuRtB2fFe3Cm6oHP9kNH/W2FryxtN1nTLvwRurBO+Kj3pWXHidtx2dFu/Bm68Fb81HvykuPlrb7LGkX3mw9eGs+6h1Y8MbSdjegXcguQLjmevDpTQLMxtJ2N6NdyBZu9AbrwVvwUW+LbteULUpCdqm0HTelXbhNPe8G68Gb8lFvVfYfSNuxvrTdTWoXbozAzdaDZzfkorOj1oxVxlIMlpSIlpLrt8D4hrQL17z+c3h6hU/wv4Q/utps4+bm+6P/hIcf0JwQ5oQGPBL0eKPTYEXTW+eL/2DKn73J9BTXYANG57hz1cEMviVf/4tf5b/6C5pTQkMIWoAq7hTpOJjtAM4pxKu5vg5vXeUrtI09/Mo/5H+4z+Mp5xULh7cEm2QbRP2tFIKR7WM3fPf/jZ3SWCqLM2l4NxID5zB72HQXv3jj/8mLR5xXNA5v8EbFQEz7PpRfl1+MB/hlAN65qgDn3wTgH13hK7T59bmP+NIx1SHHU84nLOITt3iVz8mNO+lPrjGAnBFqmioNn1mTyk1ta47R6d4MrX7tjrnjYUpdUbv2rVr6YpVfsGG58AG8Ah9eyUN8CX4WfgV+G8LVWPDGb+Zd4cU584CtqSbMKxauxTg+dyn/LkVgA+IR8KHtejeFKRtTmLLpxN6mYVLjYxwXf5x2VofiZcp/lwKk4wGOpYDnoIZPdg/AAbwMfx0+ge9dgZvYjuqKe4HnGnykYo5TvJbG0Vj12JagRhwKa44H95ShkZa5RyLGGdfYvG7aw1TsF6iapPAS29mNS3NmsTQZCmgTzFwgL3upCTgtBTRwvGMAKrgLn4evwin8+afJRcff+8izUGUM63GOOuAs3tJkw7J4kyoNreqrpO6cYLQeFUd7TTpr5YOTLc9RUUogUOVJQ1GYJaFLAW0oTmKyYS46ZooP4S4EON3xQ5zC8/CX4CnM4c1PE8ApexpoYuzqlP3d4S3OJP8ZDK7cKWNaTlqmgDiiHwl1YsE41w1zT4iRTm3DBqxvOUsbMKKDa/EHxagtnta072ejc3DOIh5ojvh8l3tk1JF/AV6FU6jh3U8HwEazLgdCLYSQ+MYiAI2ltomkzttUb0gGHdSUUgsIYjTzLG3mObX4FBRaYtpDVNZrih9TgTeYOBxsEnN1gOCTM8Bsw/ieMc75w9kuAT6A+/AiHGvN/+Gn4KRkiuzpNNDYhDGFndWRpE6SVfm8U5bxnSgVV2jrg6JCKmneqey8VMFgq2+AM/i4L4RUbfSi27lNXZ7R7W9RTcq/q9fk4Xw3AMQd4I5ifAZz8FcVtm9SAom/dyN4lczJQW/kC42ZrHgcCoIf1oVMKkVItmMBi9cOeNHGLqOZk+QqQmrbc5YmYgxELUUN35z2iohstgfLIFmcMV7s4CFmI74L9+EFmGsi+tGnAOD4Yk9gIpo01Y4cA43BWGygMdr4YZekG3OBIUXXNukvJS8tqa06e+lSDCtnqqMFu6hWHXCF+WaYt64m9QBmNxi7Ioy7D+fa1yHw+FMAcPt7SysFLtoG4PXAk7JOA3aAxBRqUiAdU9Yp5lK3HLSRFtOim0sa8euEt08xvKjYjzeJ2GU7YawexrnKI9tmobInjFXCewpwriY9+RR4aaezFhMhGCppKwom0ChrgFlKzyPKkGlTW1YQrE9HJqu8hKGgMc6hVi5QRq0PZxNfrYNgE64utmRv6KKHRpxf6VDUaOvNP5jCEx5q185My/7RKz69UQu2im5k4/eownpxZxNLwiZ1AZTO2ZjWjkU9uaB2HFn6Q3u0JcsSx/qV9hTEApRzeBLDJQXxYmTnq7bdLa3+uqFrxLJ5w1TehnNHx5ECvCh2g2c3hHH5YsfdaSKddztfjQ6imKFGSyFwlLzxEGPp6r5IevVjk1AMx3wMqi1NxDVjLBiPs9tbsCkIY5we5/ML22zrCScFxnNtzsr9Wcc3CnD+pYO+4VXXiDE0oc/vQQ/fDK3oPESJMYXNmJa/DuloJZkcTpcYE8lIH8Dz8DJMiynNC86Mb2lNaaqP/+L7f2fcE/yP7/Lde8xfgSOdMxvOixZf/9p3+M4hT1+F+zApxg9XfUvYjc8qX2lfOOpK2gNRtB4flpFu9FTKCp2XJRgXnX6olp1zyYjTKJSkGmLE2NjUr1bxFM4AeAAHBUFIeSLqXR+NvH/M9fOnfHzOD2vCSyQJKzfgsCh+yi/Mmc35F2fUrw7miW33W9hBD1vpuUojFphIyvg7aTeoymDkIkeW3XLHmguMzbIAJejN6B5MDrhipE2y6SoFRO/AK/AcHHZHNIfiWrEe/C6cr3f/yOvrQKB+zMM55/GQdLDsR+ifr5Fiuu+/y+M78LzOE5dsNuXC3PYvYWd8NXvphLSkJIasrlD2/HOqQ+RjcRdjKTGWYhhVUm4yxlyiGPuMsZR7sMCHUBeTuNWA7if+ifXgc/hovftHXs/DV+Fvwe+f8shzMiMcweFgBly3//vwJfg5AN4450fn1Hd1Rm1aBLu22Dy3y3H2+OqMemkbGZ4jozcDjJf6596xOLpC0eMTHbKnxLxH27uZ/bMTGs2jOaMOY4m87CfQwF0dw53oa1k80JRuz/XgS+8fX3N9Af4qPIMfzKgCp4H5TDGe9GGeFPzSsZz80SlPTxXjgwJmC45njzgt2vbQ4b4OAdUK4/vWhO8d8v6EE8fMUsfakXbPpFJeLs2ubM/qdm/la3WP91uWhxXHjoWhyRUq2iJ/+5mA73zwIIo+LoZ/SgvIRjAd1IMvvn98PfgOvAJfhhm8scAKVWDuaRaK8aQ9f7vuPDH6Bj47ZXau7rqYJ66mTDwEDU6lLbCjCK0qTXyl5mnDoeNRxanj3FJbaksTk0faXxHxLrssgPkWB9LnA/MFleXcJozzjwsUvUG0X/QCve51qkMDXp9mtcyOy3rwBfdvVJK7D6/ACSzg3RoruIq5UDeESfEmVclDxnniU82vxMLtceD0hGZWzBNPMM/jSPne2OVatiTKUpY5vY7gc0LdUAWeWM5tH+O2I66AOWw9xT2BuyRVLGdoDHUsVRXOo/c+ZdRXvFfnxWyIV4upFLCl9eAL7h8Zv0QH8Ry8pA2cHzQpGesctVA37ZtklBTgHjyvdSeKY/RZw/kJMk0Y25cSNRWSigQtlULPTw+kzuJPeYEkXjQRpoGZobYsLF79pyd1dMRHInbgFTZqNLhDqiIsTNpoex2WLcy0/X6rHcdMMQvFSd5dWA++4P7xv89deACnmr36uGlL69bRCL6BSZsS6c0TU2TKK5gtWCzgAOOwQcurqk9j8whvziZSMLcq5hbuwBEsYjopUBkqw1yYBGpLA97SRElEmx5MCInBY5vgLk94iKqSWmhIGmkJ4Bi9m4L645J68LyY4wsFYBfUg5feP/6gWWm58IEmKQM89hq7KsZNaKtP5TxxrUZZVkNmMJtjbKrGxLNEbHPJxhqy7lAmbC32ZqeF6lTaknRWcYaFpfLUBh/rwaQycCCJmW15Kstv6jRHyJFry2C1ahkkIW0LO75s61+owxK1y3XqweX9m5YLM2DPFeOjn/iiqCKJ+yKXF8t5Yl/kNsqaSCryxPq5xWTFIaP8KSW0RYxqupaUf0RcTNSSdJZGcKYdYA6kdtrtmyBckfKXwqk0pHpUHlwWaffjNRBYFPUDWa8e3Lt/o0R0CdisKDM89cX0pvRHEfM8ca4t0s2Xx4kgo91MPQJ/0c9MQYq0co8MBh7bz1fio0UUHLR4aAIOvOmoYO6kwlEVODSSTliWtOtH6sPkrtctF9ZtJ9GIerBskvhdVS5cFNv9s1BU0AbdUgdK4FG+dRnjFmDTzniRMdZO1QhzMK355vigbdkpz9P6qjUGE5J2qAcXmwJ20cZUiAD0z+pGMx6xkzJkmEf40Hr4qZfVg2XzF9YOyoV5BjzVkUJngKf8lgNYwKECEHrCNDrWZzMlflS3yBhr/InyoUgBc/lKT4pxVrrC6g1YwcceK3BmNxZcAtz3j5EIpqguh9H6wc011YN75cKDLpFDxuwkrPQmUwW4KTbj9mZTwBwLq4aQMUZbHm1rylJ46dzR0dua2n3RYCWZsiHROeywyJGR7mXKlpryyCiouY56sFkBWEnkEB/raeh/Sw4162KeuAxMQpEkzy5alMY5wamMsWKKrtW2WpEWNnReZWONKWjrdsKZarpFjqCslq773PLmEhM448Pc3+FKr1+94vv/rfw4tEcu+lKTBe4kZSdijBrykwv9vbCMPcLQTygBjzVckSLPRVGslqdunwJ4oegtFOYb4SwxNgWLCmD7T9kVjTv5YDgpo0XBmN34Z/rEHp0sgyz7lngsrm4lvMm2Mr1zNOJYJ5cuxuQxwMGJq/TP5emlb8fsQBZviK4t8hFL+zbhtlpwaRSxQRWfeETjuauPsdGxsBVdO7nmP4xvzSoT29pRl7kGqz+k26B3Oy0YNV+SXbbQas1ctC/GarskRdFpKczVAF1ZXnLcpaMuzVe6lZ2g/1ndcvOVgRG3sdUAY1bKD6achijMPdMxV4muKVorSpiDHituH7rSTs7n/4y5DhRXo4FVBN4vO/zbAcxhENzGbHCzU/98Mcx5e7a31kWjw9FCe/zNeYyQjZsWb1uc7U33pN4Mji6hCLhivqfa9Ss6xLg031AgfesA/l99m9fgvnaF9JoE6bYKmkGNK3aPbHB96w3+DnxFm4hs0drLsk7U8kf/N/CvwQNtllna0rjq61sH8L80HAuvwH1tvBy2ChqWSCaYTaGN19sTvlfzFD6n+iKTbvtayfrfe9ueWh6GJFoxLdr7V72a5ZpvHcCPDzma0wTO4EgbLyedxstO81n57LYBOBzyfsOhUKsW1J1BB5vr/tz8RyqOFylQP9Tvst2JALsC5lsH8PyQ40DV4ANzYa4dedNiKNR1s+x2wwbR7q4/4cTxqEk4LWDebfisuo36JXLiWFjOtLrlNWh3K1rRS4xvHcDNlFnNmWBBAl5SWaL3oPOfnvbr5pdjVnEaeBJSYjuLEkyLLsWhKccadmOphZkOPgVdalj2QpSmfOsADhMWE2ZBu4+EEJI4wKTAuCoC4xwQbWXBltpxbjkXJtKxxabo9e7tyhlgb6gNlSbUpMh+l/FaqzVwewGu8BW1Zx7pTpQDJUjb8tsUTW6+GDXbMn3mLbXlXJiGdggxFAoUrtPS3wE4Nk02UZG2OOzlk7fRs7i95QCLo3E0jtrjnM7SR3uS1p4qtS2nJ5OwtQVHgOvArLBFijZUV9QtSl8dAY5d0E0hM0w3HS2DpIeB6m/A1+HfhJcGUq4sOxH+x3f5+VO+Ds9rYNI7zPXOYWPrtf8bYMx6fuOAX5jzNR0PdsuON+X1f7EERxMJJoU6GkTEWBvVolVlb5lh3tKCg6Wx1IbaMDdJ+9sUCc5KC46hKGCk3IVOS4TCqdBNfUs7Kd4iXf2RjnT/LLysJy3XDcHLh/vde3x8DoGvwgsa67vBk91G5Pe/HbOe7xwym0NXbtiuuDkGO2IJDh9oQvJ4cY4vdoqLDuoH9Zl2F/ofsekn8lkuhIlhQcffUtSjytFyp++p6NiE7Rqx/lodgKVoceEp/CP4FfjrquZaTtj2AvH5K/ywpn7M34K/SsoYDAdIN448I1/0/wveW289T1/lX5xBzc8N5IaHr0XMOQdHsIkDuJFifj20pBm5jzwUv9e2FhwRsvhAbalCIuIw3bhJihY3p6nTFFIZgiSYjfTf3aXuOjmeGn4bPoGvwl+CFzTRczBIuHBEeImHc37/lGfwZR0cXzVDOvaKfNHvwe+suZ771K/y/XcBlsoN996JpBhoE2toYxOznNEOS5TJc6Id5GEXLjrWo+LEWGNpPDU4WAwsIRROu+1vM+0oW37z/MBN9kqHnSArwPfgFJ7Cq/Ai3Ie7g7ncmI09v8sjzw9mzOAEXoIHxURueaAce5V80f/DOuuZwHM8vsMb5wBzOFWM7wymTXPAEvm4vcFpZ2ut0VZRjkiP2MlmLd6DIpbGSiHOjdnUHN90hRYmhTnmvhzp1iKDNj+b7t5hi79lWGwQ+HN9RsfFMy0FXbEwhfuczKgCbyxYwBmcFhhvo/7a44v+i3XWcwDP86PzpGQYdWh7csP5dBvZ1jNzdxC8pBGuxqSW5vw40nBpj5JhMwvOzN0RWqERHMr4Lv1kWX84xLR830G3j6yqZ1a8UstTlW+qJPOZ+sZ7xZPKTJLhiNOAFd6tk+jrTH31ncLOxid8+nzRb128HhUcru/y0Wn6iT254YPC6FtVSIMoW2sk727AhvTtrWKZTvgsmckfXYZWeNRXx/3YQ2OUxLDrbHtN11IwrgXT6c8dATDwLniYwxzO4RzuQqTKSC5gAofMZ1QBK3zQ4JWobFbcvJm87FK+6JXrKahLn54m3p+McXzzYtP8VF/QpJuh1OwieElEoI1pRxPS09FBrkq2tWCU59+HdhNtTIqKm8EBrw2RTOEDpG3IKo2Y7mFdLm3ZeVjYwVw11o/oznceMve4CgMfNym/utA/d/ILMR7gpXzRy9eDsgLcgbs8O2Va1L0zzIdwGGemTBuwROHeoMShkUc7P+ISY3KH5ZZeWqO8mFTxQYeXTNuzvvK5FGPdQfuu00DwYFY9dyhctEt+OJDdnucfpmyhzUJzfsJjr29l8S0bXBfwRS9ZT26tmMIdZucch5ZboMz3Nio3nIOsYHCGoDT4kUA9MiXEp9Xsui1S8th/kbWIrMBxDGLodWUQIWcvnXy+9M23xPiSMOiRPqM+YMXkUN3gXFrZJwXGzUaMpJfyRS9ZT0lPe8TpScuRlbMHeUmlaKDoNuy62iWNTWNFYjoxFzuJs8oR+RhRx7O4SVNSXpa0ZJQ0K1LAHDQ+D9IepkMXpcsq5EVCvClBUIzDhDoyKwDw1Lc59GbTeORivugw1IcuaEOaGWdNm+Ps5fQ7/tm0DjMegq3yM3vb5j12qUId5UZD2oxDSEWOZMSqFl/W+5oynWDa/aI04tJRQ2eTXusg86SQVu/nwSYwpW6wLjlqIzwLuxGIvoAvul0PS+ZNz0/akp/pniO/8JDnGyaCkzbhl6YcqmK/69prxPqtpx2+Km9al9sjL+rwMgHw4jE/C8/HQ3m1vBuL1fldbzd8mOueVJ92syqdEY4KJjSCde3mcRw2TA6szxedn+zwhZMps0XrqEsiUjnC1hw0TELC2Ek7uAAdzcheXv1BYLagspxpzSAoZZUsIzIq35MnFQ9DOrlNB30jq3L4pkhccKUAA8/ocvN1Rzx9QyOtERs4CVsJRK/DF71kPYrxYsGsm6RMh4cps5g1DOmM54Ly1ii0Hd3Y/BMk8VWFgBVmhqrkJCPBHAolwZaWzLR9Vb7bcWdX9NyUYE+uB2BKfuaeBUcjDljbYVY4DdtsVWvzRZdWnyUzDpjNl1Du3aloAjVJTNDpcIOVVhrHFF66lLfJL1zJr9PQ2nFJSBaKoDe+sAvLufZVHVzYh7W0h/c6AAZ+7Tvj6q9j68G/cTCS/3n1vLKHZwNi+P+pS0WkZNMBMUl+LDLuiE4omZy71r3UFMwNJV+VJ/GC5ixVUkBStsT4gGKh0Gm4Oy3qvq7Lbmq24nPdDuDR9deR11XzP4vFu3TYzfnIyiSVmgizUYGqkIXNdKTY9pgb9D2Ix5t0+NHkVzCdU03suWkkVZAoCONCn0T35gAeW38de43mf97sMOpSvj4aa1KYUm58USI7Wxxes03bAZdRzk6UtbzMaCQ6IxO0dy7X+XsjoD16hpsBeGz9dfzHj+R/Hp8nCxZRqkEDTaCKCSywjiaoMJ1TITE9eg7Jqnq8HL6gDwiZb0u0V0Rr/rmvqjxKuaLCX7ZWXTvAY+uvm3z8CP7nzVpngqrJpZKwWnCUjIviYVlirlGOzPLI3SMVyp/elvBUjjDkNhrtufFFErQ8pmdSlbK16toBHlt/HV8uHMX/vEGALkV3RJREiSlopxwdMXOZPLZ+ix+kAHpMKIk8UtE1ygtquttwxNhphrIZ1IBzjGF3IIGxGcBj6q8bHJBG8T9vdsoWrTFEuebEZuVxhhClH6P5Zo89OG9fwHNjtNQTpD0TG9PJLEYqvEY6Rlxy+ZZGfL0Aj62/bnQCXp//eeM4KzfQVJbgMQbUjlMFIm6TpcfWlZje7NBSV6IsEVmumWIbjiloUzQX9OzYdo8L1wjw2PrrpimONfmfNyzKklrgnEkSzT5QWYQW40YShyzqsRmMXbvVxKtGuYyMKaU1ugenLDm5Ily4iT14fP11Mx+xJv+zZ3MvnfdFqxU3a1W/FTB4m3Qfsyc1XUcdVhDeUDZXSFHHLQj/Y5jtC7ZqM0CXGwB4bP11i3LhOvzPGygYtiUBiwQV/4wFO0majijGsafHyRLu0yG6q35cL1rOpVxr2s5cM2jJYMCdc10Aj6q/blRpWJ//+dmm5psMl0KA2+AFRx9jMe2WbC4jQxnikd4DU8TwUjRVacgdlhmr3bpddzuJ9zXqr2xnxJfzP29RexdtjDVZqzkqa6PyvcojGrfkXiJ8SEtml/nYskicv0ivlxbqjemwUjMw5evdg8fUX9nOiC/lf94Q2i7MURk9nW1MSj5j8eAyV6y5CN2S6qbnw3vdA1Iwq+XOSCl663udN3IzLnrt+us25cI1+Z83SXQUldqQq0b5XOT17bGpLd6ssN1VMPf8c+jG8L3NeCnMdF+Ra3fRa9dft39/LuZ/3vwHoHrqGmQFafmiQw6eyzMxS05K4bL9uA+SKUQzCnSDkqOGokXyJvbgJ/BHI+qvY69//4rl20NsmK2ou2dTsyIALv/91/8n3P2Aao71WFGi8KKv1fRC5+J67Q/507/E/SOshqN5TsmYIjVt+kcjAx98iz/4SaojbIV1rexE7/C29HcYD/DX4a0rBOF5VTu7omsb11L/AWcVlcVZHSsqGuXLLp9ha8I//w3Mv+T4Ew7nTBsmgapoCrNFObIcN4pf/Ob/mrvHTGqqgAupL8qWjWPS9m/31jAe4DjA+4+uCoQoT/zOzlrNd3qd4SdphFxsUvYwGWbTWtISc3wNOWH+kHBMfc6kpmpwPgHWwqaSUG2ZWWheYOGQGaHB+eQ/kn6b3pOgLV+ODSn94wDvr8Bvb70/LLuiPPEr8OGVWfDmr45PZyccEmsVXZGe1pRNX9SU5+AVQkNTIVPCHF/jGmyDC9j4R9LfWcQvfiETmgMMUCMN1uNCakkweZsowdYobiMSlnKA93u7NzTXlSfe+SVbfnPQXmg9LpYAQxpwEtONyEyaueWM4FPjjyjG3uOaFmBTWDNgBXGEiQpsaWhnAqIijB07Dlsy3fUGeP989xbWkyf+FF2SNEtT1E0f4DYYVlxFlbaSMPIRMk/3iMU5pME2SIWJvjckciebkQuIRRyhUvkHg/iUljG5kzVog5hV7vIlCuBrmlhvgPfNHQM8lCf+FEGsYbMIBC0qC9a0uuy2wLXVbLBaP5kjHokCRxapkQyzI4QEcwgYHRZBp+XEFTqXFuNVzMtjXLJgX4gAid24Hjwc4N3dtVSe+NNiwTrzH4WVUOlDobUqr1FuAgYllc8pmzoVrELRHSIW8ViPxNy4xwjBpyR55I6J220qQTZYR4guvUICJiSpr9gFFle4RcF/OMB7BRiX8sSfhpNSO3lvEZCQfLUVTKT78Ek1LRLhWN+yLyTnp8qWUZ46b6vxdRGXfHVqx3eI75YaLa4iNNiK4NOW7wPW6lhbSOF9/M9qw8e/aoB3d156qTzxp8pXx5BKAsYSTOIIiPkp68GmTq7sZtvyzBQaRLNxIZ+paozHWoLFeExIhRBrWitHCAHrCF7/thhD8JhYz84wg93QRV88wLuLY8zF8sQ36qF1J455bOlgnELfshKVxYOXKVuKx0jaj22sczTQqPqtV/XDgpswmGTWWMSDw3ssyUunLLrVPGjYRsH5ggHeHSWiV8kT33ycFSfMgkoOK8apCye0J6VW6GOYvffgU9RWsukEi2kUV2nl4dOYUzRik9p7bcA4ggdJ53LxKcEe17B1R8eqAd7dOepV8sTXf5lhejoL85hUdhDdknPtKHFhljOT+bdq0hxbm35p2nc8+Ja1Iw+tJykgp0EWuAAZYwMVwac5KzYMslhvgHdHRrxKnvhTYcfKsxTxtTETkjHO7rr3zjoV25lAQHrqpV7bTiy2aXMmUhTBnKS91jhtR3GEoF0oLnWhWNnYgtcc4N0FxlcgT7yz3TgNIKkscx9jtV1ZKpWW+Ub1tc1eOv5ucdgpx+FJy9pgbLE7xDyXb/f+hLHVGeitHOi6A7ybo3sF8sS7w7cgdk0nJaOn3hLj3uyD0Zp5pazFIUXUpuTTU18d1EPkDoX8SkmWTnVIozEdbTcZjoqxhNHf1JrSS/AcvHjZ/SMHhL/7i5z+POsTUh/8BvNfYMTA8n+yU/MlTZxSJDRStqvEuLQKWwDctMTQogUDyQRoTQG5Kc6oQRE1yV1jCA7ri7jdZyK0sYTRjCR0Hnnd+y7nHxNgTULqw+8wj0mQKxpYvhjm9uSUxg+TTy7s2GtLUGcywhXSKZN275GsqlclX90J6bRI1aouxmgL7Q0Nen5ziM80SqMIo8cSOo+8XplT/5DHNWsSUr/6lLN/QQ3rDyzLruEW5enpf7KqZoShEduuSFOV7DLX7Ye+GmXb6/hnNNqKsVXuMDFpb9Y9eH3C6NGEzuOuI3gpMH/I6e+zDiH1fXi15t3vA1czsLws0TGEtmPEJdiiFPwlwKbgLHAFk4P6ZyPdymYYHGE0dutsChQBl2JcBFlrEkY/N5bQeXQ18gjunuMfMfsBlxJSx3niO485fwO4fGD5T/+3fPQqkneWVdwnw/3bMPkW9Wbqg+iC765Zk+xcT98ibKZc2EdgHcLoF8cSOo/Oc8fS+OyEULF4g4sJqXVcmfMfsc7A8v1/yfGXmL9I6Fn5pRwZhsPv0TxFNlAfZCvG+Oohi82UC5f/2IsJo0cTOm9YrDoKhFPEUr/LBYTUNht9zelHXDqwfPCIw4owp3mOcIQcLttWXFe3VZ/j5H3cIc0G6oPbCR+6Y2xF2EC5cGUm6wKC5tGEzhsWqw5hNidUiKX5gFWE1GXh4/Qplw4sVzOmx9QxU78g3EF6wnZlEN4FzJ1QPSLEZz1KfXC7vd8ssGdIbNUYpVx4UapyFUHzJoTOo1McSkeNn1M5MDQfs4qQuhhX5vQZFw8suwWTcyYTgioISk2YdmkhehG4PkE7w51inyAGGaU+uCXADabGzJR1fn3lwkty0asIo8cROm9Vy1g0yDxxtPvHDAmpu+PKnM8Ix1wwsGw91YJqhteaWgjYBmmQiebmSpwKKzE19hx7jkzSWOm66oPbzZ8Yj6kxVSpYjVAuvLzYMCRo3oTQecOOjjgi3NQ4l9K5/hOGhNTdcWVOTrlgYNkEXINbpCkBRyqhp+LdRB3g0OU6rMfW2HPCFFMV9nSp+uB2woepdbLBuJQyaw/ZFysXrlXwHxI0b0LovEkiOpXGA1Ijagf+KUNC6rKNa9bQnLFqYNkEnMc1uJrg2u64ELPBHpkgWbmwKpJoDhMwNbbGzAp7Yg31wS2T5rGtzit59PrKhesWG550CZpHEzpv2NGRaxlNjbMqpmEIzygJqQfjypycs2pg2cS2RY9r8HUqkqdEgKTWtWTKoRvOBPDYBltja2SO0RGjy9UHtxwRjA11ujbKF+ti5cIR9eCnxUg6owidtyoU5tK4NLji5Q3HCtiyF2IqLGYsHViOXTXOYxucDqG0HyttqYAKqYo3KTY1ekyDXRAm2AWh9JmsVh/ccg9WJ2E8YjG201sPq5ULxxX8n3XLXuMInbft2mk80rRGjCGctJ8/GFdmEQ9Ug4FlE1ll1Y7jtiraqm5Fe04VV8lvSVBL8hiPrfFVd8+7QH3Qbu2ipTVi8cvSGivc9cj8yvH11YMHdNSERtuOslM97feYFOPKzGcsI4zW0YGAbTAOaxCnxdfiYUmVWslxiIblCeAYr9VYR1gM7GmoPrilunSxxeT3DN/2eBQ9H11+nk1adn6VK71+5+Jfct4/el10/7KBZfNryUunWSCPxPECk1rdOv1WVSrQmpC+Tl46YD3ikQYcpunSQgzVB2VHFhxHVGKDgMEY5GLlQnP7FMDzw7IacAWnO6sBr12u+XanW2AO0wQ8pknnFhsL7KYIqhkEPmEXFkwaN5KQphbkUmG72wgw7WSm9RiL9QT925hkjiVIIhphFS9HKI6/8QAjlpXqg9W2C0apyaVDwKQwrwLY3j6ADR13ZyUNByQXHQu6RY09Hu6zMqXRaNZGS/KEJs0cJEe9VH1QdvBSJv9h09eiRmy0V2uJcqHcShcdvbSNg5fxkenkVprXM9rDVnX24/y9MVtncvbKY706anNl3ASll9a43UiacVquXGhvq4s2FP62NGKfQLIQYu9q1WmdMfmUrDGt8eDS0cXozH/fjmUH6Jruvm50hBDSaEU/2Ru2LEN/dl006TSc/g7tfJERxGMsgDUEr104pfWH9lQaN+M4KWQjwZbVc2rZVNHsyHal23wZtIs2JJqtIc/WLXXRFCpJkfE9jvWlfFbsNQ9pP5ZBS0zKh4R0aMFj1IjTcTnvi0Zz2rt7NdvQb2mgbju1plsH8MmbnEk7KbK0b+wC2iy3aX3szW8xeZvDwET6hWZYwqTXSSG+wMETKum0Dq/q+x62gt2ua2ppAo309TRk9TPazfV3qL9H8z7uhGqGqxNVg/FKx0HBl9OVUORn8Q8Jx9gFttGQUDr3tzcXX9xGgN0EpzN9mdZ3GATtPhL+CjxFDmkeEU6x56kqZRusLzALXVqkCN7zMEcqwjmywDQ6OhyUe0Xao1Qpyncrg6wKp9XfWDsaZplElvQ/b3sdweeghorwBDlHzgk1JmMc/wiERICVy2VJFdMjFuLQSp3S0W3+sngt2njwNgLssFGVQdJ0tu0KH4ky1LW4yrbkuaA6Iy9oz/qEMMXMMDWyIHhsAyFZc2peV9hc7kiKvfULxCl9iddfRK1f8kk9qvbdOoBtOg7ZkOZ5MsGrSHsokgLXUp9y88smniwWyuFSIRVmjplga3yD8Uij5QS1ZiM4U3Qw5QlSm2bXjFe6jzzBFtpg+/YBbLAWG7OPynNjlCw65fukGNdkJRf7yM1fOxVzbxOJVocFoYIaGwH22mIQkrvu1E2nGuebxIgW9U9TSiukPGU+Lt++c3DJPKhyhEEbXCQLUpae2exiKy6tMPe9mDRBFCEMTWrtwxN8qvuGnt6MoihKWS5NSyBhbH8StXoAz8PLOrRgLtOT/+4vcu+7vDLnqNvztOq7fmd8sMmY9Xzn1zj8Dq8+XVdu2Nv0IIySgEdQo3xVHps3Q5i3fLFsV4aiqzAiBhbgMDEd1uh8qZZ+lwhjkgokkOIv4xNJmyncdfUUzgB4oFMBtiu71Xumpz/P+cfUP+SlwFExwWW62r7b+LSPxqxn/gvMZ5z9C16t15UbNlq+jbGJtco7p8wbYlL4alSyfWdeuu0j7JA3JFNuVAwtst7F7FhWBbPFNKIUORndWtLraFLmMu7KFVDDOzqkeaiN33YAW/r76wR4XDN/yN1z7hejPau06EddkS/6XThfcz1fI/4K736fO48vlxt2PXJYFaeUkFS8U15XE3428xdtn2kc8GQlf1vkIaNRRnOMvLTWrZbElEHeLWi1o0dlKPAh1MVgbbVquPJ5+Cr8LU5/H/+I2QlHIU2ClXM9G8v7Rr7oc/hozfUUgsPnb3D+I+7WF8kNO92GY0SNvuxiE+2Bt8prVJTkzE64sfOstxuwfxUUoyk8VjcTlsqe2qITSFoSj6Epd4KsT6BZOWmtgE3hBfir8IzZDwgV4ZTZvD8VvPHERo8v+vL1DASHTz/i9OlKueHDjK5Rnx/JB1Vb1ioXdBra16dmt7dgik10yA/FwJSVY6XjA3oy4SqM2frqDPPSRMex9qs3XQtoWxMj7/Er8GWYsXgjaVz4OYumP2+9kbxvny/6kvWsEBw+fcb5bInc8APdhpOSs01tEqIkoiZjbAqKMruLbJYddHuHFRIyJcbdEdbl2sVLaySygunutBg96Y2/JjKRCdyHV+AEFtTvIpbKIXOamknYSiB6KV/0JetZITgcjjk5ZdaskBtWO86UF0ap6ozGXJk2WNiRUlCPFir66lzdm/SLSuK7EUdPz8f1z29Skq6F1fXg8+5UVR6bszncP4Tn4KUkkdJ8UFCY1zR1i8RmL/qQL3rlei4THG7OODlnKko4oI01kd3CaM08Ia18kC3GNoVaO9iDh+hWxSyTXFABXoau7Q6q9OxYg/OVEMw6jdbtSrJ9cBcewGmaZmg+bvkUnUUaGr+ZfnMH45Ivevl61hMcXsxYLFTu1hTm2zViCp7u0o5l+2PSUh9bDj6FgYypufBDhqK2+oXkiuHFHR3zfj+9PtA8oR0xnqX8qn+sx3bFODSbbF0X8EUvWQ8jBIcjo5bRmLOljDNtcqNtOe756h3l0VhKa9hDd2l1eqmsnh0MNMT/Cqnx6BInumhLT8luljzQ53RiJeA/0dxe5NK0o2fA1+GLXr6eNQWHNUOJssQaTRlGpLHKL9fD+IrQzTOMZS9fNQD4AnRNVxvTdjC+fJdcDDWQcyB00B0t9BDwTxXgaAfzDZ/DBXzRnfWMFRwuNqocOmX6OKNkY63h5n/fFcB28McVHqnXZVI27K0i4rDLNE9lDKV/rT+udVbD8dFFu2GGZ8mOt0kAXcoX3ZkIWVtw+MNf5NjR2FbivROHmhV1/pj2egv/fMGIOWTIWrV3Av8N9imV9IWml36H6cUjqEWNv9aNc+veb2sH46PRaHSuMBxvtW+twxctq0z+QsHhux8Q7rCY4Ct8lqsx7c6Sy0dl5T89rIeEuZKoVctIk1hNpfavER6yyH1Vvm3MbsUHy4ab4hWr/OZPcsRBphnaV65/ZcdYPNNwsjN/djlf9NqCw9U5ExCPcdhKxUgLSmfROpLp4WSUr8ojdwbncbvCf+a/YzRaEc6QOvXcGO256TXc5Lab9POvB+AWY7PigWYjzhifbovuunzRawsO24ZqQQAqguBtmpmPB7ysXJfyDDaV/aPGillgz1MdQg4u5MYaEtBNNHFjkRlSpd65lp4hd2AVPTfbV7FGpyIOfmNc/XVsPfg7vzaS/3nkvLL593ANLvMuRMGpQIhiF7kUEW9QDpAUbTWYBcbp4WpacHHY1aacqQyjGZS9HI3yCBT9kUZJhVOD+zUDvEH9ddR11fzPcTDQ5TlgB0KwqdXSavk9BC0pKp0WmcuowSw07VXmXC5guzSa4p0UvRw2lbDiYUx0ExJJRzWzi6Gm8cnEkfXXsdcG/M/jAJa0+bmCgdmQ9CYlNlSYZOKixmRsgiFxkrmW4l3KdFKv1DM8tk6WxPYJZhUUzcd8Kdtgrw/gkfXXDT7+avmfVak32qhtkg6NVdUS5wgkru1YzIkSduTW1FDwVWV3JQVJVuieTc0y4iDpFwc7/BvSalvKdQM8sv662cevz/+8sQVnjVAT0W2wLllw1JiMhJRxgDjCjLQsOzSFSgZqx7lAW1JW0e03yAD3asC+GD3NbQhbe+mN5GXH1F83KDOM4n/e5JIuH4NpdQARrFPBVptUNcjj4cVMcFSRTE2NpR1LEYbYMmfWpXgP9KejaPsLUhuvLCsVXznAG9dfx9SR1ud/3hZdCLHb1GMdPqRJgqDmm76mHbvOXDtiO2QPUcKo/TWkQ0i2JFXpBoo7vij1i1Lp3ADAo+qvG3V0rM//vFnnTE4hxd5Ka/Cor5YEdsLVJyKtDgVoHgtW11pWSjolPNMnrlrVj9Fv2Qn60twMwKPqr+N/wvr8z5tZcDsDrv06tkqyzESM85Ycv6XBWA2birlNCXrI6VbD2lx2L0vQO0QVTVVLH4SE67fgsfVXv8n7sz7/85Z7cMtbE6f088wSaR4kCkCm10s6pKbJhfqiUNGLq+0gLWC6eUAZFPnLjwqtKd8EwGvWX59t7iPW4X/eAN1svgRVSY990YZg06BD1ohLMtyFTI4pKTJsS9xREq9EOaPWiO2gpms7397x6nQJkbh+Fz2q/rqRROX6/M8bJrqlVW4l6JEptKeUFuMYUbtCQ7CIttpGc6MY93x1r1vgAnRXvY5cvwWPqb9uWQm+lP95QxdNMeWhOq1x0Db55C7GcUv2ZUuN6n8iKzsvOxibC//Yfs9Na8r2Rlz02vXXDT57FP/zJi66/EJSmsJKa8QxnoqW3VLQ+jZVUtJwJ8PNX1NQCwfNgdhhHD9on7PdRdrdGPF28rJr1F+3LBdeyv+8yYfLoMYet1vX4upNAjVvwOUWnlNXJXlkzk5Il6kqeoiL0C07qno+/CYBXq/+utlnsz7/Mzvy0tmI4zm4ag23PRN3t/CWryoUVJGm+5+K8RJ0V8Hc88/XHUX/HfiAq7t+BH+x6v8t438enWmdJwFA6ZINriLGKv/95f8lT9/FnyA1NMVEvQyaXuu+gz36f/DD73E4pwqpLcvm/o0Vle78n//+L/NPvoefp1pTJye6e4A/D082FERa5/opeH9zpvh13cNm19/4v/LDe5xMWTi8I0Ta0qKlK27AS/v3/r+/x/2GO9K2c7kVMonDpq7//jc5PKCxeNPpFVzaRr01wF8C4Pu76hXuX18H4LduTr79guuFD3n5BHfI+ZRFhY8w29TYhbbLi/bvBdqKE4fUgg1pBKnV3FEaCWOWyA+m3WpORZr/j+9TKJtW8yBTF2/ZEODI9/QavHkVdGFp/Pjn4Q+u5hXapsP5sOH+OXXA1LiKuqJxiMNbhTkbdJTCy4llEt6NnqRT4dhg1V3nbdrm6dYMecA1yTOL4PWTE9L5VzPFlLBCvlG58AhehnN4uHsAYinyJ+AZ/NkVvELbfOBUuOO5syBIEtiqHU1k9XeISX5bsimrkUUhnGDxourN8SgUsCZVtKyGbyGzHXdjOhsAvOAswSRyIBddRdEZWP6GZhNK/yjwew9ehBo+3jEADu7Ay2n8mDc+TS7awUHg0OMzR0LABhqLD4hJEh/BEGyBdGlSJoXYXtr+3HS4ijzVpgi0paWXtdruGTknXBz+11qT1Q2inxaTzQCO46P3lfLpyS4fou2PH/PupwZgCxNhGlj4IvUuWEsTkqMWm6i4xCSMc9N1RDQoCVcuGItJ/MRWefais+3synowi/dESgJjkilnWnBTGvRWmaw8oR15257t7CHmCf8HOn7cwI8+NQBXMBEmAa8PMRemrNCEhLGEhDQKcGZWS319BX9PFBEwGTbRBhLbDcaV3drFcDqk5kCTd2JF1Wp0HraqBx8U0wwBTnbpCadwBA/gTH/CDrcCs93LV8E0YlmmcyQRQnjBa8JESmGUfIjK/7fkaDJpmD2QptFNVJU1bbtIAjjWQizepOKptRjbzR9Kag6xZmMLLjHOtcLT3Tx9o/0EcTT1XN3E45u24AiwEypDJXihKjQxjLprEwcmRKclaDNZCVqr/V8mYWyFADbusiY5hvgFoU2vio49RgJLn5OsReRFN6tabeetiiy0V7KFHT3HyZLx491u95sn4K1QQSPKM9hNT0wMVvAWbzDSVdrKw4zRjZMyJIHkfq1VAVCDl/bUhNKlGq0zGr05+YAceXVPCttVk0oqjVwMPt+BBefx4yPtGVkUsqY3CHDPiCM5ngupUwCdbkpd8kbPrCWHhkmtIKLEetF2499eS1jZlIPGYnlcPXeM2KD9vLS0bW3ktYNqUllpKLn5ZrsxlIzxvDu5eHxzGLctkZLEY4PgSOg2IUVVcUONzUDBEpRaMoXNmUc0tFZrTZquiLyKxrSm3DvIW9Fil+AkhXu5PhEPx9mUNwqypDvZWdKlhIJQY7vn2OsnmBeOWnYZ0m1iwbbw1U60by5om47iHRV6fOgzjMf/DAZrlP40Z7syxpLK0lJ0gqaAK1c2KQKu7tabTXkLFz0sCftuwX++MyNeNn68k5Buq23YQhUh0SNTJa1ioQ0p4nUG2y0XilF1JqODqdImloPS4Bp111DEWT0jJjVv95uX9BBV7eB3bUWcu0acSVM23YZdd8R8UbQUxJ9wdu3oMuhdt929ME+mh6JXJ8di2RxbTi6TbrDquqV4aUKR2iwT6aZbyOwEXN3DUsWr8Hn4EhwNyHuXHh7/pdaUjtR7vnDh/d8c9xD/s5f501eQ1+CuDiCvGhk1AN/4Tf74RfxPwD3toLarR0zNtsnPzmS64KIRk861dMWCU8ArasG9T9H0ZBpsDGnjtAOM2+/LuIb2iIUGXNgl5ZmKD/Tw8TlaAuihaFP5yrw18v4x1898zIdP+DDAX1bM3GAMvPgRP/cJn3zCW013nrhHkrITyvYuwOUkcHuKlRSW5C6rzIdY4ppnF7J8aAJbQepgbJYBjCY9usGXDKQxq7RZfh9eg5d1UHMVATRaD/4BHK93/1iAgYZ/+jqPn8Dn4UExmWrpa3+ZOK6MvM3bjwfzxNWA2dhs8+51XHSPJiaAhGSpWevEs5xHLXcEGFXYiCONySH3fPWq93JIsBiSWvWyc3CAN+EcXoT7rCSANloPPoa31rt/5PUA/gp8Q/jDD3hyrjzlR8VkanfOvB1XPubt17vzxAfdSVbD1pzAnfgyF3ycadOTOTXhpEUoLC1HZyNGW3dtmjeXgr2r56JNmRwdNNWaQVBddd6rh4MhviEB9EFRD/7RGvePvCbwAL4Mx/D6M541hHO4D3e7g6PafdcZVw689z7NGTwo5om7A8sPhccT6qKcl9NJl9aM/9kX+e59Hh1yPqGuCCZxuITcsmNaJ5F7d0q6J3H48TO1/+M57085q2icdu2U+W36Ldllz9Agiv4YGljoEN908EzvDOrBF98/vtJwCC/BF2AG75xxEmjmMIcjxbjoaxqOK3/4hPOZzhMPBpYPG44CM0dTVm1LjLtUWWVz1Bcf8tEx0zs8O2A2YVHRxKYOiy/aOVoAaMu0i7ubu43njjmd4ibMHU1sIDHaQNKrZND/FZYdk54oCXetjq7E7IVl9eAL7t+oHnwXXtLx44czzoRFHBztYVwtH1d+NOMkupZ5MTM+gUmq90X+Bh9zjRlmaQ+m7YMqUL/veemcecAtOJ0yq1JnVlN27di2E0+Klp1tAJ4KRw1eMI7aJjsO3R8kPSI3fUFXnIOfdQe86sIIVtWDL7h//Ok6vj8vwDk08NEcI8zz7OhBy+WwalzZeZ4+0XniRfst9pAJqQHDGLzVQ2pheZnnv1OWhwO43/AgcvAEXEVVpa4db9sGvNK8wjaENHkfFQ4Ci5i7dqnQlPoLQrHXZDvO3BIXZbJOBrOaEbML6sFL798I4FhKihjHMsPjBUZYCMFr6nvaArxqXPn4lCa+cHfSa2cP27g3Z3ziYTRrcbQNGLQmGF3F3cBdzzzX7AILx0IB9rbwn9kx2G1FW3Inic+ZLIsVvKR8Zwfj0l1fkqo8LWY1M3IX14OX3r9RKTIO+d9XzAI8qRPGPn/4NC2n6o4rN8XJ82TOIvuVA8zLKUHRFgBCetlDZlqR1gLKjS39xoE7Bt8UvA6BxuEDjU3tFsEijgA+615tmZkXKqiEENrh41iLDDZNq4pKTWR3LZfnos81LOuNa15cD956vLMsJd1rqYp51gDUQqMYm2XsxnUhD2jg1DM7SeuJxxgrmpfISSXVIJIS5qJJSvJPEQ49DQTVIbYWJ9QWa/E2+c/oPK1drmC7WSfJRNKBO5Yjvcp7Gc3dmmI/Xh1kDTEuiSnWqQf37h+fTMhGnDf6dsS8SQfQWlqqwXXGlc/PEZ/SC5mtzIV0nAshlQdM/LvUtYutrEZ/Y+EAFtq1k28zQhOwLr1AIeANzhF8t9qzTdZf2qRKO6MWE9ohBYwibbOmrFtNmg3mcS+tB28xv2uKd/agYCvOP+GkSc+0lr7RXzyufL7QbkUpjLjEWFLqOIkAGu2B0tNlO9Eau2W1qcOUvVRgKzypKIQZ5KI3q0MLzqTNRYqiZOqmtqloIRlmkBHVpHmRYV6/HixbO6UC47KOFJnoMrVyr7wYz+SlW6GUaghYbY1I6kkxA2W1fSJokUdSh2LQ1GAimRGm0MT+uu57H5l7QgOWxERpO9moLRPgTtquWCfFlGlIjQaRly9odmzMOWY+IBO5tB4sW/0+VWGUh32qYk79EidWKrjWuiLpiVNGFWFRJVktyeXWmbgBBzVl8anPuXyNJlBJOlKLTgAbi/EYHVHxWiDaVR06GnHQNpJcWcK2jJtiCfG2sEHLzuI66sGrMK47nPIInPnu799935aOK2cvmvubrE38ZzZjrELCmXM2hM7UcpXD2oC3+ECVp7xtIuxptJ0jUr3sBmBS47TVxlvJ1Sqb/E0uLdvLj0lLr29ypdd/eMX3f6lrxGlKwKQxEGvw0qHbkbwrF3uHKwVENbIV2wZ13kNEF6zD+x24aLNMfDTCbDPnEikZFyTNttxWBXDaBuM8KtI2rmaMdUY7cXcUPstqTGvBGSrFWIpNMfbdea990bvAOC1YX0qbc6smDS1mPxSJoW4fwEXvjMmhlijDRq6qale6aJEuFGoppYDoBELQzLBuh/mZNx7jkinv0EtnUp50lO9hbNK57lZaMAWuWR5Yo9/kYwcYI0t4gWM47Umnl3YmpeBPqSyNp3K7s2DSAS/39KRuEN2bS4xvowV3dFRMx/VFcp2Yp8w2nTO9hCXtHG1kF1L4KlrJr2wKfyq77R7MKpFKzWlY9UkhYxyHWW6nBWPaudvEAl3CGcNpSXPZ6R9BbBtIl6cHL3gIBi+42CYXqCx1gfGWe7Ap0h3luyXdt1MKy4YUT9xSF01G16YEdWsouW9mgDHd3veyA97H+Ya47ZmEbqMY72oPztCGvK0onL44AvgC49saZKkWRz4veWljE1FHjbRJaWv6ZKKtl875h4CziFCZhG5rx7tefsl0aRT1bMHZjm8dwL/6u7wCRysaQblQoG5yAQN5zpatMNY/+yf8z+GLcH/Qn0iX2W2oEfXP4GvwQHuIL9AYGnaO3zqAX6946nkgqZNnUhx43DIdQtMFeOPrgy/y3Yd85HlJWwjLFkU3kFwq28xPnuPhMWeS+tDLV9Otllq7pQCf3uXJDN9wFDiUTgefHaiYbdfi3b3u8+iY6TnzhgehI1LTe8lcd7s1wJSzKbahCRxKKztTLXstGAiu3a6rPuQs5pk9TWAan5f0BZmGf7Ylxzzk/A7PAs4QPPPAHeFQ2hbFHszlgZuKZsJcUmbDC40sEU403cEjczstOEypa+YxevL4QBC8oRYqWdK6b7sK25tfE+oDZgtOQ2Jg8T41HGcBE6fTWHn4JtHcu9S7uYgU5KSCkl/mcnq+5/YBXOEr6lCUCwOTOM1taOI8mSxx1NsCXBEmLKbMAg5MkwbLmpBaFOPrNSlO2HnLiEqW3tHEwd8AeiQLmn+2gxjC3k6AxREqvKcJbTEzlpLiw4rNZK6oJdidbMMGX9FULKr0AkW+2qDEPBNNm5QAt2Ik2nftNWHetubosHLo2nG4vQA7GkcVCgVCgaDixHqo9UUn1A6OshapaNR/LPRYFV8siT1cCtJE0k/3WtaNSuUZYKPnsVIW0xXWnMUxq5+En4Kvw/MqQmVXnAXj9Z+9zM98zM/Agy7F/qqj2Nh67b8HjFnPP3iBn/tkpdzwEJX/whIcQUXOaikeliCRGUk7tiwF0rItwMEhjkZ309hikFoRAmLTpEXWuHS6y+am/KB/fM50aLEhGnSMwkpxzOov4H0AvgovwJ1iGzDLtJn/9BU+fAINfwUe6FHSLhu83viV/+/HrOePX+STT2B9uWGbrMHHLldRBlhS/CJQmcRxJFqZica01XixAZsYiH1uolZxLrR/SgxVIJjkpQP4PE9sE59LKLr7kltSBogS5tyszzH8Fvw8/AS8rNOg0xUS9fIaHwb+6et8Q/gyvKRjf5OusOzGx8evA/BP4IP11uN/grca5O0lcsPLJ5YjwI4QkJBOHa0WdMZYGxPbh2W2nR9v3WxEWqgp/G3+6VZbRLSAAZ3BhdhAaUL33VUSw9yjEsvbaQ9u4A/gGXwZXoEHOuU1GSj2chf+Mo+f8IcfcAxfIKVmyunRbYQVnoevwgfw3TXXcw++xNuP4fhyueEUNttEduRVaDttddoP0eSxLe2LENk6itYxlrxBNBYrNNKSQmeaLcm9c8UsaB5WyO6675yyQIAWSDpBVoA/gxmcwEvwoDv0m58UE7gHn+fJOa8/Ywan8EKRfjsopF83eCglX/Sfr7OeaRoQfvt1CGvIDccH5BCvw1sWIzRGC/66t0VTcLZQZtm6PlAasbOJ9iwWtUo7biktTSIPxnR24jxP1ZKaqq+2RcXM9OrBAm/AAs7hDJ5bNmGb+KIfwCs8a3jnjBrOFeMjHSCdbKr+2uOLfnOd9eiA8Hvvwwq54VbP2OqwkB48Ytc4YEOiH2vTXqodabfWEOzso4qxdbqD5L6tbtNPECqbhnA708DZH4QOJUXqScmUlks7Ot6FBuZw3n2mEbaUX7kDzxHOOQk8nKWMzAzu6ZZ8sOFw4RK+6PcuXo9tB4SbMz58ApfKDXf3szjNIIbGpD5TKTRxGkEMLjLl+K3wlWXBsCUxIDU+jbOiysESqAy1MGUJpXgwbTWzNOVEziIXZrJ+VIztl1PUBxTSo0dwn2bOmfDRPD3TRTGlfbCJvO9KvuhL1hMHhB9wPuPRLGHcdOWG2xc0U+5bQtAJT0nRTewXL1pgk2+rZAdeWmz3jxAqfNQQdzTlbF8uJ5ecEIWvTkevAHpwz7w78QujlD/Lr491bD8/1vhM2yrUQRrWXNQY4fGilfctMWYjL72UL/qS9eiA8EmN88nbNdour+PBbbAjOjIa4iBhfFg6rxeKdEGcL6p3EWR1Qq2Qkhs2DrnkRnmN9tG2EAqmgPw6hoL7Oza7B+3SCrR9tRftko+Lsf2F/mkTndN2LmzuMcKTuj/mX2+4Va3ki16+nnJY+S7MefpkidxwnV+4wkXH8TKnX0tsYzYp29DOOoSW1nf7nTh2akYiWmcJOuTidSaqESrTYpwjJJNVGQr+rLI7WsqerHW6Kp/oM2pKuV7T1QY9gjqlZp41/WfKpl56FV/0kvXQFRyeQ83xaTu5E8p5dNP3dUF34ihyI3GSpeCsywSh22ZJdWto9winhqifb7VRvgktxp13vyjrS0EjvrRfZ62uyqddSWaWYlwTPAtJZ2oZ3j/Sgi/mi+6vpzesfAcWNA0n8xVyw90GVFGuZjTXEQy+6GfLGLMLL523f5E0OmxVjDoOuRiH91RKU+vtoCtH7TgmvBLvtFXWLW15H9GTdVw8ow4IlRLeHECN9ym1e9K0I+Cbnhgv4Yu+aD2HaQJ80XDqOzSGAV4+4yCqBxrsJAX6ZTIoX36QnvzhhzzMfFW2dZVLOJfo0zbce5OvwXMFaZ81mOnlTVXpDZsQNuoYWveketKb5+6JOOsgX+NTm7H49fUTlx+WLuWL7qxnOFh4BxpmJx0p2gDzA/BUARuS6phR+pUsY7MMboAHx5xNsSVfVZcYSwqCKrqon7zM+8ecCkeS4nm3rINuaWvVNnMRI1IRpxTqx8PZUZ0Br/UEduo3B3hNvmgZfs9gQPj8vIOxd2kndir3awvJ6BLvoUuOfFWNYB0LR1OQJoUySKb9IlOBx74q1+ADC2G6rOdmFdJcD8BkfualA+BdjOOzP9uUhGUEX/TwhZsUduwRr8wNuXKurCixLBgpQI0mDbJr9dIqUuV+92ngkJZ7xduCk2yZKbfWrH1VBiTg9VdzsgRjW3CVXCvAwDd+c1z9dWw9+B+8MJL/eY15ZQ/HqvTwVdsZn5WQsgRRnMaWaecu3jFvMBEmgg+FJFZsnSl0zjB9OqPYaBD7qmoVyImFvzi41usesV0julaAR9dfR15Xzv9sEruRDyk1nb+QaLU67T885GTls6YgcY+UiMa25M/pwGrbCfzkvR3e0jjtuaFtnwuagHTSb5y7boBH119HXhvwP487jJLsLJ4XnUkHX5sLbS61dpiAXRoZSCrFJ+EjpeU3puVfitngYNo6PJrAigKktmwjyQdZpfq30mmtulaAx9Zfx15Xzv+cyeuiBFUs9zq8Kq+XB9a4PVvph3GV4E3y8HENJrN55H1X2p8VyqSKwVusJDKzXOZzplWdzBUFK9e+B4+uv468xvI/b5xtSAkBHQaPvtqWzllVvEOxPbuiE6+j2pvjcKsbvI7txnRErgfH7LdXqjq0IokKzga14GzQ23SSbCQvO6r+Or7SMIr/efOkkqSdMnj9mBx2DRsiY29Uj6+qK9ZrssCKaptR6HKURdwUYeUWA2kPzVKQO8ku2nU3Anhs/XWkBx3F/7wJtCTTTIKftthue1ty9xvNYLY/zo5KSbIuKbXpbEdSyeRyYdAIwKY2neyoc3+k1XUaufYga3T9daMUx/r8z1s10ITknIO0kuoMt+TB8jK0lpayqqjsJ2qtXAYwBU932zinimgmd6mTRDnQfr88q36NAI+tv24E8Pr8zxtasBqx0+xHH9HhlrwsxxNUfKOHQaZBITNf0uccj8GXiVmXAuPEAKSdN/4GLHhs/XWj92dN/uetNuBMnVR+XWDc25JLjo5Mg5IZIq226tmCsip2zZliL213YrTlL2hcFjpCduyim3M7/eB16q/blQsv5X/esDRbtJeabLIosWy3ycavwLhtxdWzbMmHiBTiVjJo6lCLjXZsi7p9PEPnsq6X6wd4bP11i0rD5fzPm/0A6brrIsllenZs0lCJlU4abakR59enZKrKe3BZihbTxlyZ2zl1+g0wvgmA166/bhwDrcn/7Ddz0eWZuJvfSESug6NzZsox3Z04FIxz0mUjMwVOOVTq1CQ0AhdbBGVdjG/CgsfUX7esJl3K/7ytWHRv683praW/8iDOCqWLLhpljDY1ZpzK75QiaZoOTpLKl60auHS/97oBXrv+umU9+FL+5+NtLFgjqVLCdbmj7pY5zPCPLOHNCwXGOcLquOhi8CmCWvbcuO73XmMUPab+ug3A6/A/78Bwe0bcS2+tgHn4J5pyS2WbOck0F51Vq3LcjhLvZ67p1ABbaL2H67bg78BfjKi/jr3+T/ABV3ilLmNXTI2SpvxWBtt6/Z//D0z/FXaGbSBgylzlsEGp+5//xrd4/ae4d8DUUjlslfIYS3t06HZpvfQtvv0N7AHWqtjP2pW08QD/FLy//da38vo8PNlKHf5y37Dxdfe/oj4kVIgFq3koLReSR76W/bx//n9k8jonZxzWTANVwEniDsg87sOSd/z7//PvMp3jQiptGVWFX2caezzAXwfgtzYUvbr0iozs32c3Uge7varH+CNE6cvEYmzbPZ9hMaYDdjK4V2iecf6EcEbdUDVUARda2KzO/JtCuDbNQB/iTeL0EG1JSO1jbXS+nLxtPMDPw1fh5+EPrgSEKE/8Gry5A73ui87AmxwdatyMEBCPNOCSKUeRZ2P6Myb5MRvgCHmA9ywsMifU+AYXcB6Xa5GibUC5TSyerxyh0j6QgLVpdyhfArRTTLqQjwe4HOD9s92D4Ap54odXAPBWLAwB02igG5Kkc+piN4lvODIFGAZgT+EO4Si1s7fjSR7vcQETUkRm9O+MXyo9OYhfe4xt9STQ2pcZRLayCV90b4D3jR0DYAfyxJ+eywg2IL7NTMXna7S/RpQ63JhWEM8U41ZyQGjwsVS0QBrEKLu8xwZsbi4wLcCT+OGidPIOCe1PiSc9Qt+go+vYqB7cG+B9d8cAD+WJPz0Am2gxXgU9IneOqDpAAXOsOltVuMzpdakJXrdPCzXiNVUpCeOos5cxnpQT39G+XVLhs1osQVvJKPZyNq8HDwd4d7pNDuWJPxVX7MSzqUDU6gfadKiNlUFTzLeFHHDlzO4kpa7aiKhBPGKwOqxsBAmYkOIpipyXcQSPlRTf+Tii0U3EJGaZsDER2qoB3h2hu0qe+NNwUooYU8y5mILbJe6OuX+2FTKy7bieTDAemaQyQ0CPthljSWO+xmFDIYiESjM5xKd6Ik5lvLq5GrQ3aCMLvmCA9wowLuWJb9xF59hVVP6O0CrBi3ZjZSNOvRy+I6klNVRJYRBaEzdN+imiUXQ8iVF8fsp+W4JXw7WISW7fDh7lptWkCwZ4d7QTXyBPfJMYK7SijjFppGnlIVJBJBYj7eUwtiP1IBXGI1XCsjNpbjENVpSAJ2hq2LTywEly3hUYazt31J8w2+aiLx3g3fohXixPfOMYm6zCGs9LVo9MoW3MCJE7R5u/WsOIjrqBoHUO0bJE9vxBpbhsd3+Nb4/vtPCZ4oZYCitNeYuC/8UDvDvy0qvkiW/cgqNqRyzqSZa/s0mqNGjtKOoTm14zZpUauiQgVfqtQiZjq7Q27JNaSK5ExRcrGCXO1FJYh6jR6CFqK7bZdQZ4t8g0rSlPfP1RdBtqaa9diqtzJkQ9duSryi2brQXbxDwbRUpFMBHjRj8+Nt7GDKgvph9okW7LX47gu0SpGnnFQ1S1lYldOsC7hYteR574ZuKs7Ei1lBsfdz7IZoxzzCVmmVqaSySzQbBVAWDek+N4jh9E/4VqZrJjPwiv9BC1XcvOWgO8275CVyBPvAtTVlDJfZkaZGU7NpqBogAj/xEHkeAuJihWYCxGN6e8+9JtSegFXF1TrhhLGP1fak3pebgPz192/8gB4d/6WT7+GdYnpH7hH/DJzzFiYPn/vjW0SgNpTNuPIZoAEZv8tlGw4+RLxy+ZjnKa5NdFoC7UaW0aduoYse6+bXg1DLg6UfRYwmhGEjqPvF75U558SANrElK/+MdpXvmqBpaXOa/MTZaa1DOcSiLaw9j0NNNst3c+63c7EKTpkvKHzu6bPbP0RkuHAVcbRY8ijP46MIbQeeT1mhA+5PV/inyDdQipf8LTvMXbwvoDy7IruDNVZKTfV4CTSRUYdybUCnGU7KUTDxLgCknqUm5aAW6/1p6eMsOYsphLzsHrE0Y/P5bQedx1F/4yPHnMB3/IOoTU9+BL8PhtjuFKBpZXnYNJxTuv+2XqolKR2UQgHhS5novuxVySJhBNRF3SoKK1XZbbXjVwWNyOjlqWJjrWJIy+P5bQedyldNScP+HZ61xKSK3jyrz+NiHG1hcOLL/+P+PDF2gOkekKGiNWKgJ+8Z/x8Iv4DdQHzcpZyF4v19I27w9/yPGDFQvmEpKtqv/TLiWMfn4sofMm9eAH8Ao0zzh7h4sJqYtxZd5/D7hkYPneDzl5idlzNHcIB0jVlQ+8ULzw/nc5/ojzl2juE0apD7LRnJxe04dMz2iOCFNtGFpTuXA5AhcTRo8mdN4kz30nVjEC4YTZQy4gpC7GlTlrePKhGsKKgeXpCYeO0MAd/GH7yKQUlXPLOasOH3FnSphjHuDvEu4gB8g66oNbtr6eMbFIA4fIBJkgayoXriw2XEDQPJrQeROAlY6aeYOcMf+IVYTU3XFlZufMHinGywaW3YLpObVBAsbjF4QJMsVUSayjk4voPsHJOQfPWDhCgDnmDl6XIRerD24HsGtw86RMHOLvVSHrKBdeVE26gKB5NKHzaIwLOmrqBWJYZDLhASG16c0Tn+CdRhWDgWXnqRZUTnPIHuMJTfLVpkoYy5CzylHVTGZMTwkGAo2HBlkQplrJX6U+uF1wZz2uwS1SQ12IqWaPuO4baZaEFBdukksJmkcTOm+YJSvoqPFzxFA/YUhIvWxcmSdPWTWwbAKVp6rxTtPFUZfKIwpzm4IoMfaYQLWgmlG5FME2gdBgm+J7J+rtS/XBbaVLsR7bpPQnpMFlo2doWaVceHk9+MkyguZNCJ1He+kuHTWyQAzNM5YSUg/GlTk9ZunAsg1qELVOhUSAK0LABIJHLKbqaEbHZLL1VA3VgqoiOKXYiS+HRyaEKgsfIqX64HYWbLRXy/qWoylIV9gudL1OWBNgBgTNmxA6b4txDT4gi3Ri7xFSLxtXpmmYnzAcWDZgY8d503LFogz5sbonDgkKcxGsWsE1OI+rcQtlgBBCSOKD1mtqYpIU8cTvBmAT0yZe+zUzeY92fYjTtGipXLhuR0ePoHk0ofNWBX+lo8Z7pAZDk8mEw5L7dVyZZoE/pTewbI6SNbiAL5xeygW4xPRuLCGbhcO4RIeTMFYHEJkYyEO9HmJfXMDEj/LaH781wHHZEtqSQ/69UnGpzH7LKIAZEDSPJnTesJTUa+rwTepI9dLJEawYV+ZkRn9g+QirD8vF8Mq0jFQ29js6kCS3E1+jZIhgPNanHdHFqFvPJLHqFwQqbIA4jhDxcNsOCCQLDomaL/dr5lyJaJU6FxPFjO3JOh3kVMcROo8u+C+jo05GjMF3P3/FuDLn5x2M04xXULPwaS6hBYki+MrMdZJSgPHlcB7nCR5bJ9Kr5ACUn9jk5kivdd8tk95SOGrtqu9lr2IhK65ZtEl7ZKrp7DrqwZfRUSN1el7+7NJxZbywOC8neNKTch5vsTEMNsoCCqHBCqIPRjIPkm0BjvFODGtto99rCl+d3wmHkW0FPdpZtC7MMcVtGFQjJLX5bdQ2+x9ypdc313uj8xlsrfuLgWXz1cRhZvJYX0iNVBRcVcmCXZs6aEf3RQF2WI/TcCbKmGU3IOoDJGDdDub0+hYckt6PlGu2BcxmhbTdj/klhccLGJMcqRjMJP1jW2ETqLSWJ/29MAoORluJ+6LPffBZbi5gqi5h6catQpmOT7/OFf5UorRpLzCqcMltBLhwd1are3kztrSzXO0LUbXRQcdLh/RdSZ+swRm819REDrtqzC4es6Gw4JCKlSnjYVpo0xeq33PrADbFLL3RuCmObVmPN+24kfa+AojDuM4umKe2QwCf6EN906HwjujaitDs5o0s1y+k3lgbT2W2i7FJdnwbLXhJUBq/9liTctSmFC/0OqUinb0QddTWamtjbHRFuWJJ6NpqZ8vO3fZJ37Db+2GkaPYLGHs7XTTdiFQJ68SkVJFVmY6McR5UycflNCsccHFaV9FNbR4NttLxw4pQ7wJd066Z0ohVbzihaxHVExd/ay04oxUKWt+AsdiQ9OUyZ2krzN19IZIwafSTFgIBnMV73ADj7V/K8u1MaY2sJp2HWm0f41tqwajEvdHWOJs510MaAqN4aoSiPCXtN2KSi46dUxHdaMquar82O1x5jqhDGvqmoE9LfxcY3zqA7/x3HA67r9ZG4O6Cuxu12/+TP+eLP+I+HErqDDCDVmBDO4larujNe7x8om2rMug0MX0rL1+IWwdwfR+p1TNTyNmVJ85ljWzbWuGv8/C7HD/izjkHNZNYlhZcUOKVzKFUxsxxN/kax+8zPWPSFKw80rJr9Tizyj3o1gEsdwgWGoxPezDdZ1TSENE1dLdNvuKL+I84nxKesZgxXVA1VA1OcL49dFlpFV5yJMhzyCmNQ+a4BqusPJ2bB+xo8V9u3x48VVIEPS/mc3DvAbXyoYr6VgDfh5do5hhHOCXMqBZUPhWYbWZECwVJljLgMUWOCB4MUuMaxGNUQDVI50TQ+S3kFgIcu2qKkNSHVoM0SHsgoZxP2d5HH8B9woOk4x5bPkKtAHucZsdykjxuIpbUrSILgrT8G7G5oCW+K0990o7E3T6AdW4TilH5kDjds+H64kS0mz24grtwlzDHBJqI8YJQExotPvoC4JBq0lEjjQkyBZ8oH2LnRsQ4Hu1QsgDTJbO8fQDnllitkxuVskoiKbRF9VwzMDvxHAdwB7mD9yCplhHFEyUWHx3WtwCbSMMTCUCcEmSGlg4gTXkHpZXWQ7kpznK3EmCHiXInqndkQjunG5kxTKEeGye7jWz9cyMR2mGiFQ15ENRBTbCp+Gh86vAyASdgmJq2MC6hoADQ3GosP0QHbnMHjyBQvQqfhy/BUbeHd5WY/G/9LK/8Ka8Jd7UFeNWEZvzPb458Dn8DGLOe3/wGL/4xP+HXlRt+M1PE2iLhR8t+lfgxsuh7AfO2AOf+owWhSZRYQbd622hbpKWKuU+XuvNzP0OseRDa+mObgDHJUSc/pKx31QdKffQ5OIJpt8GWjlgTwMc/w5MPCR/yl1XC2a2Yut54SvOtMev55Of45BOat9aWG27p2ZVORRvnEk1hqWMVUmqa7S2YtvlIpspuF1pt0syuZS2NV14mUidCSfzQzg+KqvIYCMljIx2YK2AO34fX4GWdu5xcIAb8MzTw+j/lyWM+Dw/gjs4GD6ehNgA48kX/AI7XXM/XAN4WHr+9ntywqoCakCqmKP0rmQrJJEErG2Upg1JObr01lKQy4jskWalKYfJ/EDLMpjNSHFEUAde2fltaDgmrNaWQ9+AAb8I5vKjz3L1n1LriB/BXkG/wwR9y/oRX4LlioHA4LzP2inzRx/DWmutRweFjeP3tNeSGlaE1Fde0OS11yOpmbIp2u/jF1n2RRZviJM0yBT3IZl2HWImKjQOxIyeU325b/qWyU9Moj1o07tS0G7qJDoGHg5m8yeCxMoEH8GU45tnrNM84D2l297DQ9t1YP7jki/7RmutRweEA77/HWXOh3HCxkRgldDQkAjNTMl2Iloc1qN5JfJeeTlyTRzxURTdn1Ixv2uKjs12AbdEWlBtmVdk2k7FFwj07PCZ9XAwW3dG+8xKzNFr4EnwBZpy9Qzhh3jDXebBpYcpuo4fQ44u+fD1dweEnHzI7v0xuuOALRUV8rXpFyfSTQYkhd7IHm07jpyhlkCmI0ALYqPTpUxXS+z4jgDj1Pflvmz5ecuItpIBxyTHpSTGWd9g1ApfD/bvwUhL4nT1EzqgX7cxfCcNmb3mPL/qi9SwTHJ49oj5ZLjccbTG3pRmlYi6JCG0mQrAt1+i2UXTZ2dv9IlQpN5naMYtviaXlTrFpoMsl3bOAFEa8sqPj2WCMrx3Yjx99qFwO59Aw/wgx+HlqNz8oZvA3exRDvuhL1jMQHPaOJ0+XyA3fp1OfM3qObEVdhxjvynxNMXQV4+GJyvOEFqeQBaIbbO7i63rpxCltdZShPFxkjM2FPVkn3TG+Rp9pO3l2RzFegGfxGDHIAh8SteR0C4HopXzRF61nheDw6TFN05Ebvq8M3VKKpGjjO6r7nhudTEGMtYM92HTDaR1FDMXJ1eThsbKfywyoWwrzRSXkc51flG3vIid62h29bIcFbTGhfV+faaB+ohj7dPN0C2e2lC96+XouFByen9AsunLDJZ9z7NExiUc0OuoYW6UZkIyx2YUR2z6/TiRjyKMx5GbbjLHvHuf7YmtKghf34LJfx63Yg8vrvN2zC7lY0x0tvKezo4HmGYDU+Gab6dFL+KI761lDcNifcjLrrr9LWZJctG1FfU1uwhoQE22ObjdfkSzY63CbU5hzs21WeTddH2BaL11Gi7lVdlxP1nkxqhnKhVY6knS3EPgVGg1JpN5cP/hivujOelhXcPj8HC/LyI6MkteVjlolBdMmF3a3DbsuAYhL44dxzthWSN065xxUd55Lmf0wRbOYOqH09/o9WbO2VtFdaMb4qBgtFJoT1SqoN8wPXMoXLb3p1PUEhxfnnLzGzBI0Ku7FxrKsNJj/8bn/H8fPIVOd3rfrklUB/DOeO+nkghgSPzrlPxluCMtOnDL4Yml6dK1r3vsgMxgtPOrMFUZbEUbTdIzii5beq72G4PD0DKnwjmBULUVFmy8t+k7fZ3pKc0Q4UC6jpVRqS9Umv8bxw35flZVOU1X7qkjnhZlsMbk24qQ6Hz7QcuL6sDC0iHHki96Uh2UdvmgZnjIvExy2TeJdMDZNSbdZyAHe/Yd1xsQhHiKzjh7GxQ4yqMPaywPkjMamvqrYpmO7Knad+ZQC5msCuAPWUoxrxVhrGv7a+KLXFhyONdTMrZ7ke23qiO40ZJUyzgYyX5XyL0mV7NiUzEs9mjtbMN0dERqwyAJpigad0B3/zRV7s4PIfXSu6YV/MK7+OrYe/JvfGMn/PHJe2fyUdtnFrKRNpXV0Y2559aWPt/G4BlvjTMtXlVIWCnNyA3YQBDmYIodFz41PvXPSa6rq9lWZawZ4dP115HXV/M/tnFkkrBOdzg6aP4pID+MZnTJ1SuuB6iZlyiox4HT2y3YBtkUKWooacBQUDTpjwaDt5poBHl1/HXltwP887lKKXxNUEyPqpGTyA699UqY/lt9yGdlUKra0fFWS+36iylVWrAyd7Uw0CZM0z7xKTOduznLIjG2Hx8cDPLb+OvK6Bv7n1DYci4CxUuRxrjBc0bb4vD3rN5Zz36ntLb83eVJIB8LiIzCmn6SMPjlX+yNlTjvIGjs+QzHPf60Aj62/jrzG8j9vYMFtm1VoRWCJdmw7z9N0t+c8cxZpPeK4aTRicS25QhrVtUp7U578chk4q04Wx4YoQSjFryUlpcQ1AbxZ/XVMknIU//OGl7Q6z9Zpxi0+3yFhSkjUDpnCIUhLWVX23KQ+L9vKvFKI0ZWFQgkDLvBoylrHNVmaw10zwCPrr5tlodfnf94EWnQ0lFRWy8pW9LbkLsyUVDc2NSTHGDtnD1uMtchjbCeb1mpxFP0YbcClhzdLu6lfO8Bj6q+bdT2sz/+8SZCV7VIxtt0DUn9L7r4cLYWDSXnseEpOGFuty0qbOVlS7NNzs5FOGJUqQpl2Q64/yBpZf90sxbE+//PGdZ02HSipCbmD6NItmQ4Lk5XUrGpDMkhbMm2ZVheNYV+VbUWTcv99+2NyX1VoafSuC+AN6q9bFIMv5X/eagNWXZxEa9JjlMwNWb00akGUkSoepp1/yRuuqHGbUn3UdBSTxBU6SEVklzWRUkPndVvw2PrrpjvxOvzPmwHc0hpmq82npi7GRro8dXp0KXnUQmhZbRL7NEVp1uuZmO45vuzKsHrktS3GLWXODVjw+vXXLYx4Hf7njRPd0i3aoAGX6W29GnaV5YdyDj9TFkakje7GHYzDoObfddHtOSpoi2SmzJHrB3hM/XUDDEbxP2/oosszcRlehWXUvzHv4TpBVktHqwenFo8uLVmy4DKLa5d3RtLrmrM3aMFr1183E4sewf+85VWeg1c5ag276NZrM9IJVNcmLEvDNaV62aq+14IAOGFsBt973Ra8Xv11YzXwNfmft7Jg2oS+XOyoC8/cwzi66Dhmgk38kUmP1CUiYWOX1bpD2zWXt2FCp7uq8703APAa9dfNdscR/M/bZLIyouVxqJfeWvG9Je+JVckHQ9+CI9NWxz+blX/KYYvO5n2tAP/vrlZ7+8/h9y+9qeB/Hnt967e5mevX10rALDWK//FaAT5MXdBXdP0C/BAes792c40H+AiAp1e1oH8HgH94g/Lttx1gp63op1eyoM/Bvw5/G/7xFbqJPcCXnmBiwDPb/YKO4FX4OjyCb289db2/Noqicw4i7N6TVtoz8tNwDH+8x/i6Ae7lmaQVENzJFb3Di/BFeAwz+Is9SjeQySpPqbLFlNmyz47z5a/AF+AYFvDmHqibSXTEzoT4Gc3OALaqAP4KPFUJ6n+1x+rGAM6Zd78bgJ0a8QN4GU614vxwD9e1Amy6CcskNrczLx1JIp6HE5UZD/DBHrFr2oNlgG4Odv226BodoryjGJ9q2T/AR3vQrsOCS0ctXZi3ruLlhpFDJYl4HmYtjQCP9rhdn4suySLKDt6wLcC52h8xPlcjju1fn+yhuw4LZsAGUuo2b4Fx2UwQu77uqRHXGtg92aN3tQCbFexc0uk93vhTXbct6y7MulLycoUljx8ngDMBg1tvJjAazpEmOtxlzclvj1vQf1Tx7QlPDpGpqgtdSKz/d9/hdy1vTfFHSmC9dGDZbLiezz7Ac801HirGZsWjydfZyPvHXL/Y8Mjzg8BxTZiuwKz4Eb8sBE9zznszmjvFwHKPIWUnwhqfVRcd4Ck0K6ate48m1oOfrX3/yOtvAsJ8zsPAM89sjnddmuLuDPjX9Bu/L7x7xpMzFk6nWtyQfPg278Gn4Aekz2ZgOmU9eJ37R14vwE/BL8G3aibCiWMWWDQ0ZtkPMnlcGeAu/Ag+8ZyecU5BPuy2ILD+sQqyZhAKmn7XZd+jIMTN9eBL7x95xVLSX4On8EcNlXDqmBlqS13jG4LpmGbkF/0CnOi3H8ETOIXzmnmtb0a16Tzxj1sUvQCBiXZGDtmB3KAefPH94xcUa/6vwRn80GOFyjEXFpba4A1e8KQfFF+259tx5XS4egYn8fQsLGrqGrHbztr+uByTahWuL1NUGbDpsnrwBfePPwHHIf9X4RnM4Z2ABWdxUBlqQ2PwhuDxoS0vvqB1JzS0P4h2nA/QgTrsJFn+Y3AOjs9JFC07CGWX1oNX3T/yHOzgDjwPn1PM3g9Jk9lZrMEpxnlPmBbjyo2+KFXRU52TJM/2ALcY57RUzjObbjqxVw++4P6RAOf58pcVsw9Daje3htriYrpDOonre3CudSe6bfkTEgHBHuDiyu5MCsc7BHhYDx7ePxLjqigXZsw+ijMHFhuwBmtoTPtOxOrTvYJDnC75dnUbhfwu/ZW9AgYd+peL68HD+0emKquiXHhWjJg/UrkJYzuiaL3E9aI/ytrCvAd4GcYZMCkSQxfUg3v3j8c4e90j5ZTPdvmJJGHnOCI2nHS8081X013pHuBlV1gB2MX1YNmWLHqqGN/TWmG0y6clJWthxNUl48q38Bi8vtMKyzzpFdSDhxZ5WBA5ZLt8Jv3895DduBlgbPYAj8C4B8hO68FDkoh5lydC4FiWvBOVqjYdqjiLv92t8yPDjrDaiHdUD15qkSURSGmXJwOMSxWAXYwr3zaAufJ66l+94vv3AO+vPcD7aw/w/toDvL/2AO+vPcD7aw/wHuD9tQd4f+0B3l97gPfXHuD9tQd4f+0B3l97gG8LwP8G/AL8O/A5OCq0Ys2KIdv/qOIXG/4mvFAMF16gZD+2Xvu/B8as5+8bfllWyg0zaNO5bfXj6vfhhwD86/Aq3NfRS9t9WPnhfnvCIw/CT8GLcFTMnpntdF/z9V+PWc/vWoIH+FL3Znv57PitcdGP4R/C34avw5fgRVUInCwbsn1yyA8C8zm/BH8NXoXnVE6wVPjdeCI38kX/3+Ct9dbz1pTmHFRu+Hm4O9Ch3clr99negxfwj+ER/DR8EV6B5+DuQOnTgUw5rnkY+FbNU3gNXh0o/JYTuWOvyBf9FvzX663HH/HejO8LwAl8Hl5YLTd8q7sqA3wbjuExfAFegQdwfyDoSkWY8swzEf6o4Qyewefg+cHNbqMQruSL/u/WWc+E5g7vnnEXgDmcDeSGb/F4cBcCgT+GGRzDU3hZYburAt9TEtHgbM6JoxJ+6NMzzTcf6c2bycv2+KK/f+l6LBzw5IwfqZJhA3M472pWT/ajKxnjv4AFnMEpnBTPND6s2J7qHbPAqcMK74T2mZ4VGB9uJA465It+/eL1WKhYOD7xHOkr1ajK7d0C4+ke4Hy9qXZwpgLr+Znm/uNFw8xQOSy8H9IzjUrd9+BIfenYaylf9FsXr8fBAadnPIEDna8IBcwlxnuA0/Wv6GAWPd7dDIKjMdSWueAsBj4M7TOd06qBbwDwKr7oleuxMOEcTuEZTHWvDYUO7aHqAe0Bbq+HEFRzOz7WVoTDQkVds7A4sIIxfCQdCefFRoIOF/NFL1mPab/nvOakSL/Q1aFtNpUb/nFOVX6gzyg/1nISyDfUhsokIzaBR9Kxm80s5mK+6P56il1jXic7nhQxsxSm3OwBHl4fFdLqi64nDQZvqE2at7cWAp/IVvrN6/BFL1mPhYrGMBfOi4PyjuSGf6wBBh7p/FZTghCNWGgMzlBbrNJoPJX2mW5mwZfyRffXo7OFi5pZcS4qZUrlViptrXtw+GQoyhDPS+ANjcGBNRiLCQDPZPMHuiZfdFpPSTcQwwKYdRNqpkjm7AFeeT0pJzALgo7g8YYGrMHS0iocy+YTm2vyRUvvpXCIpQ5pe666TJrcygnScUf/p0NDs/iAI/nqDHC8TmQT8x3NF91l76oDdQGwu61Z6E0ABv7uO1dbf/37Zlv+Zw/Pbh8f1s4Avur6657/+YYBvur6657/+YYBvur6657/+YYBvur6657/+aYBvuL6657/+VMA8FXWX/f8zzcN8BXXX/f8zzcNMFdbf93zP38KLPiK6697/uebtuArrr/u+Z9vGmCusP6653/+1FjwVdZf9/zPN7oHX339dc//fNMu+irrr3v+50+Bi+Zq6697/uebA/jz8Pudf9ht/fWv517J/XUzAP8C/BAeX9WCDrUpZ3/dEMBxgPcfbtTVvsYV5Yn32u03B3Ac4P3b8I+vxNBKeeL9dRMAlwO83959qGO78sT769oB7g3w/vGVYFzKE++v6wV4OMD7F7tckFkmT7y/rhHgpQO8b+4Y46XyxPvrugBeNcB7BRiX8sT767oAvmCA9woAHsoT76+rBJjLBnh3txOvkifeX1dswZcO8G6N7sXyxPvr6i340gHe3TnqVfLE++uKAb50gHcXLnrX8sR7gNdPRqwzwLu7Y/FO5Yn3AK9jXCMGeHdgxDuVJ75VAI8ljP7PAb3/RfjcZfePHBB+79dpfpH1CanN30d+mT1h9GqAxxJGM5LQeeQ1+Tb+EQJrElLb38VHQ94TRq900aMIo8cSOo+8Dp8QfsB8zpqE1NO3OI9Zrj1h9EV78PqE0WMJnUdeU6E+Jjyk/hbrEFIfeWbvId8H9oTRFwdZaxJGvziW0Hn0gqYB/wyZ0PwRlxJST+BOw9m77Amj14ii1yGM/txYQudN0qDzGe4EqfA/5GJCagsHcPaEPWH0esekSwmjRxM6b5JEcZ4ww50ilvAOFxBSx4yLW+A/YU8YvfY5+ALC6NGEzhtmyZoFZoarwBLeZxUhtY4rc3bKnjB6TKJjFUHzJoTOozF2YBpsjcyxDgzhQ1YRUse8+J4wenwmaylB82hC5w0zoRXUNXaRBmSMQUqiWSWkLsaVqc/ZE0aPTFUuJWgeTei8SfLZQeMxNaZSIzbII4aE1Nmr13P2hNHjc9E9guYNCZ032YlNwESMLcZiLQHkE4aE1BFg0yAR4z1h9AiAGRA0jyZ03tyIxWMajMPWBIsxYJCnlITU5ShiHYdZ94TR4wCmSxg9jtB5KyPGYzymAYexWEMwAPIsAdYdV6aObmNPGD0aYLoEzaMJnTc0Ygs+YDw0GAtqxBjkuP38bMRWCHn73xNGjz75P73WenCEJnhwyVe3AEe8TtKdJcYhBl97wuhNAObK66lvD/9J9NS75v17wuitAN5fe4D31x7g/bUHeH/tAd5fe4D3AO+vPcD7aw/w/toDvL/2AO+vPcD7aw/w/toDvAd4f/24ABzZ8o+KLsSLS+Pv/TqTb3P4hKlQrTGh+fbIBT0Axqznnb+L/V2mb3HkN5Mb/nEHeK7d4IcDld6lmDW/iH9E+AH1MdOw/Jlu2T1xNmY98sv4wHnD7D3uNHu54WUuOsBTbQuvBsPT/UfzNxGYzwkP8c+Yz3C+r/i6DcyRL/rZ+utRwWH5PmfvcvYEt9jLDS/bg0/B64DWKrQM8AL8FPwS9beQCe6EMKNZYJol37jBMy35otdaz0Bw2H/C2Smc7+WGB0HWDELBmOByA3r5QONo4V+DpzR/hFS4U8wMW1PXNB4TOqYz9urxRV++ntWCw/U59Ty9ebdWbrgfRS9AYKKN63ZokZVygr8GZ/gfIhZXIXPsAlNjPOLBby5c1eOLvmQ9lwkOy5x6QV1j5TYqpS05JtUgUHUp5toHGsVfn4NX4RnMCe+AxTpwmApTYxqMxwfCeJGjpXzRF61nbcHhUBPqWze9svwcHJ+S6NPscKrEjug78Dx8Lj3T8D4YxGIdxmJcwhi34fzZUr7olevZCw5vkOhoClq5zBPZAnygD/Tl9EzDh6kl3VhsHYcDEb+hCtJSvuiV69kLDm+WycrOTArHmB5/VYyP6jOVjwgGawk2zQOaTcc1L+aLXrKeveDwZqlKrw8U9Y1p66uK8dEzdYwBeUQAY7DbyYNezBfdWQ97weEtAKYQg2xJIkuveAT3dYeLGH+ShrWNwZgN0b2YL7qznr3g8JYAo5bQBziPjx7BPZ0d9RCQp4UZbnFdzBddor4XHN4KYMrB2qHFRIzzcLAHQZ5the5ovui94PCWAPefaYnxIdzRwdHCbuR4B+tbiy96Lzi8E4D7z7S0mEPd+eqO3cT53Z0Y8SV80XvB4Z0ADJi/f7X113f+7p7/+UYBvur6657/+YYBvur6657/+aYBvuL6657/+aYBvuL6657/+aYBvuL6657/+aYBvuL6657/+VMA8FXWX/f8z58OgK+y/rrnf75RgLna+uue//lTA/CV1V/3/M837aKvvv6653++UQvmauuve/7nTwfAV1N/3fM/fzr24Cuuv+75nz8FFnxl9dc9//MOr/8/glixwRuUfM4AAAAASUVORK5CYII='; } - getSearchTexture() { + /** + * Returns the search texture as a Base64 string.. + * + * @private + * @return {String} The search texture. + */ + _getSearchTexture() { return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAAAhCAAAAABIXyLAAAAAOElEQVRIx2NgGAWjYBSMglEwEICREYRgFBZBqDCSLA2MGPUIVQETE9iNUAqLR5gIeoQKRgwXjwAAGn4AtaFeYLEAAAAASUVORK5CYII='; diff --git a/examples/jsm/tsl/display/SSAAPassNode.js b/examples/jsm/tsl/display/SSAAPassNode.js index 39fc16868f3d91..60cccd439379b4 100644 --- a/examples/jsm/tsl/display/SSAAPassNode.js +++ b/examples/jsm/tsl/display/SSAAPassNode.js @@ -1,20 +1,23 @@ -import { AdditiveBlending, Color, Vector2, PostProcessingUtils, PassNode, QuadMesh, NodeMaterial } from 'three/webgpu'; +import { AdditiveBlending, Color, Vector2, RendererUtils, PassNode, QuadMesh, NodeMaterial } from 'three/webgpu'; import { nodeObject, uniform, mrt, texture, getTextureIndex } from 'three/tsl'; +/** @module SSAAPassNode **/ + const _size = /*@__PURE__*/ new Vector2(); let _rendererState; /** -* -* 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 -* -*/ - + * A special render pass node that renders the scene with SSAA (Supersampling Anti-Aliasing). + * This manual SSAA approach re-renders the scene ones for each sample with camera jitter and accumulates the results. + * + * This node produces a high-quality anti-aliased output but is also extremely expensive because of + * its brute-force approach of re-rendering the entire scene multiple times. + * + * Reference: {@link https://en.wikipedia.org/wiki/Supersampling} + * + * @augments PassNode + */ class SSAAPassNode extends PassNode { static get type() { @@ -23,31 +26,95 @@ class SSAAPassNode extends PassNode { } + /** + * Constructs a new SSAA pass node. + * + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + */ constructor( scene, camera ) { super( PassNode.COLOR, scene, camera ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ 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. + /** + * The sample level specified as n, where the number of samples is 2^n, + * so sampleLevel = 4, is 2^4 samples, 16. + * + * @type {Number} + * @default 4 + */ + this.sampleLevel = 4; + + /** + * Whether rounding errors should be mitigated or not. + * + * @type {Boolean} + * @default true + */ this.unbiased = true; + + /** + * The clear color of the pass. + * + * @type {Color} + * @default 0x000000 + */ this.clearColor = new Color( 0x000000 ); + + /** + * The clear alpha of the pass. + * + * @type {Number} + * @default 0 + */ this.clearAlpha = 0; + /** + * A uniform node representing the sample weight. + * + * @type {UniformNode} + * @default 1 + */ this.sampleWeight = uniform( 1 ); - this.sampleRenderTarget = null; - + /** + * Reference to the internal render target that holds the current sample. + * + * @private + * @type {RenderTarget?} + */ + this._sampleRenderTarget = null; + + /** + * Reference to the internal quad mesh. + * + * @private + * @type {QuadMesh} + */ this._quadMesh = new QuadMesh(); } + /** + * This method is used to render the SSAA effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; const { scene, camera } = this; - _rendererState = PostProcessingUtils.resetRendererAndSceneState( renderer, scene, _rendererState ); + _rendererState = RendererUtils.resetRendererAndSceneState( renderer, scene, _rendererState ); // @@ -56,7 +123,7 @@ class SSAAPassNode extends PassNode { const size = renderer.getSize( _size ); this.setSize( size.width, size.height ); - this.sampleRenderTarget.setSize( this.renderTarget.width, this.renderTarget.height ); + this._sampleRenderTarget.setSize( this.renderTarget.width, this.renderTarget.height ); // @@ -120,7 +187,7 @@ class SSAAPassNode extends PassNode { } renderer.setClearColor( this.clearColor, this.clearAlpha ); - renderer.setRenderTarget( this.sampleRenderTarget ); + renderer.setRenderTarget( this._sampleRenderTarget ); renderer.clear(); renderer.render( scene, camera ); @@ -139,7 +206,7 @@ class SSAAPassNode extends PassNode { } - renderer.copyTextureToTexture( this.sampleRenderTarget.depthTexture, this.renderTarget.depthTexture ); + renderer.copyTextureToTexture( this._sampleRenderTarget.depthTexture, this.renderTarget.depthTexture ); // restore @@ -163,15 +230,21 @@ class SSAAPassNode extends PassNode { // - PostProcessingUtils.restoreRendererAndSceneState( renderer, scene, _rendererState ); + RendererUtils.restoreRendererAndSceneState( renderer, scene, _rendererState ); } + /** + * This method is used to setup the effect's MRT configuration and quad mesh. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { - if ( this.sampleRenderTarget === null ) { + if ( this._sampleRenderTarget === null ) { - this.sampleRenderTarget = this.renderTarget.clone(); + this._sampleRenderTarget = this.renderTarget.clone(); } @@ -185,11 +258,11 @@ class SSAAPassNode extends PassNode { for ( const name in passMRT.outputNodes ) { - const index = getTextureIndex( this.sampleRenderTarget.textures, name ); + const index = getTextureIndex( this._sampleRenderTarget.textures, name ); if ( index >= 0 ) { - outputs[ name ] = texture( this.sampleRenderTarget.textures[ index ] ).mul( this.sampleWeight ); + outputs[ name ] = texture( this._sampleRenderTarget.textures[ index ] ).mul( this.sampleWeight ); } @@ -199,7 +272,7 @@ class SSAAPassNode extends PassNode { } else { - sampleTexture = texture( this.sampleRenderTarget.texture ).mul( this.sampleWeight ); + sampleTexture = texture( this._sampleRenderTarget.texture ).mul( this.sampleWeight ); } @@ -216,13 +289,17 @@ class SSAAPassNode extends PassNode { } + /** + * Frees internal resources. This method should be called + * when the pass is no longer required. + */ dispose() { super.dispose(); - if ( this.sampleRenderTarget !== null ) { + if ( this._sampleRenderTarget !== null ) { - this.sampleRenderTarget.dispose(); + this._sampleRenderTarget.dispose(); } @@ -269,4 +346,12 @@ const _JitterVectors = [ ] ]; +/** + * TSL function for creating a SSAA pass node for Supersampling Anti-Aliasing. + * + * @function + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + * @returns {SSAAPassNode} + */ export const ssaaPass = ( scene, camera ) => nodeObject( new SSAAPassNode( scene, camera ) ); diff --git a/examples/jsm/tsl/display/SSRNode.js b/examples/jsm/tsl/display/SSRNode.js index fe2874a6ab1efd..a7bdeeecbfff06 100644 --- a/examples/jsm/tsl/display/SSRNode.js +++ b/examples/jsm/tsl/display/SSRNode.js @@ -1,13 +1,18 @@ -import { NearestFilter, RenderTarget, Vector2, PostProcessingUtils, QuadMesh, TempNode, NodeMaterial, NodeUpdateType } from 'three/webgpu'; +import { NearestFilter, RenderTarget, Vector2, RendererUtils, QuadMesh, TempNode, NodeMaterial, NodeUpdateType } from 'three/webgpu'; import { reference, viewZToPerspectiveDepth, logarithmicDepthToViewZ, getScreenPosition, getViewPosition, sqrt, mul, div, cross, float, Continue, Break, Loop, int, max, abs, sub, If, dot, reflect, normalize, screenCoordinate, nodeObject, Fn, passTexture, uv, uniform, perspectiveDepthToViewZ, orthographicDepthToViewZ, vec2, vec3, vec4 } from 'three/tsl'; +/** @module SSRNode **/ + const _quadMesh = /*@__PURE__*/ new QuadMesh(); const _size = /*@__PURE__*/ new Vector2(); let _rendererState; /** - * References: - * https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-reflection.html + * Post processing node for computing screen space reflections (SSR). + * + * Reference: {@link https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-reflection.html} + * + * @augments TempNode */ class SSRNode extends TempNode { @@ -17,56 +22,198 @@ class SSRNode extends TempNode { } + /** + * Constructs a new SSR node. + * + * @param {Node} colorNode - The node that represents the beauty pass. + * @param {Node} depthNode - A node that represents the beauty pass's depth. + * @param {Node} normalNode - A node that represents the beauty pass's normals. + * @param {Node} metalnessNode - A node that represents the beauty pass's metalness. + * @param {Camera} camera - The camera the scene is rendered with. + */ constructor( colorNode, depthNode, normalNode, metalnessNode, camera ) { super( 'vec4' ); + /** + * The node that represents the beauty pass. + * + * @type {Node} + */ this.colorNode = colorNode; + + /** + * A node that represents the beauty pass's depth. + * + * @type {Node} + */ this.depthNode = depthNode; + + /** + * A node that represents the beauty pass's normals. + * + * @type {Node} + */ this.normalNode = normalNode; + + /** + * A node that represents the beauty pass's metalness. + * + * @type {Node} + */ this.metalnessNode = metalnessNode; + + /** + * The camera the scene is rendered with. + * + * @type {Camera} + */ this.camera = camera; + /** + * The resolution scale. By default SSR reflections + * are computed in half resolutions. Setting the value + * to `1` improves quality but also results in more + * computational overhead. + * + * @type {Number} + * @default 0.5 + */ this.resolutionScale = 0.5; + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node renders + * its effect once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; - // render targets - + /** + * The render target the SSR is rendered into. + * + * @private + * @type {RenderTarget} + */ this._ssrRenderTarget = new RenderTarget( 1, 1, { depthBuffer: false, minFilter: NearestFilter, magFilter: NearestFilter } ); this._ssrRenderTarget.texture.name = 'SSRNode.SSR'; - // uniforms - - this.maxDistance = uniform( 1 ); // controls how far a fragment can reflect - this.thickness = uniform( 0.1 ); // controls the cutoff between what counts as a possible reflection hit and what does not - this.opacity = uniform( 1 ); // controls the transparency of the reflected colors - + /** + * Controls how far a fragment can reflect + * + * + * @type {UniformNode} + */ + this.maxDistance = uniform( 1 ); + + /** + * Controls the cutoff between what counts as a possible reflection hit and what does not. + * + * @type {UniformNode} + */ + this.thickness = uniform( 0.1 ); + + /** + * Controls the transparency of the reflected colors. + * + * @type {UniformNode} + */ + this.opacity = uniform( 1 ); + + /** + * Represents the projection matrix of the scene's camera. + * + * @private + * @type {UniformNode} + */ this._cameraProjectionMatrix = uniform( camera.projectionMatrix ); + + /** + * Represents the inverse projection matrix of the scene's camera. + * + * @private + * @type {UniformNode} + */ this._cameraProjectionMatrixInverse = uniform( camera.projectionMatrixInverse ); + + /** + * Represents the near value of the scene's camera. + * + * @private + * @type {ReferenceNode} + */ this._cameraNear = reference( 'near', 'float', camera ); + + /** + * Represents the far value of the scene's camera. + * + * @private + * @type {ReferenceNode} + */ this._cameraFar = reference( 'far', 'float', camera ); + + /** + * Whether the scene's camera is perspective or orthographic. + * + * @private + * @type {UniformNode} + */ this._isPerspectiveCamera = uniform( camera.isPerspectiveCamera ? 1 : 0 ); + + /** + * The resolution of the pass. + * + * @private + * @type {UniformNode} + */ this._resolution = uniform( new Vector2() ); - this._maxStep = uniform( 0 ); - // materials + /** + * This value is derived from the resolution and restricts + * the maximum raymarching steps in the fragment shader. + * + * @private + * @type {UniformNode} + */ + this._maxStep = uniform( 0 ); + /** + * The material that is used to render the effect. + * + * @private + * @type {NodeMaterial} + */ this._material = new NodeMaterial(); this._material.name = 'SSRNode.SSR'; - // - + /** + * The result of the effect is represented as a separate texture node. + * + * @private + * @type {PassTextureNode} + */ this._textureNode = passTexture( this, this._ssrRenderTarget.texture ); } + /** + * Returns the result of the effect as a texture node. + * + * @return {PassTextureNode} A texture node that represents the result of the effect. + */ getTextureNode() { return this._textureNode; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + */ setSize( width, height ) { width = Math.round( this.resolutionScale * width ); @@ -79,11 +226,16 @@ class SSRNode extends TempNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); const size = renderer.getDrawingBufferSize( _size ); @@ -103,10 +255,16 @@ class SSRNode extends TempNode { // restore - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { const uvNode = uv(); @@ -351,6 +509,10 @@ class SSRNode extends TempNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { this._ssrRenderTarget.dispose(); @@ -363,4 +525,15 @@ class SSRNode extends TempNode { export default SSRNode; +/** + * TSL function for creating screen space reflections (SSR). + * + * @function + * @param {Node} colorNode - The node that represents the beauty pass. + * @param {Node} depthNode - A node that represents the beauty pass's depth. + * @param {Node} normalNode - A node that represents the beauty pass's normals. + * @param {Node} metalnessNode - A node that represents the beauty pass's metalness. + * @param {Camera} camera - The camera the scene is rendered with. + * @returns {SSRNode} + */ export const ssr = ( colorNode, depthNode, normalNode, metalnessNode, camera ) => nodeObject( new SSRNode( nodeObject( colorNode ), nodeObject( depthNode ), nodeObject( normalNode ), nodeObject( metalnessNode ), camera ) ); diff --git a/examples/jsm/tsl/display/Sepia.js b/examples/jsm/tsl/display/Sepia.js index cae66b62224de3..939de4fd2d474e 100644 --- a/examples/jsm/tsl/display/Sepia.js +++ b/examples/jsm/tsl/display/Sepia.js @@ -1,5 +1,14 @@ import { dot, Fn, vec3, vec4 } from 'three/tsl'; +/** @module Sepia **/ + +/** + * Applies a sepia effect to the given color node. + * + * @function + * @param {Node} color - The color node to apply the sepia for. + * @return {Node} The updated color node. + */ export const sepia = /*@__PURE__*/ Fn( ( [ color ] ) => { const c = vec3( color ); diff --git a/examples/jsm/tsl/display/SobelOperatorNode.js b/examples/jsm/tsl/display/SobelOperatorNode.js index eb40fd4a27cc80..976e7ab9129b8e 100644 --- a/examples/jsm/tsl/display/SobelOperatorNode.js +++ b/examples/jsm/tsl/display/SobelOperatorNode.js @@ -1,6 +1,15 @@ import { Vector2, TempNode, NodeUpdateType } from 'three/webgpu'; import { nodeObject, Fn, uv, uniform, convertToTexture, vec2, vec3, vec4, mat3, luminance, add } from 'three/tsl'; +/** @module SobelOperatorNode **/ + +/** + * Post processing node for detecting edges with a sobel filter. + * A sobel filter should be applied after tone mapping and output color + * space conversion. + * + * @augments TempNode + */ class SobelOperatorNode extends TempNode { static get type() { @@ -9,19 +18,47 @@ class SobelOperatorNode extends TempNode { } + /** + * Constructs a new sobel operator node. + * + * @param {TextureNode} textureNode - The texture node that represents the input of the effect. + */ constructor( textureNode ) { super( 'vec4' ); + /** + * The texture node that represents the input of the effect. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + /** + * The `updateBeforeType` is set to `NodeUpdateType.FRAME` since the node updates + * its internal uniforms once per frame in `updateBefore()`. + * + * @type {String} + * @default 'frame' + */ this.updateBeforeType = NodeUpdateType.FRAME; + /** + * A uniform node holding the inverse resolution value. + * + * @private + * @type {UniformNode} + */ this._invSize = uniform( new Vector2() ); } - updateBefore() { + /** + * This method is used to update the effect's uniforms once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ + updateBefore( /* frame */ ) { const map = this.textureNode.value; @@ -29,7 +66,13 @@ class SobelOperatorNode extends TempNode { } - setup() { + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ + setup( /* builder */ ) { const { textureNode } = this; @@ -97,7 +140,7 @@ class SobelOperatorNode extends TempNode { Gy[ 2 ][ 2 ].mul( tx2y2 ) ); - // magnitute of the total gradient + // magnitude of the total gradient const G = valueGx.mul( valueGx ).add( valueGy.mul( valueGy ) ).sqrt(); @@ -115,4 +158,11 @@ class SobelOperatorNode extends TempNode { export default SobelOperatorNode; +/** + * TSL function for creating a sobel operator node which performs edge detection with a sobel filter. + * + * @function + * @param {Node} node - The node that represents the input of the effect. + * @returns {SobelOperatorNode} + */ export const sobel = ( node ) => nodeObject( new SobelOperatorNode( convertToTexture( node ) ) ); diff --git a/examples/jsm/tsl/display/StereoCompositePassNode.js b/examples/jsm/tsl/display/StereoCompositePassNode.js index 56c793c7c376bd..56892075095983 100644 --- a/examples/jsm/tsl/display/StereoCompositePassNode.js +++ b/examples/jsm/tsl/display/StereoCompositePassNode.js @@ -1,4 +1,4 @@ -import { RenderTarget, StereoCamera, HalfFloatType, LinearFilter, NearestFilter, Vector2, PassNode, QuadMesh, PostProcessingUtils } from 'three/webgpu'; +import { RenderTarget, StereoCamera, HalfFloatType, LinearFilter, NearestFilter, Vector2, PassNode, QuadMesh, RendererUtils } from 'three/webgpu'; import { texture } from 'three/tsl'; const _size = /*@__PURE__*/ new Vector2(); @@ -6,6 +6,16 @@ const _quadMesh = /*@__PURE__*/ new QuadMesh(); let _rendererState; +/** + * A special (abstract) render pass node that renders the scene + * as a stereoscopic image. Unlike {@link StereoPassNode}, this + * node merges the image for the left and right eye + * into a single one. That is required for effects like + * anaglyph or parallax barrier. + * + * @abstract + * @augments PassNode + */ class StereoCompositePassNode extends PassNode { static get type() { @@ -14,25 +24,76 @@ class StereoCompositePassNode extends PassNode { } + /** + * Constructs a new stereo composite pass node. + * + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + */ constructor( scene, camera ) { super( PassNode.COLOR, scene, camera ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStereoCompositePassNode = true; + /** + * The internal stereo camera that is used to render the scene. + * + * @type {StereoCamera} + */ this.stereo = new StereoCamera(); const _params = { minFilter: LinearFilter, magFilter: NearestFilter, type: HalfFloatType }; + /** + * The render target for rendering the left eye's view. + * + * @type {RenderTarget} + */ this._renderTargetL = new RenderTarget( 1, 1, _params ); + + /** + * The render target for rendering the right eye's view. + * + * @type {RenderTarget} + */ this._renderTargetR = new RenderTarget( 1, 1, _params ); + /** + * A texture node representing the left's eye view. + * + * @type {TextureNode} + */ this._mapLeft = texture( this._renderTargetL.texture ); + + /** + * A texture node representing the right's eye view. + * + * @type {TextureNode} + */ this._mapRight = texture( this._renderTargetR.texture ); + /** + * The node material that implements the composite. All + * derived effect passes must provide an instance for rendering. + * + * @type {NodeMaterial} + */ this._material = null; } + /** + * Updates the internal stereo camera. + * + * @param {Number} coordinateSystem - The current coordinate system. + */ updateStereoCamera( coordinateSystem ) { this.stereo.cameraL.coordinateSystem = coordinateSystem; @@ -41,6 +102,12 @@ class StereoCompositePassNode extends PassNode { } + /** + * Sets the size of the pass. + * + * @param {Number} width - The width of the pass. + * @param {Number} height - The height of the pass. + */ setSize( width, height ) { super.setSize( width, height ); @@ -50,12 +117,17 @@ class StereoCompositePassNode extends PassNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; const { scene, stereo, renderTarget } = this; - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); // @@ -84,10 +156,14 @@ class StereoCompositePassNode extends PassNode { // restore - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } + /** + * Frees internal resources. This method should be called + * when the pass is no longer required. + */ dispose() { super.dispose(); diff --git a/examples/jsm/tsl/display/StereoPassNode.js b/examples/jsm/tsl/display/StereoPassNode.js index 912d1d40e3b7dd..2df92cd39c4057 100644 --- a/examples/jsm/tsl/display/StereoPassNode.js +++ b/examples/jsm/tsl/display/StereoPassNode.js @@ -1,10 +1,17 @@ -import { StereoCamera, Vector2, PassNode, PostProcessingUtils } from 'three/webgpu'; +import { StereoCamera, Vector2, PassNode, RendererUtils } from 'three/webgpu'; import { nodeObject } from 'three/tsl'; +/** @module StereoPassNode **/ + const _size = /*@__PURE__*/ new Vector2(); let _rendererState; +/** + * A special render pass node that renders the scene as a stereoscopic image. + * + * @augments PassNode + */ class StereoPassNode extends PassNode { static get type() { @@ -13,23 +20,46 @@ class StereoPassNode extends PassNode { } + /** + * Constructs a new stereo pass node. + * + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + */ constructor( scene, camera ) { super( PassNode.COLOR, scene, camera ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStereoPassNode = true; + /** + * The internal stereo camera that is used to render the scene. + * + * @type {StereoCamera} + */ this.stereo = new StereoCamera(); this.stereo.aspect = 0.5; } + /** + * This method is used to render the stereo effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; const { scene, camera, stereo, renderTarget } = this; - _rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState ); + _rendererState = RendererUtils.resetRendererState( renderer, _rendererState ); // @@ -71,7 +101,7 @@ class StereoPassNode extends PassNode { // restore - PostProcessingUtils.restoreRendererState( renderer, _rendererState ); + RendererUtils.restoreRendererState( renderer, _rendererState ); } @@ -79,4 +109,12 @@ class StereoPassNode extends PassNode { export default StereoPassNode; +/** + * TSL function for creating a stereo pass node for stereoscopic rendering. + * + * @function + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + * @returns {StereoPassNode} + */ export const stereoPass = ( scene, camera ) => nodeObject( new StereoPassNode( scene, camera ) ); diff --git a/examples/jsm/tsl/display/TRAAPassNode.js b/examples/jsm/tsl/display/TRAAPassNode.js index 272cea0b92ed94..4ad3c49939e7df 100644 --- a/examples/jsm/tsl/display/TRAAPassNode.js +++ b/examples/jsm/tsl/display/TRAAPassNode.js @@ -1,19 +1,25 @@ -import { Color, Vector2, NearestFilter, Matrix4, PostProcessingUtils, PassNode, QuadMesh, NodeMaterial } from 'three/webgpu'; +import { Color, Vector2, NearestFilter, Matrix4, RendererUtils, PassNode, QuadMesh, NodeMaterial } from 'three/webgpu'; import { add, float, If, Loop, int, Fn, min, max, clamp, nodeObject, texture, uniform, uv, vec2, vec4, luminance } from 'three/tsl'; +/** @module TRAAPassNode **/ + const _quadMesh = /*@__PURE__*/ new QuadMesh(); const _size = /*@__PURE__*/ new Vector2(); let _rendererState; + /** -* Temporal Reprojection Anti-Aliasing (TRAA). -* -* References: -* https://alextardif.com/TAA.html -* https://www.elopezr.com/temporal-aa-and-the-quest-for-the-holy-trail/ -* -*/ + * A special render pass node that renders the scene with TRAA (Temporal Reprojection Anti-Aliasing). + * + * Note: The current implementation does not yet support MRT setups. + * + * References: + * - {@link https://alextardif.com/TAA.html} + * - {@link https://www.elopezr.com/temporal-aa-and-the-quest-for-the-holy-trail/} + * + * @augments PassNode + */ class TRAAPassNode extends PassNode { static get type() { @@ -22,34 +28,100 @@ class TRAAPassNode extends PassNode { } + /** + * Constructs a new TRAA pass node. + * + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + */ constructor( scene, camera ) { super( PassNode.COLOR, scene, camera ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isTRAAPassNode = true; + /** + * The clear color of the pass. + * + * @type {Color} + * @default 0x000000 + */ this.clearColor = new Color( 0x000000 ); + + /** + * The clear alpha of the pass. + * + * @type {Number} + * @default 0 + */ this.clearAlpha = 0; + /** + * The jitter index selects the current camera offset value. + * + * @private + * @type {Number} + * @default 0 + */ this._jitterIndex = 0; - this._originalProjectionMatrix = new Matrix4(); - // uniforms + /** + * Used to save the original/unjittered projection matrix. + * + * @private + * @type {Matrix4} + */ + this._originalProjectionMatrix = new Matrix4(); + /** + * A uniform node holding the inverse resolution value. + * + * @private + * @type {UniformNode} + */ this._invSize = uniform( new Vector2() ); - // render targets - + /** + * The render target that holds the current sample. + * + * @private + * @type {RenderTarget?} + */ this._sampleRenderTarget = null; - this._historyRenderTarget = null; - // materials + /** + * The render target that represents the history of frame data. + * + * @private + * @type {RenderTarget?} + */ + this._historyRenderTarget = null; + /** + * Material used for the resolve step. + * + * @private + * @type {NodeMaterial} + */ this._resolveMaterial = new NodeMaterial(); this._resolveMaterial.name = 'TRAA.Resolve'; } + /** + * Sets the size of the effect. + * + * @param {Number} width - The width of the effect. + * @param {Number} height - The height of the effect. + * @return {Boolean} Whether the TRAA needs a restart or not. That is required after a resize since buffer data with different sizes can't be resolved. + */ setSize( width, height ) { super.setSize( width, height ); @@ -71,12 +143,17 @@ class TRAAPassNode extends PassNode { } + /** + * This method is used to render the effect once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ updateBefore( frame ) { const { renderer } = frame; const { scene, camera } = this; - _rendererState = PostProcessingUtils.resetRendererAndSceneState( renderer, scene, _rendererState ); + _rendererState = RendererUtils.resetRendererAndSceneState( renderer, scene, _rendererState ); // @@ -214,10 +291,16 @@ class TRAAPassNode extends PassNode { velocityOutput.setProjectionMatrix( null ); - PostProcessingUtils.restoreRendererAndSceneState( renderer, scene, _rendererState ); + RendererUtils.restoreRendererAndSceneState( renderer, scene, _rendererState ); } + /** + * This method is used to setup the effect's render targets and TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {PassTextureNode} + */ setup( builder ) { if ( this._sampleRenderTarget === null ) { @@ -317,6 +400,10 @@ class TRAAPassNode extends PassNode { } + /** + * Frees internal resources. This method should be called + * when the effect is no longer required. + */ dispose() { super.dispose(); @@ -352,4 +439,12 @@ const _JitterVectors = [ [ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ] ]; +/** + * TSL function for creating a TRAA pass node for Temporal Reprojection Anti-Aliasing. + * + * @function + * @param {Scene} scene - The scene to render. + * @param {Camera} camera - The camera to render the scene with. + * @returns {TRAAPassNode} + */ export const traaPass = ( scene, camera ) => nodeObject( new TRAAPassNode( scene, camera ) ); diff --git a/examples/jsm/tsl/display/TransitionNode.js b/examples/jsm/tsl/display/TransitionNode.js index 45b3a41c1bf2d8..004bf43f733281 100644 --- a/examples/jsm/tsl/display/TransitionNode.js +++ b/examples/jsm/tsl/display/TransitionNode.js @@ -1,6 +1,13 @@ import { TempNode } from 'three/webgpu'; import { nodeObject, Fn, float, uv, convertToTexture, vec4, If, int, clamp, sub, mix } from 'three/tsl'; +/** @module TransitionNode **/ + +/** + * Post processing node for creating a transition effect between scenes. + * + * @augments TempNode + */ class TransitionNode extends TempNode { static get type() { @@ -9,24 +16,70 @@ class TransitionNode extends TempNode { } + /** + * Constructs a new transition node. + * + * @param {TextureNode} textureNodeA - A texture node that represents the beauty pass of the first scene. + * @param {TextureNode} textureNodeB - A texture node that represents the beauty pass of the second scene. + * @param {TextureNode} mixTextureNode - A texture node that defines how the transition effect should look like. + * @param {Node} mixRatioNode - The interpolation factor that controls the mix. + * @param {Node} thresholdNode - Can be used to tweak the linear interpolation. + * @param {Node} useTextureNode - Whether `mixTextureNode` should influence the transition or not. + */ constructor( textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode ) { super( 'vec4' ); - // Input textures - + /** + * A texture node that represents the beauty pass of the first scene. + * + * @type {TextureNode} + */ this.textureNodeA = textureNodeA; + + /** + * A texture node that represents the beauty pass of the second scene. + * + * @type {TextureNode} + */ this.textureNodeB = textureNodeB; - this.mixTextureNode = mixTextureNode; - // Uniforms + /** + * A texture that defines how the transition effect should look like. + * + * @type {TextureNode} + */ + this.mixTextureNode = mixTextureNode; + /** + * The interpolation factor that controls the mix. + * + * @type {Node} + */ this.mixRatioNode = mixRatioNode; + + /** + * Can be used to tweak the linear interpolation. + * + * @type {Node} + */ this.thresholdNode = thresholdNode; + + /** + * Whether `mixTextureNode` should influence the transition or not. + * + * @type {Node} + */ this.useTextureNode = useTextureNode; } + /** + * This method is used to setup the effect's TSL code. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ShaderCallNodeInternal} + */ setup() { const { textureNodeA, textureNodeB, mixTextureNode, mixRatioNode, thresholdNode, useTextureNode } = this; @@ -73,4 +126,16 @@ class TransitionNode extends TempNode { export default TransitionNode; -export 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 ) ) ); +/** + * TSL function for creating a transition node for post processing. + * + * @function + * @param {Node} nodeA - A texture node that represents the beauty pass of the first scene. + * @param {Node} nodeB - A texture node that represents the beauty pass of the second scene. + * @param {Node} mixTextureNode - A texture that defines how the transition effect should look like. + * @param {Node | Number} mixRatio - The interpolation factor that controls the mix. + * @param {Node | Number} threshold - Can be used to tweak the linear interpolation. + * @param {Node | Number} useTexture - Whether `mixTextureNode` should influence the transition or not. + * @returns {TransitionNode} + */ +export const transition = ( nodeA, nodeB, mixTextureNode, mixRatio, threshold, useTexture ) => nodeObject( new TransitionNode( convertToTexture( nodeA ), convertToTexture( nodeB ), convertToTexture( mixTextureNode ), nodeObject( mixRatio ), nodeObject( threshold ), nodeObject( useTexture ) ) ); diff --git a/examples/jsm/tsl/display/hashBlur.js b/examples/jsm/tsl/display/hashBlur.js index 6a9eaea079686d..eb4426c482a3cd 100644 --- a/examples/jsm/tsl/display/hashBlur.js +++ b/examples/jsm/tsl/display/hashBlur.js @@ -1,7 +1,18 @@ import { float, Fn, vec2, uv, sin, rand, degrees, cos, Loop, vec4 } from 'three/tsl'; -// https://www.shadertoy.com/view/4lXXWn - +/** @module HashBlur **/ + +/** + * Applies a hash blur effect to the given texture node. + * + * Reference: {@link https://www.shadertoy.com/view/4lXXWn}. + * + * @function + * @param {Node} textureNode - The texture node that should be blurred. + * @param {Node} [bluramount=float(0.1)] - This node determines the amount of blur. + * @param {Node} [repeats=float(45)] - This node determines the quality of the blur. A higher value produces a less grainy result but is also more expensive. + * @return {Node} The blurred texture node. + */ export const hashBlur = /*#__PURE__*/ Fn( ( [ textureNode, bluramount = float( 0.1 ), repeats = float( 45 ) ] ) => { const draw = ( uv ) => textureNode.sample( uv ); diff --git a/examples/jsm/tsl/lighting/TiledLightsNode.js b/examples/jsm/tsl/lighting/TiledLightsNode.js index b65ebd3de6ba75..f8f7eb0326f7fb 100644 --- a/examples/jsm/tsl/lighting/TiledLightsNode.js +++ b/examples/jsm/tsl/lighting/TiledLightsNode.js @@ -52,30 +52,36 @@ class TiledLightsNode extends LightsNode { this.maxLights = maxLights; this.tileSize = tileSize; - this.bufferSize = null; - this.lightIndexes = null; - this.screenTileIndex = null; - this.compute = null; - this.lightsTexture = null; - - this.lightsCount = uniform( 0, 'int' ); - this.tileLightCount = 8; - this.screenSize = uniform( new Vector2() ); - this.cameraProjectionMatrix = uniform( 'mat4' ); - this.cameraViewMatrix = uniform( 'mat4' ); + this._bufferSize = null; + this._lightIndexes = null; + this._screenTileIndex = null; + this._compute = null; + this._lightsTexture = null; + + this._lightsCount = uniform( 0, 'int' ); + this._tileLightCount = 8; + this._screenSize = uniform( new Vector2() ); + this._cameraProjectionMatrix = uniform( 'mat4' ); + this._cameraViewMatrix = uniform( 'mat4' ); this.updateBeforeType = NodeUpdateType.RENDER; } + customCacheKey() { + + return this._compute.getCacheKey() + super.customCacheKey(); + + } + updateLightsTexture() { - const { lightsTexture, tiledLights } = this; + const { _lightsTexture: lightsTexture, tiledLights } = this; const data = lightsTexture.image.data; const lineSize = lightsTexture.image.width * 4; - this.lightsCount.value = tiledLights.length; + this._lightsCount.value = tiledLights.length; for ( let i = 0; i < tiledLights.length; i ++ ) { @@ -113,13 +119,13 @@ class TiledLightsNode extends LightsNode { this.updateLightsTexture( camera ); - this.cameraProjectionMatrix.value = camera.projectionMatrix; - this.cameraViewMatrix.value = camera.matrixWorldInverse; + this._cameraProjectionMatrix.value = camera.projectionMatrix; + this._cameraViewMatrix.value = camera.matrixWorldInverse; renderer.getDrawingBufferSize( _size ); - this.screenSize.value.copy( _size ); + this._screenSize.value.copy( _size ); - renderer.compute( this.compute ); + renderer.compute( this._compute ); } @@ -153,7 +159,7 @@ class TiledLightsNode extends LightsNode { getBlock( block = 0 ) { - return this.lightIndexes.element( this.screenTileIndex.mul( int( 2 ).add( int( block ) ) ) ); + return this._lightIndexes.element( this._screenTileIndex.mul( int( 2 ).add( int( block ) ) ) ); } @@ -163,9 +169,9 @@ class TiledLightsNode extends LightsNode { const stride = int( 4 ); const tileOffset = element.div( stride ); - const tileIndex = this.screenTileIndex.mul( int( 2 ) ).add( tileOffset ); + const tileIndex = this._screenTileIndex.mul( int( 2 ) ).add( tileOffset ); - return this.lightIndexes.element( tileIndex ).element( element.modInt( stride ) ); + return this._lightIndexes.element( tileIndex ).element( element.modInt( stride ) ); } @@ -173,11 +179,11 @@ class TiledLightsNode extends LightsNode { index = int( index ); - const dataA = textureLoad( this.lightsTexture, ivec2( index, 0 ) ); - const dataB = textureLoad( this.lightsTexture, ivec2( index, 1 ) ); + const dataA = textureLoad( this._lightsTexture, ivec2( index, 0 ) ); + const dataB = textureLoad( this._lightsTexture, ivec2( index, 1 ) ); const position = dataA.xyz; - const viewPosition = this.cameraViewMatrix.mul( position ); + const viewPosition = this._cameraViewMatrix.mul( position ); const distance = dataA.w; const color = dataB.rgb; const decay = dataB.w; @@ -208,7 +214,7 @@ class TiledLightsNode extends LightsNode { Fn( () => { - Loop( this.tileLightCount, ( { i } ) => { + Loop( this._tileLightCount, ( { i } ) => { const lightIndex = this.getTile( i ); @@ -246,7 +252,7 @@ class TiledLightsNode extends LightsNode { width = this.getBufferFitSize( width ); height = this.getBufferFitSize( height ); - if ( ! this.bufferSize || this.bufferSize.width !== width || this.bufferSize.height !== height ) { + if ( ! this._bufferSize || this._bufferSize.width !== width || this._bufferSize.height !== height ) { this.create( width, height ); @@ -263,11 +269,11 @@ class TiledLightsNode extends LightsNode { const width = this.getBufferFitSize( _size.width ); const height = this.getBufferFitSize( _size.height ); - if ( this.bufferSize === null ) { + if ( this._bufferSize === null ) { this.create( width, height ); - } else if ( this.bufferSize.width !== width || this.bufferSize.height !== height ) { + } else if ( this._bufferSize.width !== width || this._bufferSize.height !== height ) { this.create( width, height ); @@ -315,7 +321,7 @@ class TiledLightsNode extends LightsNode { const compute = Fn( () => { - const { cameraProjectionMatrix, bufferSize, screenSize } = this; + const { _cameraProjectionMatrix: cameraProjectionMatrix, _bufferSize: bufferSize, _screenSize: screenSize } = this; const tiledBufferSize = bufferSize.clone().divideScalar( tileSize ).floor(); @@ -335,7 +341,7 @@ class TiledLightsNode extends LightsNode { Loop( this.maxLights, ( { i } ) => { - If( index.greaterThanEqual( this.tileLightCount ).or( int( i ).greaterThanEqual( int( this.lightsCount ) ) ), () => { + If( index.greaterThanEqual( this._tileLightCount ).or( int( i ).greaterThanEqual( int( this._lightsCount ) ) ), () => { Return(); @@ -368,11 +374,11 @@ class TiledLightsNode extends LightsNode { // assigns - this.bufferSize = bufferSize; - this.lightIndexes = lightIndexes; - this.screenTileIndex = screenTileIndex; - this.compute = compute; - this.lightsTexture = lightsTexture; + this._bufferSize = bufferSize; + this._lightIndexes = lightIndexes; + this._screenTileIndex = screenTileIndex; + this._compute = compute; + this._lightsTexture = lightsTexture; } diff --git a/examples/jsm/webxr/XRControllerModelFactory.js b/examples/jsm/webxr/XRControllerModelFactory.js index d56b1e569da613..dfb1d4c194f5b8 100644 --- a/examples/jsm/webxr/XRControllerModelFactory.js +++ b/examples/jsm/webxr/XRControllerModelFactory.js @@ -54,6 +54,8 @@ class XRControllerModel extends Object3D { /** * Polls data from the XRInputSource and updates the model's components to match * the real world data + * + * @param {Boolean} force */ updateMatrixWorld( force ) { @@ -109,6 +111,9 @@ class XRControllerModel extends Object3D { * Walks the model's tree to find the nodes needed to animate the components and * saves them to the motionController components for use in the frame loop. When * touchpads are found, attaches a touch dot to them. + * + * @param {MotionController} motionController + * @param {Object3D} scene */ function findNodes( motionController, scene ) { diff --git a/examples/jsm/webxr/XREstimatedLight.js b/examples/jsm/webxr/XREstimatedLight.js index 85c7b9b690c854..4b2b1977f84e9b 100644 --- a/examples/jsm/webxr/XREstimatedLight.js +++ b/examples/jsm/webxr/XREstimatedLight.js @@ -79,7 +79,7 @@ class SessionLightProbe { onXRFrame( time, xrFrame ) { - // If either this obejct or the XREstimatedLight has been destroyed, stop + // If either this object or the XREstimatedLight has been destroyed, stop // running the frame loop. if ( ! this.xrLight ) { diff --git a/examples/misc_raycaster_helper.html b/examples/misc_raycaster_helper.html new file mode 100644 index 00000000000000..6a21223ded9f2d --- /dev/null +++ b/examples/misc_raycaster_helper.html @@ -0,0 +1,112 @@ + + + + three.js misc - raycaster - helper + + + + + +
    + three.js - raycaster - helper
    + See external RaycasterHelper for more information. +
    + + + + + + + \ No newline at end of file diff --git a/examples/screenshots/misc_raycaster_helper.jpg b/examples/screenshots/misc_raycaster_helper.jpg new file mode 100644 index 00000000000000..5b5d4dd82c2670 Binary files /dev/null and b/examples/screenshots/misc_raycaster_helper.jpg differ diff --git a/examples/screenshots/webgl_geometry_teapot.jpg b/examples/screenshots/webgl_geometry_teapot.jpg index 47f95d54d598b4..ec05d359f447f3 100644 Binary files a/examples/screenshots/webgl_geometry_teapot.jpg and b/examples/screenshots/webgl_geometry_teapot.jpg differ diff --git a/examples/screenshots/webgpu_camera.jpg b/examples/screenshots/webgpu_camera.jpg new file mode 100644 index 00000000000000..1d38a820ad686d Binary files /dev/null and b/examples/screenshots/webgpu_camera.jpg differ diff --git a/examples/screenshots/webgpu_camera_array.jpg b/examples/screenshots/webgpu_camera_array.jpg new file mode 100644 index 00000000000000..7a5c66727c950e Binary files /dev/null and b/examples/screenshots/webgpu_camera_array.jpg differ diff --git a/examples/screenshots/webgpu_clearcoat.jpg b/examples/screenshots/webgpu_clearcoat.jpg index c2f83f67f9c537..f16008c4595639 100644 Binary files a/examples/screenshots/webgpu_clearcoat.jpg and b/examples/screenshots/webgpu_clearcoat.jpg differ diff --git a/examples/screenshots/webgpu_clipping.jpg b/examples/screenshots/webgpu_clipping.jpg index 188545866ae3cc..bae91f99369ed6 100644 Binary files a/examples/screenshots/webgpu_clipping.jpg and b/examples/screenshots/webgpu_clipping.jpg differ diff --git a/examples/screenshots/webgpu_compute_birds.jpg b/examples/screenshots/webgpu_compute_birds.jpg index fa9301798a65c6..1293dd5f12be58 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_instance_points.jpg b/examples/screenshots/webgpu_instance_points.jpg index ca3484aa73688e..40eca59386dc3a 100644 Binary files a/examples/screenshots/webgpu_instance_points.jpg and b/examples/screenshots/webgpu_instance_points.jpg differ diff --git a/examples/screenshots/webgpu_instance_sprites.jpg b/examples/screenshots/webgpu_instance_sprites.jpg index 099f4fb2406e20..a452698dd728e6 100644 Binary files a/examples/screenshots/webgpu_instance_sprites.jpg and b/examples/screenshots/webgpu_instance_sprites.jpg differ diff --git a/examples/screenshots/webgpu_lights_custom.jpg b/examples/screenshots/webgpu_lights_custom.jpg index 50a139f1332f5f..ee54fef1add122 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_lights_ies_spotlight.jpg b/examples/screenshots/webgpu_lights_ies_spotlight.jpg index d645a62b822167..492dd1dc4c21d0 100644 Binary files a/examples/screenshots/webgpu_lights_ies_spotlight.jpg and b/examples/screenshots/webgpu_lights_ies_spotlight.jpg differ diff --git a/examples/screenshots/webgpu_postprocessing.jpg b/examples/screenshots/webgpu_postprocessing.jpg index 055e2fcb46c646..305c5bb4bd366d 100644 Binary files a/examples/screenshots/webgpu_postprocessing.jpg and b/examples/screenshots/webgpu_postprocessing.jpg differ diff --git a/examples/screenshots/webgpu_postprocessing_afterimage.jpg b/examples/screenshots/webgpu_postprocessing_afterimage.jpg index 4a1032c93cd0a4..004fc4afb6b348 100644 Binary files a/examples/screenshots/webgpu_postprocessing_afterimage.jpg and b/examples/screenshots/webgpu_postprocessing_afterimage.jpg differ diff --git a/examples/screenshots/webgpu_postprocessing_ssr.jpg b/examples/screenshots/webgpu_postprocessing_ssr.jpg index bfed0539c6375f..89212457efb475 100644 Binary files a/examples/screenshots/webgpu_postprocessing_ssr.jpg and b/examples/screenshots/webgpu_postprocessing_ssr.jpg differ diff --git a/examples/screenshots/webgpu_rendertarget_2d-array_3d.jpg b/examples/screenshots/webgpu_rendertarget_2d-array_3d.jpg new file mode 100644 index 00000000000000..da9ddafedad849 Binary files /dev/null and b/examples/screenshots/webgpu_rendertarget_2d-array_3d.jpg differ diff --git a/examples/screenshots/webgpu_shadowmap_opacity.jpg b/examples/screenshots/webgpu_shadowmap_opacity.jpg index 6075d34a5029d6..3fb79125f00791 100644 Binary files a/examples/screenshots/webgpu_shadowmap_opacity.jpg and b/examples/screenshots/webgpu_shadowmap_opacity.jpg differ diff --git a/examples/screenshots/webgpu_sprites.jpg b/examples/screenshots/webgpu_sprites.jpg index 259adb86f764cf..324931b17e8086 100644 Binary files a/examples/screenshots/webgpu_sprites.jpg and b/examples/screenshots/webgpu_sprites.jpg differ diff --git a/examples/screenshots/webgpu_textures_2d-array_compressed.jpg b/examples/screenshots/webgpu_textures_2d-array_compressed.jpg index f3b39b56d4154d..c92bba94c8d2d4 100644 Binary files a/examples/screenshots/webgpu_textures_2d-array_compressed.jpg and b/examples/screenshots/webgpu_textures_2d-array_compressed.jpg differ diff --git a/examples/screenshots/webgpu_tsl_galaxy.jpg b/examples/screenshots/webgpu_tsl_galaxy.jpg index 8f4f54eb70ad09..5e759a1fdbdb58 100644 Binary files a/examples/screenshots/webgpu_tsl_galaxy.jpg and b/examples/screenshots/webgpu_tsl_galaxy.jpg differ diff --git a/examples/screenshots/webgpu_tsl_vfx_tornado.jpg b/examples/screenshots/webgpu_tsl_vfx_tornado.jpg index 9fa7e7d5e13696..3e331470efb9f2 100644 Binary files a/examples/screenshots/webgpu_tsl_vfx_tornado.jpg and b/examples/screenshots/webgpu_tsl_vfx_tornado.jpg differ diff --git a/examples/screenshots/webgpu_video_frame.jpg b/examples/screenshots/webgpu_video_frame.jpg new file mode 100644 index 00000000000000..0f418a4bdb1013 Binary files /dev/null and b/examples/screenshots/webgpu_video_frame.jpg differ diff --git a/examples/screenshots/webxr_vr_layers.jpg b/examples/screenshots/webxr_vr_layers.jpg index 26462eb2f22db1..549a83ea3f6779 100755 Binary files a/examples/screenshots/webxr_vr_layers.jpg and b/examples/screenshots/webxr_vr_layers.jpg differ diff --git a/examples/tags.json b/examples/tags.json index b103ba8298fd06..1c508c2d1f4632 100644 --- a/examples/tags.json +++ b/examples/tags.json @@ -5,6 +5,7 @@ "misc_controls_orbit": [ "rotation" ], "misc_controls_trackball": [ "rotation" ], "misc_controls_transform": [ "scale", "rotate", "translate" ], + "misc_raycaster_helper": [ "external" ], "physics_ammo_cloth": [ "integration" ], "physics_jolt_instancing": [ "external" ], "physics_rapier_instancing": [ "external" ], @@ -144,8 +145,10 @@ "webgpu_postprocessing_ssaa": [ "msaa", "multisampled" ], "webgpu_refraction": [ "water" ], "webgpu_rtt": [ "renderTarget", "texture" ], + "webgpu_rendertarget_2d-array_3d": [ "renderTarget", "2d-array", "3d" ], "webgpu_sky": [ "sun" ], "webgpu_tonemapping": [ "gltf" ], "webgpu_tsl_compute_attractors_particles": [ "gpgpu" ], - "webgpu_ocean": [ "water" ] + "webgpu_ocean": [ "water" ], + "webgpu_video_frame": [ "webcodecs" ] } diff --git a/examples/webgl_buffergeometry_instancing_billboards.html b/examples/webgl_buffergeometry_instancing_billboards.html index 1c6470a2f49e92..155c0fd7826adb 100644 --- a/examples/webgl_buffergeometry_instancing_billboards.html +++ b/examples/webgl_buffergeometry_instancing_billboards.html @@ -47,7 +47,7 @@ varying vec2 vUv; varying float vScale; - // HSL to RGB Convertion helpers + // HSL to RGB Conversion helpers vec3 HUEtoRGB(float H){ H = mod(H,1.0); float R = abs(H * 6.0 - 3.0) - 1.0; diff --git a/examples/webgl_geometry_extrude_splines.html b/examples/webgl_geometry_extrude_splines.html index 262a83d5f20224..a852ff8274002d 100644 --- a/examples/webgl_geometry_extrude_splines.html +++ b/examples/webgl_geometry_extrude_splines.html @@ -328,7 +328,7 @@ splineCamera.position.copy( position ); cameraEye.position.copy( position ); - // using arclength for stablization in look ahead + // using arclength for stabilization in look ahead tubeGeometry.parameters.path.getPointAt( ( t + 30 / tubeGeometry.parameters.path.getLength() ) % 1, lookAt ); lookAt.multiplyScalar( params.scale ); diff --git a/examples/webgl_geometry_teapot.html b/examples/webgl_geometry_teapot.html index 66d379f7b2034e..8c1eed556a1e40 100644 --- a/examples/webgl_geometry_teapot.html +++ b/examples/webgl_geometry_teapot.html @@ -63,9 +63,9 @@ camera.position.set( - 600, 550, 1300 ); // LIGHTS - ambientLight = new THREE.AmbientLight( 0x7c7c7c, 3.0 ); + ambientLight = new THREE.AmbientLight( 0x7c7c7c, 2.0 ); - light = new THREE.DirectionalLight( 0xFFFFFF, 3.0 ); + light = new THREE.DirectionalLight( 0xFFFFFF, 2.0 ); light.position.set( 0.32, 0.39, 0.7 ); // RENDERER @@ -96,7 +96,7 @@ materials[ 'wireframe' ] = new THREE.MeshBasicMaterial( { wireframe: true } ); materials[ 'flat' ] = new THREE.MeshPhongMaterial( { specular: 0x000000, flatShading: true, side: THREE.DoubleSide } ); materials[ 'smooth' ] = new THREE.MeshLambertMaterial( { side: THREE.DoubleSide } ); - materials[ 'glossy' ] = new THREE.MeshPhongMaterial( { side: THREE.DoubleSide } ); + materials[ 'glossy' ] = new THREE.MeshPhongMaterial( { color: 0xc0c0c0, specular: 0x404040, shininess: 300, side: THREE.DoubleSide } ); materials[ 'textured' ] = new THREE.MeshPhongMaterial( { map: textureMap, side: THREE.DoubleSide } ); materials[ 'reflective' ] = new THREE.MeshPhongMaterial( { envMap: textureCube, side: THREE.DoubleSide } ); diff --git a/examples/webgl_materials_modified.html b/examples/webgl_materials_modified.html index afb8c3fa29ec53..b54ee9c9fb075b 100644 --- a/examples/webgl_materials_modified.html +++ b/examples/webgl_materials_modified.html @@ -104,7 +104,7 @@ }; - // Make sure WebGLRenderer doesnt reuse a single program + // Make sure WebGLRenderer doesn't reuse a single program material.customProgramCacheKey = function () { diff --git a/examples/webgl_materials_texture_rotation.html b/examples/webgl_materials_texture_rotation.html index 36cfa8b49319f5..b4107ab9881929 100644 --- a/examples/webgl_materials_texture_rotation.html +++ b/examples/webgl_materials_texture_rotation.html @@ -128,7 +128,7 @@ texture.matrix .identity() .translate( - API.centerX, - API.centerY ) - .rotate( API.rotation ) // I don't understand how rotation can preceed scale, but it seems to be required... + .rotate( API.rotation ) // I don't understand how rotation can precede scale, but it seems to be required... .scale( API.repeatX, API.repeatY ) .translate( API.centerX, API.centerY ) .translate( API.offsetX, API.offsetY ); diff --git a/examples/webgl_materials_toon.html b/examples/webgl_materials_toon.html index 5d097e313bc85f..b2aecf388eb574 100644 --- a/examples/webgl_materials_toon.html +++ b/examples/webgl_materials_toon.html @@ -67,9 +67,9 @@ // Materials const cubeWidth = 400; - const numberOfSphersPerSide = 5; - const sphereRadius = ( cubeWidth / numberOfSphersPerSide ) * 0.8 * 0.5; - const stepSize = 1.0 / numberOfSphersPerSide; + const numberOfSpheresPerSide = 5; + const sphereRadius = ( cubeWidth / numberOfSpheresPerSide ) * 0.8 * 0.5; + const stepSize = 1.0 / numberOfSpheresPerSide; const geometry = new THREE.SphereGeometry( sphereRadius, 32, 16 ); diff --git a/examples/webgl_postprocessing_godrays.html b/examples/webgl_postprocessing_godrays.html index d409a4bd5c7a2a..178246803b3e70 100644 --- a/examples/webgl_postprocessing_godrays.html +++ b/examples/webgl_postprocessing_godrays.html @@ -272,7 +272,7 @@ screenSpacePosition.x = ( clipPosition.x + 1 ) / 2; // transform from [-1,1] to [0,1] screenSpacePosition.y = ( clipPosition.y + 1 ) / 2; // transform from [-1,1] to [0,1] - screenSpacePosition.z = clipPosition.z; // needs to stay in clip space for visibilty checks + screenSpacePosition.z = clipPosition.z; // needs to stay in clip space for visibility checks // Give it to the god-ray and sun shaders diff --git a/examples/webgpu_animation_retargeting.html b/examples/webgpu_animation_retargeting.html index d9b49477a7f703..1374db155f9dd4 100644 --- a/examples/webgpu_animation_retargeting.html +++ b/examples/webgpu_animation_retargeting.html @@ -25,7 +25,7 @@ + + + + + diff --git a/examples/webgpu_camera_array.html b/examples/webgpu_camera_array.html new file mode 100644 index 00000000000000..f8349a6077f531 --- /dev/null +++ b/examples/webgpu_camera_array.html @@ -0,0 +1,142 @@ + + + + three.js webgpu - arraycamera + + + + + + + + + + + diff --git a/examples/webgpu_compute_audio.html b/examples/webgpu_compute_audio.html index 8f92254bd4a3db..0668404d2b3e5d 100644 --- a/examples/webgpu_compute_audio.html +++ b/examples/webgpu_compute_audio.html @@ -101,9 +101,14 @@ waveArray = instancedArray( waveBuffer ); + // read-only buffer + + const originalWave = instancedArray( waveBuffer ).toReadOnly(); + // The Pixel Buffer Object (PBO) is required to get the GPU computed data to the CPU in the WebGL2 fallback. // As used in `renderer.getArrayBufferAsync( waveArray.value )`. + originalWave.setPBO( true ); waveArray.setPBO( true ); // params @@ -123,14 +128,14 @@ const time = index.mul( pitch ); - let wave = waveArray.element( time ); + let wave = originalWave.element( time ); // delay for ( let i = 1; i < 7; i ++ ) { - const waveOffset = waveArray.element( index.sub( delayOffset.mul( sampleRate ).mul( i ) ).mul( pitch ) ); + const waveOffset = originalWave.element( index.sub( delayOffset.mul( sampleRate ).mul( i ) ).mul( pitch ) ); const waveOffsetVolume = waveOffset.mul( delayVolume.div( i * i ) ); wave = wave.add( waveOffsetVolume ); @@ -191,6 +196,7 @@ container.appendChild( renderer.domElement ); window.addEventListener( 'resize', onWindowResize ); + document.addEventListener( 'click', playAudioBuffer ); playAudioBuffer(); diff --git a/examples/webgpu_compute_birds.html b/examples/webgpu_compute_birds.html index c83d9e27bdfc11..abd99fe473729f 100644 --- a/examples/webgpu_compute_birds.html +++ b/examples/webgpu_compute_birds.html @@ -179,7 +179,7 @@ controls.connect( /* renderer.domElement */ ); // Initialize position, velocity, and phase values - + const positionArray = new Float32Array( BIRDS * 3 ); const velocityArray = new Float32Array( BIRDS * 3 ); const phaseArray = new Float32Array( BIRDS ); @@ -220,7 +220,7 @@ phaseStorage.setPBO( true ); // Define Uniforms. Uniforms only need to be defined once rather than per shader. - + effectController = { separation: uniform( 15.0 ).label( 'separation' ), alignment: uniform( 20.0 ).label( 'alignment' ), @@ -233,12 +233,12 @@ }; // Create geometry - + const birdGeometry = new BirdGeometry(); const birdMaterial = new THREE.NodeMaterial(); // Animate bird mesh within vertex shader, then apply position offset to vertices. - + const birdVertexTSL = Fn( () => { const reference = attribute( 'reference' ); @@ -247,12 +247,12 @@ const position = positionLocal.toVar(); const newPhase = phaseStorage.element( reference ).toVar(); const newVelocity = normalize( velocityStorage.element( reference ) ).toVar(); - + If( birdVertex.equal( 4 ).or( birdVertex.equal( 7 ) ), () => { // flap wings position.y = sin( newPhase ).mul( 5.0 ); - + } ); const newPosition = modelWorldMatrix.mul( position ); @@ -267,7 +267,7 @@ const cosrz = x.div( xyz ); const sinrz = newVelocity.y.div( xyz ).toVar(); - + // Nodes must be negated with negate(). Using '-', their values will resolve to NaN. const maty = mat3( cosry, 0, negate( sinry ), @@ -301,7 +301,7 @@ // Shaders are computationally identical to their GLSL counterparts outside of texture destructuring. computeVelocity = Fn( () => { - + // Define consts const PI = float( 3.141592653589793 ); const PI_2 = PI.mul( 2.0 ); @@ -351,7 +351,7 @@ const dirToBird = birdPosition.sub( position ); const distToBird = length( dirToBird ); - // Don't apply any changes to velocity if the distance to this bird is negligable. + // Don't apply any changes to velocity if the distance to this bird is negligible. If( distToBird.lessThan( 0.0001 ), () => { Continue(); @@ -372,7 +372,7 @@ const percent = distToBirdSq.div( zoneRadiusSq ); If( percent.lessThan( separationThresh ), () => { - + // Separation - Move apart for comfort const velocityAdjust = ( separationThresh.div( percent ).sub( 1.0 ) ).mul( deltaTime ); velocity.subAssign( normalize( dirToBird ).mul( velocityAdjust ) ); @@ -404,13 +404,13 @@ velocity.addAssign( normalize( dirToBird ).mul( velocityAdjust ) ); } ); - + } ); If( length( velocity ).greaterThan( limit ), () => { velocity.assign( normalize( velocity ).mul( limit ) ); - + } ); } )().compute( BIRDS ); diff --git a/examples/webgpu_compute_geometry.html b/examples/webgpu_compute_geometry.html index 06dfc1f251fa0c..2b43f0ac4bfe3f 100644 --- a/examples/webgpu_compute_geometry.html +++ b/examples/webgpu_compute_geometry.html @@ -137,10 +137,10 @@ // background const bgColor = screenUV.y.mix( color( 0x9f87f7 ), color( 0xf2cdcd ) ); - const bgVignet = screenUV.distance( .5 ).remapClamp( 0.3, .8 ).oneMinus(); + const bgVignette = screenUV.distance( .5 ).remapClamp( 0.3, .8 ).oneMinus(); const bgIntensity = 4; - scene.backgroundNode = bgColor.mul( bgVignet.mul( color( 0xa78ff6 ).mul( bgIntensity ) ) ); + scene.backgroundNode = bgColor.mul( bgVignette.mul( color( 0xa78ff6 ).mul( bgIntensity ) ) ); // model diff --git a/examples/webgpu_compute_particles_snow.html b/examples/webgpu_compute_particles_snow.html index 067d8fd07af957..a2d0ca07245d44 100644 --- a/examples/webgpu_compute_particles_snow.html +++ b/examples/webgpu_compute_particles_snow.html @@ -294,7 +294,7 @@ const scenePass = pass( scene, camera ); const scenePassColor = scenePass.getTextureNode(); - const vignet = screenUV.distance( .5 ).mul( 1.35 ).clamp().oneMinus(); + const vignette = screenUV.distance( .5 ).mul( 1.35 ).clamp().oneMinus(); const teapotTreePass = pass( teapotTree, camera ).getTextureNode(); const teapotTreePassBlurred = gaussianBlur( teapotTreePass, vec2( 1 ), 3 ); @@ -308,7 +308,7 @@ let totalPass = scenePass; totalPass = totalPass.add( scenePassColorBlurred.mul( .1 ) ); - totalPass = totalPass.mul( vignet ); + totalPass = totalPass.mul( vignette ); totalPass = totalPass.add( teapotTreePass.mul( 10 ).add( teapotTreePassBlurred ) ); postProcessing = new THREE.PostProcessing( renderer ); @@ -355,7 +355,7 @@ renderer.setRenderTarget( null ); await postProcessing.renderAsync(); - + stats.update(); } diff --git a/examples/webgpu_compute_sort_bitonic.html b/examples/webgpu_compute_sort_bitonic.html index c3204f5ed03765..48b2e08596c34e 100644 --- a/examples/webgpu_compute_sort_bitonic.html +++ b/examples/webgpu_compute_sort_bitonic.html @@ -55,7 +55,7 @@ + + + + \ No newline at end of file diff --git a/examples/webgpu_tsl_angular_slicing.html b/examples/webgpu_tsl_angular_slicing.html index 7d40ade585cb41..5cfb4c9e3a4cee 100644 --- a/examples/webgpu_tsl_angular_slicing.html +++ b/examples/webgpu_tsl_angular_slicing.html @@ -28,7 +28,7 @@ + + + + diff --git a/examples/webxr_vr_layers.html b/examples/webxr_vr_layers.html index 002af5108d1b96..37c12f8a1072d9 100644 --- a/examples/webxr_vr_layers.html +++ b/examples/webxr_vr_layers.html @@ -196,7 +196,7 @@ eyeCharts.add( snellenMeshMipMap ); // The layers don't participate depth testing between each other. Since the projection - // layer is rendered last, any 3D object will incorrecly overlap layers. To avoid this, + // layer is rendered last, any 3D object will incorrectly overlap layers. To avoid this, // invisible quads can be placed into the scene to participate in depth testing when the // projection layer is rendered. const dummyMeshLeft = new THREE.Mesh( @@ -305,7 +305,12 @@ const gl = renderer.getContext(); // Init layers once in immersive mode and video is ready. - if ( session && session.renderState.layers === undefined ) { + const useLayers = session && + session.enabledFeatures !== undefined && + session.enabledFeatures.includes('layers') && + XRMediaBinding !== undefined; + + if ( ! useLayers ) { errorMesh.visible = true; @@ -313,7 +318,7 @@ if ( session && - session.renderState.layers !== undefined && + useLayers && session.hasMediaLayer === undefined && video.readyState >= 2 ) { diff --git a/examples/webxr_xr_controls_transform.html b/examples/webxr_xr_controls_transform.html index 9451d13e92452f..7e535b08fa0346 100644 --- a/examples/webxr_xr_controls_transform.html +++ b/examples/webxr_xr_controls_transform.html @@ -1,7 +1,7 @@ - three.js xr - controls - trasnform + three.js xr - controls - transform diff --git a/examples/webxr_xr_haptics.html b/examples/webxr_xr_haptics.html index 511c64b3fc1263..a6580c792e818a 100644 --- a/examples/webxr_xr_haptics.html +++ b/examples/webxr_xr_haptics.html @@ -39,7 +39,7 @@ let controls, group; let audioCtx = null; - // minor pentatonic scale, so whichever notes is striked would be more pleasant + // minor pentatonic scale, so whichever notes is stricken would be more pleasant const musicScale = [ 0, 3, 5, 7, 10 ]; init(); diff --git a/manual/en/offscreencanvas.html b/manual/en/offscreencanvas.html index 30279c21c25c4d..260f82089c6788 100644 --- a/manual/en/offscreencanvas.html +++ b/manual/en/offscreencanvas.html @@ -815,6 +815,7 @@

    OffscreenCanvas

    'pointerType', 'clientX', 'clientY', + 'pointerId', 'pageX', 'pageY', ]); @@ -853,6 +854,10 @@

    OffscreenCanvas

    } function touchEventHandler(event, sendFn) { + // preventDefault() fixes mousemove, mouseup and mousedown + // firing when doing a simple touchup touchdown + // Happens only at offscreen canvas + event.preventDefault(); const touches = []; const data = {type: event.type, touches}; for (let i = 0; i < event.touches.length; ++i) { @@ -860,6 +865,8 @@

    OffscreenCanvas

    touches.push({ pageX: touch.pageX, pageY: touch.pageY, + clientX: touch.clientX, + clientY: touch.clientY, }); } sendFn(data); diff --git a/manual/en/post-processing.html b/manual/en/post-processing.html index f57c5b944d46d0..11009d14d3f0e0 100644 --- a/manual/en/post-processing.html +++ b/manual/en/post-processing.html @@ -154,10 +154,10 @@

    renderToScree

    Looking inside BloomPass.js I found this line:

    -
    this.copyUniforms[ "opacity" ].value = strength;
    +
    this.combineUniforms[ 'strength' ].value = strength;
     

    So we can set the strength by setting

    -
    bloomPass.copyUniforms.opacity.value = someValue;
    +
    bloomPass.combineUniforms.strength.value = someValue;
     

    Similarly looking in FilmPass.js @@ -173,7 +173,7 @@

    renderToScree
    const gui = new GUI();
     {
       const folder = gui.addFolder('BloomPass');
    -  folder.add(bloomPass.copyUniforms.opacity, 'value', 0, 2).name('strength');
    +  folder.add(bloomPass.combineUniforms.strength, 'value', 0, 2).name('strength');
       folder.open();
     }
     {
    @@ -283,4 +283,4 @@ 

    renderToScree - \ No newline at end of file + diff --git a/manual/examples/fog-gui.html b/manual/examples/fog-gui.html index 3b55e97be5eabb..56d6e2f13d3802 100644 --- a/manual/examples/fog-gui.html +++ b/manual/examples/fog-gui.html @@ -51,7 +51,7 @@ // We use this class to pass to lil-gui // so when it manipulates near or far // near is never > far and far is never < near - // Also when lil-gui maniplates color we'll + // Also when lil-gui manipulates color we'll // update both the fog and background colors. class FogGUIHelper { diff --git a/manual/examples/offscreencanvas-w-orbitcontrols.html b/manual/examples/offscreencanvas-w-orbitcontrols.html index 56fe3c9b35d67a..099cd34a35fb23 100644 --- a/manual/examples/offscreencanvas-w-orbitcontrols.html +++ b/manual/examples/offscreencanvas-w-orbitcontrols.html @@ -34,6 +34,7 @@ 'pointerType', 'clientX', 'clientY', + 'pointerId', 'pageX', 'pageY', ] ); @@ -84,7 +85,11 @@ } function touchEventHandler( event, sendFn ) { - + + // preventDefault() fixes mousemove, mouseup and mousedown + // firing at touch events when doing a simple touchup touchdown + // Happens only at offscreen canvas + event.preventDefault(); const touches = []; const data = { type: event.type, touches }; for ( let i = 0; i < event.touches.length; ++ i ) { @@ -93,6 +98,8 @@ touches.push( { pageX: touch.pageX, pageY: touch.pageY, + clientX: touch.clientX, + clientY: touch.clientY, } ); } diff --git a/manual/ja/offscreencanvas.html b/manual/ja/offscreencanvas.html index 997f329f0f8dd1..cd1d363e2276d2 100644 --- a/manual/ja/offscreencanvas.html +++ b/manual/ja/offscreencanvas.html @@ -767,6 +767,7 @@

    のOffscreenCanvas

    'pointerType', 'clientX', 'clientY', + 'pointerId', 'pageX', 'pageY', ]); @@ -805,6 +806,10 @@

    のOffscreenCanvas

    } function touchEventHandler(event, sendFn) { + // preventDefault() fixes mousemove, mouseup and mousedown + // firing when doing a simple touchup touchdown + // Happens only at offscreen canvas + event.preventDefault(); const touches = []; const data = {type: event.type, touches}; for (let i = 0; i < event.touches.length; ++i) { @@ -812,6 +817,8 @@

    のOffscreenCanvas

    touches.push({ pageX: touch.pageX, pageY: touch.pageY, + clientX: touch.clientX, + clientY: touch.clientY, }); } sendFn(data); diff --git a/manual/ko/offscreencanvas.html b/manual/ko/offscreencanvas.html index c9d3d87cdb68bd..3b3a64462d0c3e 100644 --- a/manual/ko/offscreencanvas.html +++ b/manual/ko/offscreencanvas.html @@ -717,6 +717,7 @@

    OffscreenCanvas

    'pointerType', 'clientX', 'clientY', + 'pointerId', 'pageX', 'pageY', ]); @@ -755,6 +756,10 @@

    OffscreenCanvas

    } function touchEventHandler(event, sendFn) { + // preventDefault() fixes mousemove, mouseup and mousedown + // firing when doing a simple touchup touchdown + // Happens only at offscreen canvas + event.preventDefault(); const touches = []; const data = { type: event.type, touches }; for (let i = 0; i < event.touches.length; ++i) { @@ -762,6 +767,8 @@

    OffscreenCanvas

    touches.push({ pageX: touch.pageX, pageY: touch.pageY, + clientX: touch.clientX, + clientY: touch.clientY, }); } sendFn(data); diff --git a/manual/resources/threejs-material-table.js b/manual/resources/threejs-material-table.js index cfe5552b74ea8d..c6ba1d49c6f47f 100644 --- a/manual/resources/threejs-material-table.js +++ b/manual/resources/threejs-material-table.js @@ -9,6 +9,8 @@ const materials = [ 'color', 'combine', 'envMap', + 'envMapRotation', + 'fog', 'lightMap', 'lightMapIntensity', 'map', @@ -16,6 +18,9 @@ const materials = [ 'refractionRatio', 'specularMap', 'wireframe', + 'wireframeLinecap', + 'wireframeLinejoin', + 'wireframeLinewidth' ], }, { @@ -29,13 +34,16 @@ const materials = [ 'bumpScale', 'color', 'combine', + 'displacementBias', 'displacementMap', 'displacementScale', - 'displacementBias', 'emissive', - 'emissiveMap', 'emissiveIntensity', + 'emissiveMap', 'envMap', + 'envMapRotation', + 'flatShading', + 'fog', 'lightMap', 'lightMapIntensity', 'map', @@ -46,6 +54,9 @@ const materials = [ 'refractionRatio', 'specularMap', 'wireframe', + 'wireframeLinecap', + 'wireframeLinejoin', + 'wireframeLinewidth' ], }, { @@ -59,13 +70,16 @@ const materials = [ 'bumpScale', 'color', 'combine', + 'displacementBias', 'displacementMap', 'displacementScale', - 'displacementBias', 'emissive', - 'emissiveMap', 'emissiveIntensity', + 'emissiveMap', 'envMap', + 'envMapRotation', + 'flatShading', + 'fog', 'lightMap', 'lightMapIntensity', 'map', @@ -78,6 +92,9 @@ const materials = [ 'specular', 'specularMap', 'wireframe', + 'wireframeLinecap', + 'wireframeLinejoin', + 'wireframeLinewidth' ], }, { @@ -90,14 +107,17 @@ const materials = [ 'bumpMap', 'bumpScale', 'color', + 'displacementBias', 'displacementMap', 'displacementScale', - 'displacementBias', 'emissive', - 'emissiveMap', 'emissiveIntensity', + 'emissiveMap', 'envMap', 'envMapIntensity', + 'envMapRotation', + 'flatShading', + 'fog', 'lightMap', 'lightMapIntensity', 'map', @@ -106,10 +126,12 @@ const materials = [ 'normalMap', 'normalMapType', 'normalScale', - 'refractionRatio', 'roughness', 'roughnessMap', 'wireframe', + 'wireframeLinecap', + 'wireframeLinejoin', + 'wireframeLinewidth' ], }, { @@ -119,38 +141,46 @@ const materials = [ 'alphaMap', 'aoMap', 'aoMapIntensity', + 'anisotropy', + 'anisotropyRotation', + 'anisotropyMap', + 'attenuationColor', + 'attenuationDistance', 'bumpMap', 'bumpScale', 'clearcoat', 'clearcoatMap', + 'clearcoatNormalMap', + 'clearcoatNormalScale', 'clearcoatRoughness', 'clearcoatRoughnessMap', - 'clearcoatNormalScale', - 'clearcoatNormalMap', 'color', + 'displacementBias', 'displacementMap', 'displacementScale', - 'displacementBias', 'emissive', - 'emissiveMap', 'emissiveIntensity', + 'emissiveMap', 'envMap', 'envMapIntensity', + 'envMapRotation', + 'flatShading', + 'fog', + 'ior', 'iridescence', - 'iridescenceMap', 'iridescenceIOR', - 'iridescenceThicknessRange', + 'iridescenceMap', 'iridescenceThicknessMap', + 'iridescenceThicknessRange', 'lightMap', 'lightMapIntensity', - 'ior', 'map', 'metalness', 'metalnessMap', 'normalMap', 'normalMapType', 'normalScale', - 'refractionRatio', + 'reflectivity', 'roughness', 'roughnessMap', 'sheen', @@ -158,31 +188,28 @@ const materials = [ 'sheenColorMap', 'sheenRoughness', 'sheenRoughnessMap', + 'specularColor', + 'specularColorMap', + 'specularIntensity', + 'specularIntensityMap', 'thickness', 'thicknessMap', 'transmission', 'transmissionMap', - 'attenuationDistance', - 'attenuationColor', - 'anisotropy', - 'anisotropyRotation', - 'anisotropyMap', - 'specularIntensity', - 'specularIntensityMap', - 'specularColor', - 'specularColorMap', 'wireframe', - 'reflectivity', + 'wireframeLinecap', + 'wireframeLinejoin', + 'wireframeLinewidth' ], }, ]; -const allProperties = {}; +const allProperties = new Set(); materials.forEach( ( material ) => { material.properties.forEach( ( property ) => { - allProperties[ property ] = true; + allProperties.add( property ); } ); @@ -222,7 +249,7 @@ const thead = addElem( 'thead', table ); } -Object.keys( allProperties ).sort().forEach( ( property ) => { +Array.from( allProperties ).sort().forEach( ( property ) => { const tr = addElem( 'tr', table ); addElem( 'td', tr, property ); diff --git a/manual/resources/threejs-textures.js b/manual/resources/threejs-textures.js index 3321a3559b70fb..0340b075201844 100644 --- a/manual/resources/threejs-textures.js +++ b/manual/resources/threejs-textures.js @@ -196,7 +196,7 @@ import { threejsLessonUtils } from './threejs-lesson-utils.js'; // but no checks for mipmaps I'm guessing. It seems like // they shouldn't be checking for same image, the should be // checking for same WebGLTexture. Given there is more than - // WebGL to support maybe they need to abtract WebGLTexture to + // WebGL to support maybe they need to abstract WebGLTexture to // PlatformTexture or something? const meshInfos = [ diff --git a/manual/resources/tools/geo-picking/shapefile.js b/manual/resources/tools/geo-picking/shapefile.js index 206755057fd2eb..a8acf84a43c823 100644 --- a/manual/resources/tools/geo-picking/shapefile.js +++ b/manual/resources/tools/geo-picking/shapefile.js @@ -97,7 +97,7 @@ var slice_slice = function(length) { return (function read() { return that._source.read().then(function(result) { - // When done, it’s possible the request wasn’t fully fullfilled! + // When done, it’s possible the request wasn’t fully fulfilled! // If so, the pre-allocated array is too big and needs slicing. if (result.done) { that._array = empty; diff --git a/manual/ru/offscreencanvas.html b/manual/ru/offscreencanvas.html index d2c091239dbe23..3e8edf4b2756e8 100644 --- a/manual/ru/offscreencanvas.html +++ b/manual/ru/offscreencanvas.html @@ -748,6 +748,7 @@

    OffscreenCanvas

    'pointerType', 'clientX', 'clientY', + 'pointerId', 'pageX', 'pageY', ]); @@ -786,6 +787,10 @@

    OffscreenCanvas

    } function touchEventHandler(event, sendFn) { + // preventDefault() fixes mousemove, mouseup and mousedown + // firing when doing a simple touchup touchdown + // Happens only at offscreen canvas + event.preventDefault(); const touches = []; const data = {type: event.type, touches}; for (let i = 0; i < event.touches.length; ++i) { @@ -793,6 +798,8 @@

    OffscreenCanvas

    touches.push({ pageX: touch.pageX, pageY: touch.pageY, + clientX: touch.clientX, + clientY: touch.clientY, }); } sendFn(data); diff --git a/manual/zh/shadertoy.html b/manual/zh/shadertoy.html index 61a695c36a772f..026b6d3c6761c1 100644 --- a/manual/zh/shadertoy.html +++ b/manual/zh/shadertoy.html @@ -62,9 +62,9 @@

    Three.js 与 Shadertoy

    class="notranslate" translate="no">vec4
    , vec2,vec3 这三种特定类型。 一个 vec2 有2个value, 一个 vec3 - 有3个value,一个vec4 有4个 values。他们的使用方法非常灵活。最常见的一种是通过 vec4 有4个 values。他们的使用方法非常灵活。最常见的用法是使用 x, y, z, 以及w 表示向里。

    + class="notranslate" translate="no">z
    , 以及w 例如:

    vec4 v1 = vec4(1.0, 2.0, 3.0, 4.0);
     float v2 = v1.x + v1.y;  // adds 1.0 + 2.0
     
    diff --git a/package-lock.json b/package-lock.json index ac653365beb1e5..9d81acac5f3a01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "three", - "version": "0.171.0", + "version": "0.172.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "three", - "version": "0.171.0", + "version": "0.172.0", "license": "MIT", "devDependencies": { - "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-node-resolve": "^16.0.0", "@rollup/plugin-terser": "^0.4.0", "chalk": "^5.2.0", "clean-jsdoc-theme": "^4.3.0", @@ -66,12 +66,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", "dev": true, "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -92,16 +92,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime/node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true - }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -273,18 +267,6 @@ "node": ">=18" } }, - "node_modules/@jimp/core/node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/@jimp/diff": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@jimp/diff/-/diff-1.6.0.tgz", @@ -701,9 +683,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -759,9 +741,9 @@ } }, "node_modules/@jsdoc/salty": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.8.tgz", - "integrity": "sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", + "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", "dev": true, "dependencies": { "lodash": "^4.17.21" @@ -771,9 +753,9 @@ } }, "node_modules/@mdn/browser-compat-data": { - "version": "5.6.11", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.6.11.tgz", - "integrity": "sha512-kJUu7JcRSOf3uEs0jK0RZCckaBfjhtWpgKyJUyAk8LRlQl9Yj/R/ddwfjo37dfzkvNYtHvH4Eg+NFkTDzd08Eg==", + "version": "5.6.26", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.6.26.tgz", + "integrity": "sha512-7NdgdOR7lkzrN70zGSULmrcvKyi/aJjpTJRCbuy8IZuHiLkPTvsr10jW0MJgWzK2l2wTmhdQvegTw6yNU5AVNQ==", "dev": true }, "node_modules/@nodelib/fs.scandir": { @@ -996,9 +978,9 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.0.tgz", - "integrity": "sha512-9eO5McEICxMzJpDW9OnMYSv4Sta3hmt7VtBFz5zR9273suNOydOyq/FrGeGy+KsTRFm8w0SLVhzig2ILFT63Ag==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.0.tgz", + "integrity": "sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -1042,9 +1024,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", - "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", + "integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==", "dev": true, "dependencies": { "@types/estree": "^1.0.0", @@ -1064,9 +1046,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.28.0.tgz", - "integrity": "sha512-wLJuPLT6grGZsy34g4N1yRfYeouklTgPhH1gWXCYspenKYD0s3cR99ZevOGw5BexMNywkbV3UkjADisozBmpPQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", + "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", "cpu": [ "arm" ], @@ -1078,9 +1060,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.28.0.tgz", - "integrity": "sha512-eiNkznlo0dLmVG/6wf+Ifi/v78G4d4QxRhuUl+s8EWZpDewgk7PX3ZyECUXU0Zq/Ca+8nU8cQpNC4Xgn2gFNDA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", + "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", "cpu": [ "arm64" ], @@ -1092,9 +1074,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.28.0.tgz", - "integrity": "sha512-lmKx9yHsppblnLQZOGxdO66gT77bvdBtr/0P+TPOseowE7D9AJoBw8ZDULRasXRWf1Z86/gcOdpBrV6VDUY36Q==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", + "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", "cpu": [ "arm64" ], @@ -1106,9 +1088,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.28.0.tgz", - "integrity": "sha512-8hxgfReVs7k9Js1uAIhS6zq3I+wKQETInnWQtgzt8JfGx51R1N6DRVy3F4o0lQwumbErRz52YqwjfvuwRxGv1w==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", + "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", "cpu": [ "x64" ], @@ -1120,9 +1102,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.28.0.tgz", - "integrity": "sha512-lA1zZB3bFx5oxu9fYud4+g1mt+lYXCoch0M0V/xhqLoGatbzVse0wlSQ1UYOWKpuSu3gyN4qEc0Dxf/DII1bhQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", + "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", "cpu": [ "arm64" ], @@ -1134,9 +1116,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.28.0.tgz", - "integrity": "sha512-aI2plavbUDjCQB/sRbeUZWX9qp12GfYkYSJOrdYTL/C5D53bsE2/nBPuoiJKoWp5SN78v2Vr8ZPnB+/VbQ2pFA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", + "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", "cpu": [ "x64" ], @@ -1148,9 +1130,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.28.0.tgz", - "integrity": "sha512-WXveUPKtfqtaNvpf0iOb0M6xC64GzUX/OowbqfiCSXTdi/jLlOmH0Ba94/OkiY2yTGTwteo4/dsHRfh5bDCZ+w==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", + "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", "cpu": [ "arm" ], @@ -1162,9 +1144,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.28.0.tgz", - "integrity": "sha512-yLc3O2NtOQR67lI79zsSc7lk31xjwcaocvdD1twL64PK1yNaIqCeWI9L5B4MFPAVGEVjH5k1oWSGuYX1Wutxpg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", + "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", "cpu": [ "arm" ], @@ -1176,9 +1158,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.28.0.tgz", - "integrity": "sha512-+P9G9hjEpHucHRXqesY+3X9hD2wh0iNnJXX/QhS/J5vTdG6VhNYMxJ2rJkQOxRUd17u5mbMLHM7yWGZdAASfcg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", + "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", "cpu": [ "arm64" ], @@ -1190,9 +1172,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.28.0.tgz", - "integrity": "sha512-1xsm2rCKSTpKzi5/ypT5wfc+4bOGa/9yI/eaOLW0oMs7qpC542APWhl4A37AENGZ6St6GBMWhCCMM6tXgTIplw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", + "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", "cpu": [ "arm64" ], @@ -1203,10 +1185,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", + "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.28.0.tgz", - "integrity": "sha512-zgWxMq8neVQeXL+ouSf6S7DoNeo6EPgi1eeqHXVKQxqPy1B2NvTbaOUWPn/7CfMKL7xvhV0/+fq/Z/J69g1WAQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", + "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", "cpu": [ "ppc64" ], @@ -1218,9 +1214,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.28.0.tgz", - "integrity": "sha512-VEdVYacLniRxbRJLNtzwGt5vwS0ycYshofI7cWAfj7Vg5asqj+pt+Q6x4n+AONSZW/kVm+5nklde0qs2EUwU2g==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", + "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", "cpu": [ "riscv64" ], @@ -1232,9 +1228,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.28.0.tgz", - "integrity": "sha512-LQlP5t2hcDJh8HV8RELD9/xlYtEzJkm/aWGsauvdO2ulfl3QYRjqrKW+mGAIWP5kdNCBheqqqYIGElSRCaXfpw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", + "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", "cpu": [ "s390x" ], @@ -1246,9 +1242,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.28.0.tgz", - "integrity": "sha512-Nl4KIzteVEKE9BdAvYoTkW19pa7LR/RBrT6F1dJCV/3pbjwDcaOq+edkP0LXuJ9kflW/xOK414X78r+K84+msw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", + "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", "cpu": [ "x64" ], @@ -1260,9 +1256,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.28.0.tgz", - "integrity": "sha512-eKpJr4vBDOi4goT75MvW+0dXcNUqisK4jvibY9vDdlgLx+yekxSm55StsHbxUsRxSTt3JEQvlr3cGDkzcSP8bw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", + "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", "cpu": [ "x64" ], @@ -1274,9 +1270,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.28.0.tgz", - "integrity": "sha512-Vi+WR62xWGsE/Oj+mD0FNAPY2MEox3cfyG0zLpotZdehPFXwz6lypkGs5y38Jd/NVSbOD02aVad6q6QYF7i8Bg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", + "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", "cpu": [ "arm64" ], @@ -1288,9 +1284,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.28.0.tgz", - "integrity": "sha512-kN/Vpip8emMLn/eOza+4JwqDZBL6MPNpkdaEsgUtW1NYN3DZvZqSQrbKzJcTL6hd8YNmFTn7XGWMwccOcJBL0A==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", + "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", "cpu": [ "ia32" ], @@ -1302,9 +1298,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.28.0.tgz", - "integrity": "sha512-Bvno2/aZT6usSa7lRDL2+hMjVAGjuqaymF1ApZm31JXzniR/hvr14jpU+/z4X6Gt5BPlzosscyJZGUvguXIqeQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", + "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", "cpu": [ "x64" ], @@ -1625,9 +1621,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", "dev": true }, "node_modules/abbrev": { @@ -1680,21 +1676,18 @@ } }, "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, "engines": { "node": ">= 14" } }, "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", "dev": true, "dependencies": { "humanize-ms": "^1.2.1" @@ -1824,13 +1817,13 @@ "dev": true }, "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" @@ -1886,15 +1879,15 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -1904,15 +1897,15 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -1922,19 +1915,18 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -1944,12 +1936,12 @@ } }, "node_modules/ast-metadata-inferer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.8.0.tgz", - "integrity": "sha512-jOMKcHht9LxYIEQu+RVd22vtgrPaVCtDRQ/16IGmurdzxvYbDd5ynxjnyrzLnieG96eTcAyaoj/wN/4/1FyyeA==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.8.1.tgz", + "integrity": "sha512-ht3Dm6Zr7SXv6t1Ra6gFo0+kLDglHGrEbYihTkcycrbHw7WCcuhBzPlJYHEsIpycaUwzsJHje+vUcxXUX4ztTA==", "dev": true, "dependencies": { - "@mdn/browser-compat-data": "^5.2.34" + "@mdn/browser-compat-data": "^5.6.19" } }, "node_modules/ast-types": { @@ -2037,13 +2029,13 @@ } }, "node_modules/bare-stream": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.2.tgz", - "integrity": "sha512-EFZHSIBkDgSHIwj2l2QZfP4U5OcD4xFAOwhSb/vlr9PIqyGJGvB/nfClJbcnh3EY4jtPE4zsb5ztae96bVF79A==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.1.tgz", + "integrity": "sha512-eVZbtKM+4uehzrsj49KtCy3Pbg7kO1pJ3SKZ1SFrIH/0pnj9scuGGgUlNDf/7qS8WKtGdiJY5Kyhs/ivYPTB/g==", "dev": true, "optional": true, "dependencies": { - "streamx": "^2.20.0" + "streamx": "^2.21.0" } }, "node_modules/base64-js": { @@ -2298,9 +2290,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "version": "4.24.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.3.tgz", + "integrity": "sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==", "dev": true, "funding": [ { @@ -2317,9 +2309,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { @@ -2410,16 +2402,44 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -2460,9 +2480,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001676", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz", - "integrity": "sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==", + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", "dev": true, "funding": [ { @@ -2492,9 +2512,9 @@ } }, "node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -2526,6 +2546,15 @@ "devtools-protocol": "*" } }, + "node_modules/chromium-bidi/node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/clean-css": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", @@ -2555,20 +2584,6 @@ "jsdoc": ">=3.x <=4.x" } }, - "node_modules/clean-jsdoc-theme/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -2726,12 +2741,12 @@ } }, "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, "engines": { - "node": ">= 10" + "node": ">=14" } }, "node_modules/concat-map": { @@ -2741,11 +2756,10 @@ "dev": true }, "node_modules/concurrently": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.0.tgz", - "integrity": "sha512-VxkzwMAn4LP7WyMnJNbHN5mKV9L2IbyDjpzemKr99sXNR3GqRNMMHdm7prV1ws9wg7ETj6WUkNOigZVsptwbgg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz", + "integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.1.2", "lodash": "^4.17.21", @@ -2771,7 +2785,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2787,7 +2800,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2804,7 +2816,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2894,9 +2905,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -2917,14 +2928,14 @@ } }, "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2934,29 +2945,29 @@ } }, "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/inspect-js" } }, "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" }, @@ -2968,9 +2979,9 @@ } }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "dependencies": { "ms": "^2.1.3" @@ -3153,9 +3164,9 @@ } }, "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.1.tgz", + "integrity": "sha512-xWXmuRnN9OMP6ptPd2+H0cCbcYBULa5YDTbMm/2lvkWvNA3O4wcW+GvzooqBuNM8yy6pl3VIAeJTUUWUbfI5Fw==", "dev": true, "dependencies": { "dom-serializer": "^2.0.0", @@ -3225,6 +3236,20 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/dpdm/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/dpdm/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3237,6 +3262,20 @@ "node": ">=8" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -3256,9 +3295,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.5.49", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.49.tgz", - "integrity": "sha512-ZXfs1Of8fDb6z7WEYZjXpgIRF6MEu8JdeGA0A40aZq6OQbS+eJpnnV49epZRna2DU/YsEjSQuGtQPPtvt6J65A==", + "version": "1.5.76", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz", + "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==", "dev": true }, "node_modules/emoji-regex": { @@ -3332,57 +3371,60 @@ } }, "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "version": "1.23.8", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.8.tgz", + "integrity": "sha512-lfab8IzDn6EpI1ibZakcgS6WsfEBiB+43cuJo+wgylx1xKXf+Sp+YR3vFuQwC/u3sxYwV8Cxe3B0DpVUu/WiJQ==", "dev": true, "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.6", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", + "object.assign": "^4.1.7", + "own-keys": "^1.0.0", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" }, "engines": { "node": ">= 0.4" @@ -3392,13 +3434,10 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -3448,14 +3487,14 @@ } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -3621,15 +3660,15 @@ } }, "node_modules/eslint-plugin-compat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.0.1.tgz", - "integrity": "sha512-0MeIEuoy8kWkOhW38kK8hU4vkb6l/VvyjpuYDymYOXmUY9NvTgyErF16lYuX+HPS5hkmym7lfA+XpYZiWYWmYA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.0.2.tgz", + "integrity": "sha512-1ME+YfJjmOz1blH0nPZpHgjMGK4kjgEeoYqGCqoBPQ/mGu/dJzdoP0f1C8H2jcWZjzhZjAMccbM/VdXhPORIfA==", "dev": true, "dependencies": { "@mdn/browser-compat-data": "^5.5.35", - "ast-metadata-inferer": "^0.8.0", - "browserslist": "^4.23.1", - "caniuse-lite": "^1.0.30001639", + "ast-metadata-inferer": "^0.8.1", + "browserslist": "^4.24.2", + "caniuse-lite": "^1.0.30001687", "find-up": "^5.0.0", "globals": "^15.7.0", "lodash.memoize": "^4.1.2", @@ -3643,9 +3682,9 @@ } }, "node_modules/eslint-plugin-compat/node_modules/globals": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", - "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", "dev": true, "engines": { "node": ">=18" @@ -3900,9 +3939,9 @@ "dev": true }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "dependencies": { "accepts": "~1.3.8", @@ -3924,7 +3963,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -3939,6 +3978,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/debug": { @@ -4081,9 +4124,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", + "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -4200,9 +4243,9 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true }, "node_modules/for-each": { @@ -4249,9 +4292,9 @@ } }, "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -4259,7 +4302,7 @@ "universalify": "^2.0.0" }, "engines": { - "node": ">=14.14" + "node": ">=12" } }, "node_modules/fs-minipass": { @@ -4304,15 +4347,17 @@ } }, "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -4386,16 +4431,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", + "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", "dev": true, "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -4420,14 +4470,14 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -4437,15 +4487,14 @@ } }, "node_modules/get-uri": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", - "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", + "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", "dev": true, "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", - "debug": "^4.3.4", - "fs-extra": "^11.2.0" + "debug": "^4.3.4" }, "engines": { "node": ">= 14" @@ -4561,12 +4610,12 @@ "dev": true }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4606,10 +4655,13 @@ "dev": true }, "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4636,10 +4688,13 @@ } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -4648,9 +4703,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "engines": { "node": ">= 0.4" @@ -4693,9 +4748,9 @@ } }, "node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.3.tgz", + "integrity": "sha512-HVJyzUrLIL1c0QmviVh5E8VGyUS7xCFPS6yydaVd1UegW+ibV/CohqTH9MkOLDp5o+rb82DMo77PTuc9F/8GKw==", "dev": true, "dependencies": { "lru-cache": "^7.5.1" @@ -4734,15 +4789,6 @@ "node": "^14.13.1 || >=16.0.0" } }, - "node_modules/html-minifier-terser/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true, - "engines": { - "node": ">=14" - } - }, "node_modules/htmlparser2": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", @@ -4798,12 +4844,12 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { @@ -4964,14 +5010,14 @@ "dev": true }, "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, "dependencies": { "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5000,13 +5046,14 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -5021,26 +5068,44 @@ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz", + "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5062,9 +5127,9 @@ } }, "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "dependencies": { "hasown": "^2.0.2" @@ -5077,11 +5142,13 @@ } }, "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" }, "engines": { @@ -5092,12 +5159,13 @@ } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5130,6 +5198,21 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -5139,10 +5222,25 @@ "node": ">=8" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" @@ -5166,16 +5264,10 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true - }, - "node_modules/is-negative-zero": { + "node_modules/is-map": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, "engines": { "node": ">= 0.4" @@ -5184,13 +5276,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5209,13 +5308,15 @@ } }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -5224,13 +5325,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, "dependencies": { - "call-bind": "^1.0.7" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -5240,12 +5353,13 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5255,12 +5369,14 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5270,12 +5386,12 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, "dependencies": { - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -5296,13 +5412,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz", + "integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5682,11 +5829,10 @@ "dev": true }, "node_modules/magic-string": { - "version": "0.30.14", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", - "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -5962,6 +6108,15 @@ "node": ">= 12" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", @@ -5996,15 +6151,15 @@ } }, "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", "dev": true, "bin": { "mime": "cli.js" }, "engines": { - "node": ">=4" + "node": ">=10.0.0" } }, "node_modules/mime-db": { @@ -6353,9 +6508,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true }, "node_modules/node-watch": { @@ -6639,9 +6794,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, "engines": { "node": ">= 0.4" @@ -6660,14 +6815,16 @@ } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -6710,12 +6867,13 @@ } }, "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, @@ -6868,6 +7026,23 @@ "node": ">=8" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -6914,19 +7089,19 @@ } }, "node_modules/pac-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", - "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.1.0.tgz", + "integrity": "sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==", "dev": true, "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.5", + "https-proxy-agent": "^7.0.6", "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.4" + "socks-proxy-agent": "^8.0.5" }, "engines": { "node": ">= 14" @@ -7129,9 +7304,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true }, "node_modules/peek-readable": { @@ -7261,19 +7436,19 @@ } }, "node_modules/proxy-agent": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", - "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", "dev": true, "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.1", - "https-proxy-agent": "^7.0.3", + "https-proxy-agent": "^7.0.6", "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.1", + "pac-proxy-agent": "^7.1.0", "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.2" + "socks-proxy-agent": "^8.0.5" }, "engines": { "node": ">= 14" @@ -7399,9 +7574,9 @@ "dev": true }, "node_modules/qunit": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/qunit/-/qunit-2.22.0.tgz", - "integrity": "sha512-wPYvAvpjTL3zlUeyCX75T8gfZfdVXZa8y1EVkGe/XZNORIsCH/WI2X8R2KlemT921X9EKSZUL6CLGSPC7Ks08g==", + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/qunit/-/qunit-2.23.1.tgz", + "integrity": "sha512-CGrsGy7NhkQmfiyOixBpbexh2PT7ekIb35uWiBi/hBNdTJF1W98UonyACFJJs8UmcP96lH+YJlX99dYZi5rZkg==", "dev": true, "dependencies": { "commander": "7.2.0", @@ -7415,6 +7590,15 @@ "node": ">=10" } }, + "node_modules/qunit/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -7537,6 +7721,34 @@ "url": "https://github.com/sponsors/Borewit" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz", + "integrity": "sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "dunder-proto": "^1.0.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, "node_modules/regexp.prototype.flags": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", @@ -7583,18 +7795,21 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7684,9 +7899,9 @@ } }, "node_modules/rollup": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.28.0.tgz", - "integrity": "sha512-G9GOrmgWHBma4YfCcX8PjH0qhXSdH8B4HDE2o4/jaxj93S4DPCIDoLcXz99eWMji4hB29UFCEd7B2gwGJDR9cQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", + "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", "dev": true, "license": "MIT", "dependencies": { @@ -7700,24 +7915,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.28.0", - "@rollup/rollup-android-arm64": "4.28.0", - "@rollup/rollup-darwin-arm64": "4.28.0", - "@rollup/rollup-darwin-x64": "4.28.0", - "@rollup/rollup-freebsd-arm64": "4.28.0", - "@rollup/rollup-freebsd-x64": "4.28.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.28.0", - "@rollup/rollup-linux-arm-musleabihf": "4.28.0", - "@rollup/rollup-linux-arm64-gnu": "4.28.0", - "@rollup/rollup-linux-arm64-musl": "4.28.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.28.0", - "@rollup/rollup-linux-riscv64-gnu": "4.28.0", - "@rollup/rollup-linux-s390x-gnu": "4.28.0", - "@rollup/rollup-linux-x64-gnu": "4.28.0", - "@rollup/rollup-linux-x64-musl": "4.28.0", - "@rollup/rollup-win32-arm64-msvc": "4.28.0", - "@rollup/rollup-win32-ia32-msvc": "4.28.0", - "@rollup/rollup-win32-x64-msvc": "4.28.0", + "@rollup/rollup-android-arm-eabi": "4.30.1", + "@rollup/rollup-android-arm64": "4.30.1", + "@rollup/rollup-darwin-arm64": "4.30.1", + "@rollup/rollup-darwin-x64": "4.30.1", + "@rollup/rollup-freebsd-arm64": "4.30.1", + "@rollup/rollup-freebsd-x64": "4.30.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", + "@rollup/rollup-linux-arm-musleabihf": "4.30.1", + "@rollup/rollup-linux-arm64-gnu": "4.30.1", + "@rollup/rollup-linux-arm64-musl": "4.30.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", + "@rollup/rollup-linux-riscv64-gnu": "4.30.1", + "@rollup/rollup-linux-s390x-gnu": "4.30.1", + "@rollup/rollup-linux-x64-gnu": "4.30.1", + "@rollup/rollup-linux-x64-musl": "4.30.1", + "@rollup/rollup-win32-arm64-msvc": "4.30.1", + "@rollup/rollup-win32-ia32-msvc": "4.30.1", + "@rollup/rollup-win32-x64-msvc": "4.30.1", "fsevents": "~2.3.2" } }, @@ -7741,13 +7957,14 @@ } }, "node_modules/rollup-plugin-visualizer": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz", - "integrity": "sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.14.0.tgz", + "integrity": "sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==", "dev": true, + "license": "MIT", "dependencies": { "open": "^8.4.0", - "picomatch": "^2.3.1", + "picomatch": "^4.0.2", "source-map": "^0.7.4", "yargs": "^17.5.1" }, @@ -7755,34 +7972,27 @@ "rollup-plugin-visualizer": "dist/bin/cli.js" }, "engines": { - "node": ">=14" + "node": ">=18" }, "peerDependencies": { + "rolldown": "1.x", "rollup": "2.x || 3.x || 4.x" }, "peerDependenciesMeta": { + "rolldown": { + "optional": true + }, "rollup": { "optional": true } } }, - "node_modules/rollup-plugin-visualizer/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/rollup-plugin-visualizer/node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">= 8" } @@ -7820,14 +8030,15 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, "engines": { @@ -7857,15 +8068,31 @@ } ] }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "is-regex": "^1.1.4" + "is-regex": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -7965,6 +8192,18 @@ "node": ">= 0.8" } }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -8074,30 +8313,30 @@ "dev": true }, "node_modules/servez": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/servez/-/servez-2.2.4.tgz", - "integrity": "sha512-HcsVAEnEvDq5WH9kLQBK6SvykTRFllX052b34k5mCs/XpwTXdxYyf4+1pCJdHenLb1gGuEZzcm5HdHRdVciBHA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/servez/-/servez-2.3.0.tgz", + "integrity": "sha512-47Et/S+wuVwO2qsNMT/MhVNLvlBJD6sr+qQxTdvNoWOEzDRPfdQWSy6qjWUHWd70n39HoVLAvfPhWAFlgVMbvQ==", "dev": true, "dependencies": { "ansi-colors": "^4.1.3", "color-support": "^1.1.3", "commander": "^12.1.0", - "servez-lib": "^2.9.5" + "servez-lib": "^2.10.0" }, "bin": { "servez": "bin/servez" } }, "node_modules/servez-lib": { - "version": "2.9.5", - "resolved": "https://registry.npmjs.org/servez-lib/-/servez-lib-2.9.5.tgz", - "integrity": "sha512-ET3M1Vd4v6a0uz2bQBsZ/fOS8Mmx0GLWYr4cPVKA/QNKLrrBfnzHVkIR3wRxxsC8kU11jS93HTu8zOkZAp1wBw==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/servez-lib/-/servez-lib-2.10.0.tgz", + "integrity": "sha512-QLh3bXMBljYRajszb0f5gp5W3aJg/8LSfHY5UYY+fzWt4+egDr21ZnKUrzEPYV8XNajiAyinOlaGbzL6NHUJFQ==", "dev": true, "dependencies": { "basic-auth": "^2.0.1", "cors": "^2.8.5", - "debug": "^4.3.7", - "express": "^4.21.1", + "debug": "^4.4.0", + "express": "^4.21.2", "secure-compare": "^3.0.1", "selfsigned": "^2.4.1", "serve-index": "^1.9.1", @@ -8179,10 +8418,13 @@ } }, "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8213,15 +8455,69 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -8424,12 +8720,12 @@ } }, "node_modules/socks-proxy-agent": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", - "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "dev": true, "dependencies": { - "agent-base": "^7.1.1", + "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" }, @@ -8516,9 +8812,9 @@ } }, "node_modules/streamx": { - "version": "2.20.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz", - "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==", + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.21.1.tgz", + "integrity": "sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==", "dev": true, "dependencies": { "fast-fifo": "^1.3.2", @@ -8604,15 +8900,18 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -8622,15 +8921,19 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8818,9 +9121,9 @@ } }, "node_modules/terser": { - "version": "5.36.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", - "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", + "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -8842,10 +9145,13 @@ "dev": true }, "node_modules/text-decoder": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.1.tgz", - "integrity": "sha512-x9v3H/lTKIJKQQe7RPQkLfKAnc9lUTkWDypIQgTzPJAq+5/GCDHonmshfvlsNSj58yyshbIJJDLmU15qNERrXQ==", - "dev": true + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4" + } }, "node_modules/text-table": { "version": "0.2.0", @@ -8923,9 +9229,9 @@ } }, "node_modules/tslib": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.0.tgz", - "integrity": "sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, "node_modules/tuf-js": { @@ -9103,30 +9409,30 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -9136,17 +9442,18 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { "node": ">= 0.4" @@ -9156,17 +9463,17 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-proto": "^1.0.3", "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" }, "engines": { "node": ">= 0.4" @@ -9176,9 +9483,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -9195,15 +9502,18 @@ "dev": true }, "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9389,31 +9699,80 @@ } }, "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", + "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", "dev": true, "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "for-each": "^0.3.3", - "gopd": "^1.0.1", + "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, "engines": { @@ -9736,9 +10095,9 @@ } }, "node_modules/zod": { - "version": "3.23.8", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", + "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", "dev": true, "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index 1969d90cf7fd75..1152877339ccb4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "three", - "version": "0.171.0", + "version": "0.172.0", "description": "JavaScript 3D library", "type": "module", "main": "./build/three.cjs", @@ -47,7 +47,7 @@ "test": "npm run lint && npm run test-unit && npm run test-unit-addons", "build": "rollup -c utils/build/rollup.config.js", "build-module": "rollup -c utils/build/rollup.config.js --configOnlyModule", - "build-docs": "jsdoc src/nodes -c utils/docs/jsdoc.config.json", + "build-docs": "jsdoc -c utils/docs/jsdoc.config.json", "dev": "concurrently --names \"ROLLUP,HTTP\" -c \"bgBlue.bold,bgGreen.bold\" \"rollup -c utils/build/rollup.config.js -w -m inline\" \"servez -p 8080\"", "dev-ssl": "concurrently --names \"ROLLUP,HTTPS\" -c \"bgBlue.bold,bgGreen.bold\" \"rollup -c utils/build/rollup.config.js -w -m inline\" \"servez -p 8080 --ssl\"", "lint-core": "eslint src", @@ -93,7 +93,7 @@ }, "homepage": "https://threejs.org/", "devDependencies": { - "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-node-resolve": "^16.0.0", "@rollup/plugin-terser": "^0.4.0", "chalk": "^5.2.0", "clean-jsdoc-theme": "^4.3.0", diff --git a/playground/Nodes.json b/playground/Nodes.json index 1208579cda4c91..a9f42c6558dc65 100644 --- a/playground/Nodes.json +++ b/playground/Nodes.json @@ -1222,7 +1222,7 @@ { "name": "Max", "icon": "math-function", - "description": "Returns the maximun of the two parameters.", + "description": "Returns the maximum of the two parameters.", "shaderNode": "max", "nodeType": "node", "properties": [ @@ -1369,7 +1369,7 @@ "name": "bNode", "nodeType": "node", "label": "y", - "description": "Specify the value to whitch to raise x." + "description": "Specify the value to raise x." } ] }, @@ -1531,7 +1531,7 @@ "name": "aNode", "nodeType": "node", "label": "x", - "description": "Specify the value from wich to extract the sign." + "description": "Specify the value from which to extract the sign." } ] }, diff --git a/src/Three.Core.js b/src/Three.Core.js index f7a10261f0014e..782018000d8111 100644 --- a/src/Three.Core.js +++ b/src/Three.Core.js @@ -21,6 +21,7 @@ export { Line } from './objects/Line.js'; export { Points } from './objects/Points.js'; export { Group } from './objects/Group.js'; export { VideoTexture } from './textures/VideoTexture.js'; +export { VideoFrameTexture } from './textures/VideoFrameTexture.js'; export { FramebufferTexture } from './textures/FramebufferTexture.js'; export { Source } from './textures/Source.js'; export { DataTexture } from './textures/DataTexture.js'; @@ -85,6 +86,8 @@ export { AnimationMixer } from './animation/AnimationMixer.js'; export { AnimationClip } from './animation/AnimationClip.js'; export { AnimationAction } from './animation/AnimationAction.js'; export { RenderTarget } from './core/RenderTarget.js'; +export { RenderTarget3D } from './core/RenderTarget3D.js'; +export { RenderTargetArray } from './core/RenderTargetArray.js'; export { Uniform } from './core/Uniform.js'; export { UniformsGroup } from './core/UniformsGroup.js'; export { InstancedBufferGeometry } from './core/InstancedBufferGeometry.js'; diff --git a/src/Three.TSL.js b/src/Three.TSL.js index 7afc0c18c91795..1bc66166c5c213 100644 --- a/src/Three.TSL.js +++ b/src/Three.TSL.js @@ -33,7 +33,6 @@ export const abs = TSL.abs; export const acesFilmicToneMapping = TSL.acesFilmicToneMapping; export const acos = TSL.acos; export const add = TSL.add; -export const addMethodChaining = TSL.addMethodChaining; export const addNodeElement = TSL.addNodeElement; export const agxToneMapping = TSL.agxToneMapping; export const all = TSL.all; @@ -115,6 +114,7 @@ export const colorSpaceToWorking = TSL.colorSpaceToWorking; export const colorToDirection = TSL.colorToDirection; export const compute = TSL.compute; export const cond = TSL.cond; +export const Const = TSL.Const; export const context = TSL.context; export const convert = TSL.convert; export const convertColorSpace = TSL.convertColorSpace; @@ -155,6 +155,7 @@ export const exp2 = TSL.exp2; export const expression = TSL.expression; export const faceDirection = TSL.faceDirection; export const faceForward = TSL.faceForward; +export const faceforward = TSL.faceforward; export const float = TSL.float; export const floor = TSL.floor; export const fog = TSL.fog; @@ -183,8 +184,8 @@ export const grayscale = TSL.grayscale; export const greaterThan = TSL.greaterThan; export const greaterThanEqual = TSL.greaterThanEqual; export const hash = TSL.hash; -export const highPrecisionModelNormalViewMatrix = TSL.highPrecisionModelNormalViewMatrix; -export const highPrecisionModelViewMatrix = TSL.highPrecisionModelViewMatrix; +export const highpModelNormalViewMatrix = TSL.highpModelNormalViewMatrix; +export const highpModelViewMatrix = TSL.highpModelViewMatrix; export const hue = TSL.hue; export const instance = TSL.instance; export const instanceIndex = TSL.instanceIndex; @@ -194,6 +195,7 @@ export const instancedDynamicBufferAttribute = TSL.instancedDynamicBufferAttribu export const instancedMesh = TSL.instancedMesh; export const int = TSL.int; export const inverseSqrt = TSL.inverseSqrt; +export const inversesqrt = TSL.inversesqrt; export const invocationLocalIndex = TSL.invocationLocalIndex; export const invocationSubgroupIndex = TSL.invocationSubgroupIndex; export const ior = TSL.ior; @@ -218,16 +220,18 @@ export const lights = TSL.lights; export const linearDepth = TSL.linearDepth; export const linearToneMapping = TSL.linearToneMapping; export const localId = TSL.localId; +export const globalId = TSL.globalId; export const log = TSL.log; export const log2 = TSL.log2; export const logarithmicDepthToViewZ = TSL.logarithmicDepthToViewZ; export const loop = TSL.loop; export const luminance = TSL.luminance; +export const mediumpModelViewMatrix = TSL.mediumpModelViewMatrix; export const mat2 = TSL.mat2; export const mat3 = TSL.mat3; export const mat4 = TSL.mat4; export const matcapUV = TSL.matcapUV; -export const materialAOMap = TSL.materialAOMap; +export const materialAO = TSL.materialAO; export const materialAlphaTest = TSL.materialAlphaTest; export const materialAnisotropy = TSL.materialAnisotropy; export const materialAnisotropyVector = TSL.materialAnisotropyVector; @@ -252,7 +256,7 @@ export const materialLineWidth = TSL.materialLineWidth; export const materialMetalness = TSL.materialMetalness; export const materialNormal = TSL.materialNormal; export const materialOpacity = TSL.materialOpacity; -export const materialPointWidth = TSL.materialPointWidth; +export const materialPointSize = TSL.materialPointSize; export const materialReference = TSL.materialReference; export const materialReflectivity = TSL.materialReflectivity; export const materialRefractionRatio = TSL.materialRefractionRatio; @@ -409,8 +413,9 @@ export const select = TSL.select; export const setCurrentStack = TSL.setCurrentStack; export const shaderStages = TSL.shaderStages; export const shadow = TSL.shadow; -export const shadowWorldPosition = TSL.shadowWorldPosition; +export const shadowPositionWorld = TSL.shadowPositionWorld; export const sharedUniformGroup = TSL.sharedUniformGroup; +export const shapeCircle = TSL.shapeCircle; export const sheen = TSL.sheen; export const sheenRoughness = TSL.sheenRoughness; export const shiftLeft = TSL.shiftLeft; @@ -494,6 +499,7 @@ export const uv = TSL.uv; export const uvec2 = TSL.uvec2; export const uvec3 = TSL.uvec3; export const uvec4 = TSL.uvec4; +export const Var = TSL.Var; export const varying = TSL.varying; export const varyingProperty = TSL.varyingProperty; export const vec2 = TSL.vec2; diff --git a/src/Three.WebGPU.Nodes.js b/src/Three.WebGPU.Nodes.js index f3371c57d0d463..cffe29047e11f5 100644 --- a/src/Three.WebGPU.Nodes.js +++ b/src/Three.WebGPU.Nodes.js @@ -7,8 +7,8 @@ export { default as BundleGroup } from './renderers/common/BundleGroup.js'; export { default as QuadMesh } from './renderers/common/QuadMesh.js'; export { default as PMREMGenerator } from './renderers/common/extras/PMREMGenerator.js'; export { default as PostProcessing } from './renderers/common/PostProcessing.js'; -import * as PostProcessingUtils from './renderers/common/PostProcessingUtils.js'; -export { PostProcessingUtils }; +import * as RendererUtils from './renderers/common/RendererUtils.js'; +export { RendererUtils }; export { default as StorageTexture } from './renderers/common/StorageTexture.js'; export { default as StorageBufferAttribute } from './renderers/common/StorageBufferAttribute.js'; export { default as StorageInstancedBufferAttribute } from './renderers/common/StorageInstancedBufferAttribute.js'; diff --git a/src/Three.WebGPU.js b/src/Three.WebGPU.js index 4289377b368d9a..94717330c2e9ca 100644 --- a/src/Three.WebGPU.js +++ b/src/Three.WebGPU.js @@ -7,8 +7,8 @@ export { default as BundleGroup } from './renderers/common/BundleGroup.js'; export { default as QuadMesh } from './renderers/common/QuadMesh.js'; export { default as PMREMGenerator } from './renderers/common/extras/PMREMGenerator.js'; export { default as PostProcessing } from './renderers/common/PostProcessing.js'; -import * as PostProcessingUtils from './renderers/common/PostProcessingUtils.js'; -export { PostProcessingUtils }; +import * as RendererUtils from './renderers/common/RendererUtils.js'; +export { RendererUtils }; export { default as StorageTexture } from './renderers/common/StorageTexture.js'; export { default as StorageBufferAttribute } from './renderers/common/StorageBufferAttribute.js'; export { default as StorageInstancedBufferAttribute } from './renderers/common/StorageInstancedBufferAttribute.js'; diff --git a/src/cameras/PerspectiveCamera.js b/src/cameras/PerspectiveCamera.js index 5183f010c2cd5b..19a6ebe1a72c76 100644 --- a/src/cameras/PerspectiveCamera.js +++ b/src/cameras/PerspectiveCamera.js @@ -113,8 +113,8 @@ class PerspectiveCamera extends Camera { * Sets minTarget and maxTarget to the coordinates of the lower-left and upper-right corners of the view rectangle. * * @param {number} distance - * @param {number} minTarget - * @param {number} maxTarget + * @param {Vector2} minTarget + * @param {Vector2} maxTarget */ getViewBounds( distance, minTarget, maxTarget ) { diff --git a/src/constants.js b/src/constants.js index 2097edde6ab3f1..89116a5eb6cb91 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,4 +1,4 @@ -export const REVISION = '172dev'; +export const REVISION = '173dev'; export const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; export const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; diff --git a/src/core/BufferAttribute.js b/src/core/BufferAttribute.js index 747bb1efe34499..652a2a2d32616c 100644 --- a/src/core/BufferAttribute.js +++ b/src/core/BufferAttribute.js @@ -7,6 +7,8 @@ import { fromHalfFloat, toHalfFloat } from '../extras/DataUtils.js'; const _vector = /*@__PURE__*/ new Vector3(); const _vector2 = /*@__PURE__*/ new Vector2(); +let _id = 0; + class BufferAttribute { constructor( array, itemSize, normalized = false ) { @@ -19,6 +21,8 @@ class BufferAttribute { this.isBufferAttribute = true; + Object.defineProperty( this, 'id', { value: _id ++ } ); + this.name = ''; this.array = array; diff --git a/src/core/EventDispatcher.js b/src/core/EventDispatcher.js index e75d1e71d8b883..fb4567ed172e77 100644 --- a/src/core/EventDispatcher.js +++ b/src/core/EventDispatcher.js @@ -26,19 +26,20 @@ class EventDispatcher { hasEventListener( type, listener ) { - if ( this._listeners === undefined ) return false; - const listeners = this._listeners; + if ( listeners === undefined ) return false; + return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; } removeEventListener( type, listener ) { - if ( this._listeners === undefined ) return; - const listeners = this._listeners; + + if ( listeners === undefined ) return; + const listenerArray = listeners[ type ]; if ( listenerArray !== undefined ) { @@ -57,9 +58,10 @@ class EventDispatcher { dispatchEvent( event ) { - if ( this._listeners === undefined ) return; - const listeners = this._listeners; + + if ( listeners === undefined ) return; + const listenerArray = listeners[ event.type ]; if ( listenerArray !== undefined ) { diff --git a/src/core/RenderTarget3D.js b/src/core/RenderTarget3D.js new file mode 100644 index 00000000000000..9cd41bb2e2d318 --- /dev/null +++ b/src/core/RenderTarget3D.js @@ -0,0 +1,22 @@ +import { RenderTarget } from './RenderTarget.js'; +import { Data3DTexture } from '../textures/Data3DTexture.js'; + +class RenderTarget3D extends RenderTarget { + + constructor( width = 1, height = 1, depth = 1, options = {} ) { + + super( width, height, options ); + + this.isRenderTarget3D = true; + + this.depth = depth; + + this.texture = new Data3DTexture( null, width, height, depth ); + + this.texture.isRenderTargetTexture = true; + + } + +} + +export { RenderTarget3D }; diff --git a/src/core/RenderTargetArray.js b/src/core/RenderTargetArray.js new file mode 100644 index 00000000000000..7c4b2a25300953 --- /dev/null +++ b/src/core/RenderTargetArray.js @@ -0,0 +1,22 @@ +import { RenderTarget } from './RenderTarget.js'; +import { DataArrayTexture } from '../textures/DataArrayTexture.js'; + +class RenderTargetArray extends RenderTarget { + + constructor( width = 1, height = 1, depth = 1, options = {} ) { + + super( width, height, options ); + + this.isRenderTargetArray = true; + + this.depth = depth; + + this.texture = new DataArrayTexture( null, width, height, depth ); + + this.texture.isRenderTargetTexture = true; + + } + +} + +export { RenderTargetArray }; diff --git a/src/extras/Earcut.js b/src/extras/Earcut.js index 0a824aca20631d..2737e1c7638963 100644 --- a/src/extras/Earcut.js +++ b/src/extras/Earcut.js @@ -591,7 +591,7 @@ function pointInTriangle( ax, ay, bx, by, cx, cy, px, 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 + return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // doesn'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( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case diff --git a/src/helpers/CameraHelper.js b/src/helpers/CameraHelper.js index 4695a9bf8071d2..85273e836da883 100644 --- a/src/helpers/CameraHelper.js +++ b/src/helpers/CameraHelper.js @@ -5,6 +5,7 @@ import { Color } from '../math/Color.js'; import { LineBasicMaterial } from '../materials/LineBasicMaterial.js'; import { BufferGeometry } from '../core/BufferGeometry.js'; import { Float32BufferAttribute } from '../core/BufferAttribute.js'; +import { WebGLCoordinateSystem } from '../constants.js'; const _vector = /*@__PURE__*/ new Vector3(); const _camera = /*@__PURE__*/ new Camera(); @@ -195,17 +196,19 @@ class CameraHelper extends LineSegments { _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); - // center / target + // Adjust z values based on coordinate system + const nearZ = this.camera.coordinateSystem === WebGLCoordinateSystem ? - 1 : 0; - setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); + // center / target + setPoint( 'c', pointMap, geometry, _camera, 0, 0, nearZ ); setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); // near - setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); - setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); - setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); - setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); + setPoint( 'n1', pointMap, geometry, _camera, - w, - h, nearZ ); + setPoint( 'n2', pointMap, geometry, _camera, w, - h, nearZ ); + setPoint( 'n3', pointMap, geometry, _camera, - w, h, nearZ ); + setPoint( 'n4', pointMap, geometry, _camera, w, h, nearZ ); // far @@ -216,9 +219,9 @@ class CameraHelper extends LineSegments { // up - setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); - setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); - setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); + setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, nearZ ); + setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, nearZ ); + setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, nearZ ); // cross @@ -227,10 +230,10 @@ class CameraHelper extends LineSegments { setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); - setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); - setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); - setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); - setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); + setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, nearZ ); + setPoint( 'cn2', pointMap, geometry, _camera, w, 0, nearZ ); + setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, nearZ ); + setPoint( 'cn4', pointMap, geometry, _camera, 0, h, nearZ ); geometry.getAttribute( 'position' ).needsUpdate = true; diff --git a/src/loaders/nodes/NodeLoader.js b/src/loaders/nodes/NodeLoader.js index 0ee39c773a39d6..051f3f86ae683c 100644 --- a/src/loaders/nodes/NodeLoader.js +++ b/src/loaders/nodes/NodeLoader.js @@ -3,17 +3,46 @@ import { nodeObject, float } from '../../nodes/tsl/TSLBase.js'; import { Loader } from '../Loader.js'; import { FileLoader } from '../../loaders/FileLoader.js'; +/** + * A loader for loading node objects in the three.js JSON Object/Scene format. + * + * @augments Loader + */ class NodeLoader extends Loader { + /** + * Constructs a new node loader. + * + * @param {LoadingManager?} manager - A reference to a loading manager. + */ constructor( manager ) { super( manager ); + /** + * Represents a dictionary of textures. + * + * @type {Object} + */ this.textures = {}; + + /** + * Represents a dictionary of node types. + * + * @type {Object} + */ this.nodes = {}; } + /** + * Loads the node definitions from the given URL. + * + * @param {String} url - The path/URL of the file to be loaded. + * @param {Function} onLoad - Will be called when load completes. + * @param {Function} onProgress - Will be called while load progresses. + * @param {Function} onError - Will be called when errors are thrown during the loading process. + */ load( url, onLoad, onProgress, onError ) { const loader = new FileLoader( this.manager ); @@ -46,6 +75,12 @@ class NodeLoader extends Loader { } + /** + * Parse the node dependencies for the loaded node. + * + * @param {Object} json - The JSON definition + * @return {Object} A dictionary with node dependencies. + */ parseNodes( json ) { const nodes = {}; @@ -80,6 +115,12 @@ class NodeLoader extends Loader { } + /** + * Parses the node from the given JSON. + * + * @param {Object} json - The JSON definition + * @return {Node} The parsed node. + */ parse( json ) { const node = this.createNodeFromType( json.type ); @@ -98,6 +139,12 @@ class NodeLoader extends Loader { } + /** + * Defines the dictionary of textures. + * + * @param {Object} value - The texture library defines as ``. + * @return {NodeLoader} A reference to this loader. + */ setTextures( value ) { this.textures = value; @@ -105,6 +152,12 @@ class NodeLoader extends Loader { } + /** + * Defines the dictionary of node types. + * + * @param {Object} value - The node library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodes( value ) { this.nodes = value; @@ -112,6 +165,12 @@ class NodeLoader extends Loader { } + /** + * Creates a node object from the given type. + * + * @param {String} type - The node type. + * @return {Node} The created node instance. + */ createNodeFromType( type ) { if ( this.nodes[ type ] === undefined ) { diff --git a/src/loaders/nodes/NodeMaterialLoader.js b/src/loaders/nodes/NodeMaterialLoader.js index ec624f73022422..80d7a6c49dfd71 100644 --- a/src/loaders/nodes/NodeMaterialLoader.js +++ b/src/loaders/nodes/NodeMaterialLoader.js @@ -1,16 +1,43 @@ import { MaterialLoader } from '../../loaders/MaterialLoader.js'; +/** + * A special type of material loader for loading node materials. + * + * @augments MaterialLoader + */ class NodeMaterialLoader extends MaterialLoader { + /** + * Constructs a new node material loader. + * + * @param {LoadingManager?} manager - A reference to a loading manager. + */ constructor( manager ) { super( manager ); + /** + * Represents a dictionary of node types. + * + * @type {Object} + */ this.nodes = {}; + + /** + * Represents a dictionary of node material types. + * + * @type {Object} + */ this.nodeMaterials = {}; } + /** + * Parses the node material from the given JSON. + * + * @param {Object} json - The JSON definition + * @return {NodeMaterial}. The parsed material. + */ parse( json ) { const material = super.parse( json ); @@ -30,6 +57,12 @@ class NodeMaterialLoader extends MaterialLoader { } + /** + * Defines the dictionary of node types. + * + * @param {Object} value - The node library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodes( value ) { this.nodes = value; @@ -37,6 +70,12 @@ class NodeMaterialLoader extends MaterialLoader { } + /** + * Defines the dictionary of node material types. + * + * @param {Object} value - The node material library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodeMaterials( value ) { this.nodeMaterials = value; @@ -44,6 +83,12 @@ class NodeMaterialLoader extends MaterialLoader { } + /** + * Creates a node material from the given type. + * + * @param {String} type - The node material type. + * @return {Node} The created node material instance. + */ createMaterialFromType( type ) { const materialClass = this.nodeMaterials[ type ]; diff --git a/src/loaders/nodes/NodeObjectLoader.js b/src/loaders/nodes/NodeObjectLoader.js index 105abcf6c638a6..3ca748250c5f8b 100644 --- a/src/loaders/nodes/NodeObjectLoader.js +++ b/src/loaders/nodes/NodeObjectLoader.js @@ -3,19 +3,53 @@ import NodeMaterialLoader from './NodeMaterialLoader.js'; import { ObjectLoader } from '../../loaders/ObjectLoader.js'; +/** + * A special type of object loader for loading 3D objects using + * node materials. + * + * @augments ObjectLoader + */ class NodeObjectLoader extends ObjectLoader { + /** + * Constructs a new node object loader. + * + * @param {LoadingManager?} manager - A reference to a loading manager. + */ constructor( manager ) { super( manager ); + /** + * Represents a dictionary of node types. + * + * @type {Object} + */ this.nodes = {}; + + /** + * Represents a dictionary of node material types. + * + * @type {Object} + */ this.nodeMaterials = {}; + /** + * A reference to hold the `nodes` JSON property. + * + * @private + * @type {Object?} + */ this._nodesJSON = null; } + /** + * Defines the dictionary of node types. + * + * @param {Object} value - The node library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodes( value ) { this.nodes = value; @@ -23,6 +57,12 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Defines the dictionary of node material types. + * + * @param {Object} value - The node material library defined as ``. + * @return {NodeLoader} A reference to this loader. + */ setNodeMaterials( value ) { this.nodeMaterials = value; @@ -30,6 +70,13 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Parses the node objects from the given JSON. + * + * @param {Object} json - The JSON definition + * @param {Function} onLoad - The onLoad callback function. + * @return {Object3D}. The parsed 3D object. + */ parse( json, onLoad ) { this._nodesJSON = json.nodes; @@ -42,6 +89,13 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Parses the node objects from the given JSON and textures. + * + * @param {Object} json - The JSON definition + * @param {Object} textures - The texture library. + * @return {Object}. The parsed nodes. + */ parseNodes( json, textures ) { if ( json !== undefined ) { @@ -58,6 +112,13 @@ class NodeObjectLoader extends ObjectLoader { } + /** + * Parses the node objects from the given JSON and textures. + * + * @param {Object} json - The JSON definition + * @param {Object} textures - The texture library. + * @return {Object}. The parsed materials. + */ parseMaterials( json, textures ) { const materials = {}; diff --git a/src/materials/nodes/InstancedPointsNodeMaterial.js b/src/materials/nodes/InstancedPointsNodeMaterial.js deleted file mode 100644 index 0d7278225f5bdd..00000000000000 --- a/src/materials/nodes/InstancedPointsNodeMaterial.js +++ /dev/null @@ -1,156 +0,0 @@ -import NodeMaterial from './NodeMaterial.js'; -import { attribute } from '../../nodes/core/AttributeNode.js'; -import { cameraProjectionMatrix } from '../../nodes/accessors/Camera.js'; -import { materialColor, materialOpacity, materialPointWidth } from '../../nodes/accessors/MaterialNode.js'; // or should this be a property, instead? -import { modelViewMatrix } from '../../nodes/accessors/ModelNode.js'; -import { positionGeometry } from '../../nodes/accessors/Position.js'; -import { smoothstep, lengthSq } from '../../nodes/math/MathNode.js'; -import { Fn, vec4, float } from '../../nodes/tsl/TSLBase.js'; -import { uv } from '../../nodes/accessors/UV.js'; -import { viewport } from '../../nodes/display/ScreenNode.js'; - -import { PointsMaterial } from '../PointsMaterial.js'; - -const _defaultValues = /*@__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 ); - - 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; - - } - - } - -} - -export default InstancedPointsNodeMaterial; diff --git a/src/materials/nodes/Line2NodeMaterial.js b/src/materials/nodes/Line2NodeMaterial.js index 7e8437cc4345e0..7a2835020b2327 100644 --- a/src/materials/nodes/Line2NodeMaterial.js +++ b/src/materials/nodes/Line2NodeMaterial.js @@ -16,6 +16,12 @@ import { NoBlending } from '../../constants.js'; const _defaultValues = /*@__PURE__*/ new LineDashedMaterial(); +/** + * This node material can be used to render lines with a size larger than one + * by representing them as instanced meshes. + * + * @augments NodeMaterial + */ class Line2NodeMaterial extends NodeMaterial { static get type() { @@ -24,49 +30,120 @@ class Line2NodeMaterial extends NodeMaterial { } - constructor( params = {} ) { + /** + * Constructs a new node material for wide line rendering. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters = {} ) { super(); - this.lights = false; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isLine2NodeMaterial = true; this.setDefaultValues( _defaultValues ); - this.useAlphaToCoverage = true; - this.useColor = params.vertexColors; - this.useDash = params.dashed; - this.useWorldUnits = false; - + /** + * Whether vertex colors should be used or not. + * + * @type {Boolean} + * @default false + */ + this.useColor = parameters.vertexColors; + + /** + * The dash offset. + * + * @type {Number} + * @default 0 + */ this.dashOffset = 0; + + /** + * The line width. + * + * @type {Number} + * @default 0 + */ this.lineWidth = 1; + /** + * Defines the lines color. + * + * @type {Node?} + * @default null + */ this.lineColorNode = null; + /** + * Defines the offset. + * + * @type {Node?} + * @default null + */ this.offsetNode = null; + + /** + * Defines the dash scale. + * + * @type {Node?} + * @default null + */ this.dashScaleNode = null; + + /** + * Defines the dash size. + * + * @type {Node?} + * @default null + */ this.dashSizeNode = null; + + /** + * Defines the gap size. + * + * @type {Node?} + * @default null + */ this.gapSizeNode = null; + /** + * Blending is set to `NoBlending` since transparency + * is not supported, yet. + * + * @type {Number} + * @default 0 + */ this.blending = NoBlending; - this.setValues( params ); + this._useDash = parameters.dashed; + this._useAlphaToCoverage = true; + this._useWorldUnits = false; + + this.setValues( parameters ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { - this.setupShaders( builder ); - - super.setup( builder ); - - } - - setupShaders( { renderer } ) { + const { renderer } = builder; - const useAlphaToCoverage = this.alphaToCoverage; + const useAlphaToCoverage = this._useAlphaToCoverage; const useColor = this.useColor; - const useDash = this.dashed; - const useWorldUnits = this.worldUnits; + const useDash = this._useDash; + const useWorldUnits = this._useWorldUnits; const trimSegment = Fn( ( { start, end } ) => { @@ -100,7 +177,7 @@ class Line2NodeMaterial extends NodeMaterial { if ( useDash ) { const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale; - const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset; + const offsetNode = this.offsetNode ? float( this.offsetNode ) : materialLineDashOffset; const instanceDistanceStart = attribute( 'instanceDistanceStart' ); const instanceDistanceEnd = attribute( 'instanceDistanceEnd' ); @@ -277,7 +354,7 @@ class Line2NodeMaterial extends NodeMaterial { if ( useDash ) { const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize; - const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize; + const gapSizeNode = this.gapSizeNode ? float( this.gapSizeNode ) : materialLineGapSize; dashSize.assign( dashSizeNode ); gapSize.assign( gapSizeNode ); @@ -394,56 +471,74 @@ class Line2NodeMaterial extends NodeMaterial { } - } + super.setup( builder ); + } + /** + * Whether the lines should sized in world units or not. + * When set to `false` the unit is pixel. + * + * @type {Boolean} + * @default false + */ get worldUnits() { - return this.useWorldUnits; + return this._useWorldUnits; } set worldUnits( value ) { - if ( this.useWorldUnits !== value ) { + if ( this._useWorldUnits !== value ) { - this.useWorldUnits = value; + this._useWorldUnits = value; this.needsUpdate = true; } } - + /** + * Whether the lines should be dashed or not. + * + * @type {Boolean} + * @default false + */ get dashed() { - return this.useDash; + return this._useDash; } set dashed( value ) { - if ( this.useDash !== value ) { + if ( this._useDash !== value ) { - this.useDash = value; + this._useDash = value; this.needsUpdate = true; } } - + /** + * Whether alpha to coverage should be used or not. + * + * @type {Boolean} + * @default true + */ get alphaToCoverage() { - return this.useAlphaToCoverage; + return this._useAlphaToCoverage; } set alphaToCoverage( value ) { - if ( this.useAlphaToCoverage !== value ) { + if ( this._useAlphaToCoverage !== value ) { - this.useAlphaToCoverage = value; + this._useAlphaToCoverage = value; this.needsUpdate = true; } diff --git a/src/materials/nodes/LineBasicNodeMaterial.js b/src/materials/nodes/LineBasicNodeMaterial.js index c167ab0ecb988f..1e0fbdb4dfa118 100644 --- a/src/materials/nodes/LineBasicNodeMaterial.js +++ b/src/materials/nodes/LineBasicNodeMaterial.js @@ -4,6 +4,11 @@ import { LineBasicMaterial } from '../LineBasicMaterial.js'; const _defaultValues = /*@__PURE__*/ new LineBasicMaterial(); +/** + * Node material version of `LineBasicMaterial`. + * + * @augments NodeMaterial + */ class LineBasicNodeMaterial extends NodeMaterial { static get type() { @@ -12,14 +17,24 @@ class LineBasicNodeMaterial extends NodeMaterial { } + /** + * Constructs a new line basic node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isLineBasicNodeMaterial = true; - this.lights = false; - this.setDefaultValues( _defaultValues ); this.setValues( parameters ); diff --git a/src/materials/nodes/LineDashedNodeMaterial.js b/src/materials/nodes/LineDashedNodeMaterial.js index e1c0421d83aaf5..d60f1be7c2f8d3 100644 --- a/src/materials/nodes/LineDashedNodeMaterial.js +++ b/src/materials/nodes/LineDashedNodeMaterial.js @@ -8,6 +8,11 @@ import { LineDashedMaterial } from '../LineDashedMaterial.js'; const _defaultValues = /*@__PURE__*/ new LineDashedMaterial(); +/** + * Node material version of `LineDashedMaterial`. + * + * @augments NodeMaterial + */ class LineDashedNodeMaterial extends NodeMaterial { static get type() { @@ -16,33 +21,101 @@ class LineDashedNodeMaterial extends NodeMaterial { } + /** + * Constructs a new line dashed node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isLineDashedNodeMaterial = true; - this.lights = false; - this.setDefaultValues( _defaultValues ); + /** + * The dash offset. + * + * @type {Number} + * @default 0 + */ this.dashOffset = 0; + /** + * The offset of dash materials is by default inferred from the `dashOffset` + * property. This node property allows to overwrite the default + * and define the offset with a node instead. + * + * If you don't want to overwrite the offset but modify the existing + * value instead, use {@link module:MaterialNode.materialLineDashOffset}. + * + * @type {Node?} + * @default null + */ this.offsetNode = null; + + /** + * The scale of dash materials is by default inferred from the `scale` + * property. This node property allows to overwrite the default + * and define the scale with a node instead. + * + * If you don't want to overwrite the scale but modify the existing + * value instead, use {@link module:MaterialNode.materialLineScale}. + * + * @type {Node?} + * @default null + */ this.dashScaleNode = null; + + /** + * The dash size of dash materials is by default inferred from the `dashSize` + * property. This node property allows to overwrite the default + * and define the dash size with a node instead. + * + * If you don't want to overwrite the dash size but modify the existing + * value instead, use {@link module:MaterialNode.materialLineDashSize}. + * + * @type {Node?} + * @default null + */ this.dashSizeNode = null; + + /** + * The gap size of dash materials is by default inferred from the `gapSize` + * property. This node property allows to overwrite the default + * and define the gap size with a node instead. + * + * If you don't want to overwrite the gap size but modify the existing + * value instead, use {@link module:MaterialNode.materialLineGapSize}. + * + * @type {Node?} + * @default null + */ this.gapSizeNode = null; this.setValues( parameters ); } - setupVariants() { + /** + * Setups the dash specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ + setupVariants( /* builder */ ) { - const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset; + const offsetNode = this.offsetNode ? float( this.offsetNode ) : 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; + const gapSizeNode = this.gapSizeNode ? float( this.gapSizeNode ) : materialLineGapSize; dashSize.assign( dashSizeNode ); gapSize.assign( gapSizeNode ); diff --git a/src/materials/nodes/MeshBasicNodeMaterial.js b/src/materials/nodes/MeshBasicNodeMaterial.js index 5be8a986df11e2..6bca9f84d18570 100644 --- a/src/materials/nodes/MeshBasicNodeMaterial.js +++ b/src/materials/nodes/MeshBasicNodeMaterial.js @@ -10,6 +10,11 @@ import { MeshBasicMaterial } from '../MeshBasicMaterial.js'; const _defaultValues = /*@__PURE__*/ new MeshBasicMaterial(); +/** + * Node material version of `MeshBasicMaterial`. + * + * @augments NodeMaterial + */ class MeshBasicNodeMaterial extends NodeMaterial { static get type() { @@ -18,12 +23,32 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh basic node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshBasicNodeMaterial = true; + /** + * Although the basic material is by definition unlit, we set + * this property to `true` since we use a lighting model to compute + * the outgoing light of the fragment shader. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues ); @@ -32,12 +57,25 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * Basic materials are not affected by normal and bump maps so we + * return by default {@link module:Normal.normalView}. + * + * @return {Node} The normal node. + */ setupNormal() { return normalView; // see #28839 } + /** + * Overwritten since this type of material uses {@link BasicEnvironmentNode} + * to implement the default environment mapping. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicEnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { const envNode = super.setupEnvironment( builder ); @@ -46,6 +84,13 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * This method must be overwritten since light maps are evaluated + * with a special scaling factor for basic materials. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicLightMapNode?} The light map node. + */ setupLightMap( builder ) { let node = null; @@ -60,12 +105,23 @@ class MeshBasicNodeMaterial extends NodeMaterial { } + /** + * The material overwrites this method because `lights` is set to `true` but + * we still want to return the diffuse color as the outgoing light. + * + * @return {Node} The outgoing light node. + */ setupOutgoingLight() { return diffuseColor.rgb; } + /** + * Setups the lighting model. + * + * @return {BasicLightingModel} The lighting model. + */ setupLightingModel() { return new BasicLightingModel(); diff --git a/src/materials/nodes/MeshLambertNodeMaterial.js b/src/materials/nodes/MeshLambertNodeMaterial.js index 033ff96c92f9cf..da4e4c28cc1dbd 100644 --- a/src/materials/nodes/MeshLambertNodeMaterial.js +++ b/src/materials/nodes/MeshLambertNodeMaterial.js @@ -6,6 +6,11 @@ import { MeshLambertMaterial } from '../MeshLambertMaterial.js'; const _defaultValues = /*@__PURE__*/ new MeshLambertMaterial(); +/** + * Node material version of `MeshLambertMaterial`. + * + * @augments NodeMaterial + */ class MeshLambertNodeMaterial extends NodeMaterial { static get type() { @@ -14,12 +19,30 @@ class MeshLambertNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh lambert node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshLambertNodeMaterial = true; + /** + * Set to `true` because lambert materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues ); @@ -28,6 +51,13 @@ class MeshLambertNodeMaterial extends NodeMaterial { } + /** + * Overwritten since this type of material uses {@link BasicEnvironmentNode} + * to implement the default environment mapping. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicEnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { const envNode = super.setupEnvironment( builder ); @@ -36,6 +66,11 @@ class MeshLambertNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhongLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhongLightingModel( false ); // ( specular ) -> force lambert diff --git a/src/materials/nodes/MeshMatcapNodeMaterial.js b/src/materials/nodes/MeshMatcapNodeMaterial.js index 19f274cc78366a..df3a1ac95b3f31 100644 --- a/src/materials/nodes/MeshMatcapNodeMaterial.js +++ b/src/materials/nodes/MeshMatcapNodeMaterial.js @@ -9,6 +9,11 @@ import { MeshMatcapMaterial } from '../MeshMatcapMaterial.js'; const _defaultValues = /*@__PURE__*/ new MeshMatcapMaterial(); +/** + * Node material version of `MeshMatcapMaterial`. + * + * @augments NodeMaterial + */ class MeshMatcapNodeMaterial extends NodeMaterial { static get type() { @@ -17,12 +22,22 @@ class MeshMatcapNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh normal node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); - this.lights = false; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshMatcapNodeMaterial = true; this.setDefaultValues( _defaultValues ); @@ -31,6 +46,11 @@ class MeshMatcapNodeMaterial extends NodeMaterial { } + /** + * Setups the matcap specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( builder ) { const uv = matcapUV; diff --git a/src/materials/nodes/MeshNormalNodeMaterial.js b/src/materials/nodes/MeshNormalNodeMaterial.js index 3917cc3594cb62..e88fce34737e0c 100644 --- a/src/materials/nodes/MeshNormalNodeMaterial.js +++ b/src/materials/nodes/MeshNormalNodeMaterial.js @@ -9,6 +9,11 @@ import { MeshNormalMaterial } from '../MeshNormalMaterial.js'; const _defaultValues = /*@__PURE__*/ new MeshNormalMaterial(); +/** + * Node material version of `MeshNormalMaterial`. + * + * @augments NodeMaterial + */ class MeshNormalNodeMaterial extends NodeMaterial { static get type() { @@ -17,12 +22,22 @@ class MeshNormalNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh normal node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); - this.lights = false; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshNormalNodeMaterial = true; this.setDefaultValues( _defaultValues ); @@ -31,6 +46,10 @@ class MeshNormalNodeMaterial extends NodeMaterial { } + /** + * Overwrites the default implementation by computing the diffuse color + * based on the normal data. + */ setupDiffuseColor() { const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity; diff --git a/src/materials/nodes/MeshPhongNodeMaterial.js b/src/materials/nodes/MeshPhongNodeMaterial.js index c152283c913690..3d47a140a9a44d 100644 --- a/src/materials/nodes/MeshPhongNodeMaterial.js +++ b/src/materials/nodes/MeshPhongNodeMaterial.js @@ -9,6 +9,11 @@ import { MeshPhongMaterial } from '../MeshPhongMaterial.js'; const _defaultValues = /*@__PURE__*/ new MeshPhongMaterial(); +/** + * Node material version of `MeshPhongMaterial`. + * + * @augments NodeMaterial + */ class MeshPhongNodeMaterial extends NodeMaterial { static get type() { @@ -17,15 +22,56 @@ class MeshPhongNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh lambert node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshPhongNodeMaterial = true; + /** + * Set to `true` because phong materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; + /** + * The shininess of phong materials is by default inferred from the `shininess` + * property. This node property allows to overwrite the default + * and define the shininess with a node instead. + * + * If you don't want to overwrite the shininess but modify the existing + * value instead, use {@link module:MaterialNode.materialShininess}. + * + * @type {Node?} + * @default null + */ this.shininessNode = null; + + /** + * The specular color of phong materials is by default inferred from the + * `specular` property. This node property allows to overwrite the default + * and define the specular color with a node instead. + * + * If you don't want to overwrite the specular color but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecular}. + * + * @type {Node?} + * @default null + */ this.specularNode = null; this.setDefaultValues( _defaultValues ); @@ -34,6 +80,13 @@ class MeshPhongNodeMaterial extends NodeMaterial { } + /** + * Overwritten since this type of material uses {@link BasicEnvironmentNode} + * to implement the default environment mapping. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {BasicEnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { const envNode = super.setupEnvironment( builder ); @@ -42,13 +95,23 @@ class MeshPhongNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhongLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhongLightingModel(); } - setupVariants() { + /** + * Setups the phong specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ + setupVariants( /*builder*/ ) { // SHININESS diff --git a/src/materials/nodes/MeshPhysicalNodeMaterial.js b/src/materials/nodes/MeshPhysicalNodeMaterial.js index b06062ae5b0afd..0836931e87a23e 100644 --- a/src/materials/nodes/MeshPhysicalNodeMaterial.js +++ b/src/materials/nodes/MeshPhysicalNodeMaterial.js @@ -11,6 +11,11 @@ import { MeshPhysicalMaterial } from '../MeshPhysicalMaterial.js'; const _defaultValues = /*@__PURE__*/ new MeshPhysicalMaterial(); +/** + * Node material version of `MeshPhysicalMaterial`. + * + * @augments MeshStandardNodeMaterial + */ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { static get type() { @@ -19,33 +24,243 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Constructs a new mesh physical node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshPhysicalNodeMaterial = true; + /** + * The clearcoat of physical materials is by default inferred from the `clearcoat` + * and `clearcoatMap` properties. This node property allows to overwrite the default + * and define the clearcoat with a node instead. + * + * If you don't want to overwrite the clearcoat but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoat}. + * + * @type {Node?} + * @default null + */ this.clearcoatNode = null; + + /** + * The clearcoat roughness of physical materials is by default inferred from the `clearcoatRoughness` + * and `clearcoatRoughnessMap` properties. This node property allows to overwrite the default + * and define the clearcoat roughness with a node instead. + * + * If you don't want to overwrite the clearcoat roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoatRoughness}. + * + * @type {Node?} + * @default null + */ this.clearcoatRoughnessNode = null; + + /** + * The clearcoat normal of physical materials is by default inferred from the `clearcoatNormalMap` + * property. This node property allows to overwrite the default + * and define the clearcoat normal with a node instead. + * + * If you don't want to overwrite the clearcoat normal but modify the existing + * value instead, use {@link module:MaterialNode.materialClearcoatNormal}. + * + * @type {Node?} + * @default null + */ this.clearcoatNormalNode = null; + /** + * The sheen of physical materials is by default inferred from the `sheen`, `sheenColor` + * and `sheenColorMap` properties. This node property allows to overwrite the default + * and define the sheen with a node instead. + * + * If you don't want to overwrite the sheen but modify the existing + * value instead, use {@link module:MaterialNode.materialSheen}. + * + * @type {Node?} + * @default null + */ this.sheenNode = null; + + /** + * The sheen roughness of physical materials is by default inferred from the `sheenRoughness` and + * `sheenRoughnessMap` properties. This node property allows to overwrite the default + * and define the sheen roughness with a node instead. + * + * If you don't want to overwrite the sheen roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialSheenRoughness}. + * + * @type {Node?} + * @default null + */ this.sheenRoughnessNode = null; + /** + * The iridescence of physical materials is by default inferred from the `iridescence` + * property. This node property allows to overwrite the default + * and define the iridescence with a node instead. + * + * If you don't want to overwrite the iridescence but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescence}. + * + * @type {Node?} + * @default null + */ this.iridescenceNode = null; + + /** + * The iridescence IOR of physical materials is by default inferred from the `iridescenceIOR` + * property. This node property allows to overwrite the default + * and define the iridescence IOR with a node instead. + * + * If you don't want to overwrite the iridescence IOR but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescenceIOR}. + * + * @type {Node?} + * @default null + */ this.iridescenceIORNode = null; + + /** + * The iridescence thickness of physical materials is by default inferred from the `iridescenceThicknessRange` + * and `iridescenceThicknessMap` properties. This node property allows to overwrite the default + * and define the iridescence thickness with a node instead. + * + * If you don't want to overwrite the iridescence thickness but modify the existing + * value instead, use {@link module:MaterialNode.materialIridescenceThickness}. + * + * @type {Node?} + * @default null + */ this.iridescenceThicknessNode = null; + /** + * The specular intensity of physical materials is by default inferred from the `specularIntensity` + * and `specularIntensityMap` properties. This node property allows to overwrite the default + * and define the specular intensity with a node instead. + * + * If you don't want to overwrite the specular intensity but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecularIntensity}. + * + * @type {Node?} + * @default null + */ this.specularIntensityNode = null; + + /** + * The specular color of physical materials is by default inferred from the `specularColor` + * and `specularColorMap` properties. This node property allows to overwrite the default + * and define the specular color with a node instead. + * + * If you don't want to overwrite the specular color but modify the existing + * value instead, use {@link module:MaterialNode.materialSpecularColor}. + * + * @type {Node?} + * @default null + */ this.specularColorNode = null; + /** + * The ior of physical materials is by default inferred from the `ior` + * property. This node property allows to overwrite the default + * and define the ior with a node instead. + * + * If you don't want to overwrite the ior but modify the existing + * value instead, use {@link module:MaterialNode.materialIOR}. + * + * @type {Node?} + * @default null + */ this.iorNode = null; + + /** + * The transmission of physical materials is by default inferred from the `transmission` and + * `transmissionMap` properties. This node property allows to overwrite the default + * and define the transmission with a node instead. + * + * If you don't want to overwrite the transmission but modify the existing + * value instead, use {@link module:MaterialNode.materialTransmission}. + * + * @type {Node?} + * @default null + */ this.transmissionNode = null; + + /** + * The thickness of physical materials is by default inferred from the `thickness` and + * `thicknessMap` properties. This node property allows to overwrite the default + * and define the thickness with a node instead. + * + * If you don't want to overwrite the thickness but modify the existing + * value instead, use {@link module:MaterialNode.materialThickness}. + * + * @type {Node?} + * @default null + */ this.thicknessNode = null; + + /** + * The attenuation distance of physical materials is by default inferred from the + * `attenuationDistance` property. This node property allows to overwrite the default + * and define the attenuation distance with a node instead. + * + * If you don't want to overwrite the attenuation distance but modify the existing + * value instead, use {@link module:MaterialNode.materialAttenuationDistance}. + * + * @type {Node?} + * @default null + */ this.attenuationDistanceNode = null; + + /** + * The attenuation color of physical materials is by default inferred from the + * `attenuationColor` property. This node property allows to overwrite the default + * and define the attenuation color with a node instead. + * + * If you don't want to overwrite the attenuation color but modify the existing + * value instead, use {@link module:MaterialNode.materialAttenuationColor}. + * + * @type {Node?} + * @default null + */ this.attenuationColorNode = null; + + /** + * The dispersion of physical materials is by default inferred from the + * `dispersion` property. This node property allows to overwrite the default + * and define the dispersion with a node instead. + * + * If you don't want to overwrite the dispersion but modify the existing + * value instead, use {@link module:MaterialNode.materialDispersion}. + * + * @type {Node?} + * @default null + */ this.dispersionNode = null; + /** + * The anisotropy of physical materials is by default inferred from the + * `anisotropy` property. This node property allows to overwrite the default + * and define the anisotropy with a node instead. + * + * If you don't want to overwrite the anisotropy but modify the existing + * value instead, use {@link module:MaterialNode.materialAnisotropy}. + * + * @type {Node?} + * @default null + */ this.anisotropyNode = null; this.setDefaultValues( _defaultValues ); @@ -54,42 +269,81 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Whether the lighting model should use clearcoat or not. + * + * @type {Boolean} + * @default true + */ get useClearcoat() { return this.clearcoat > 0 || this.clearcoatNode !== null; } + /** + * Whether the lighting model should use iridescence or not. + * + * @type {Boolean} + * @default true + */ get useIridescence() { return this.iridescence > 0 || this.iridescenceNode !== null; } + /** + * Whether the lighting model should use sheen or not. + * + * @type {Boolean} + * @default true + */ get useSheen() { return this.sheen > 0 || this.sheenNode !== null; } + /** + * Whether the lighting model should use anisotropy or not. + * + * @type {Boolean} + * @default true + */ get useAnisotropy() { return this.anisotropy > 0 || this.anisotropyNode !== null; } + /** + * Whether the lighting model should use transmission or not. + * + * @type {Boolean} + * @default true + */ get useTransmission() { return this.transmission > 0 || this.transmissionNode !== null; } + /** + * Whether the lighting model should use dispersion or not. + * + * @type {Boolean} + * @default true + */ get useDispersion() { return this.dispersion > 0 || this.dispersionNode !== null; } + /** + * Setups the specular related node variables. + */ setupSpecular() { const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; @@ -100,12 +354,22 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhysicalLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhysicalLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion ); } + /** + * Setups the physical specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( builder ) { super.setupVariants( builder ); @@ -201,6 +465,11 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { } + /** + * Setups the clearcoat normal node. + * + * @return {Node} The clearcoat normal. + */ setupClearcoatNormal() { return this.clearcoatNormalNode ? vec3( this.clearcoatNormalNode ) : materialClearcoatNormal; diff --git a/src/materials/nodes/MeshSSSNodeMaterial.js b/src/materials/nodes/MeshSSSNodeMaterial.js index 064d9e4b896fe3..3c5736f48a173d 100644 --- a/src/materials/nodes/MeshSSSNodeMaterial.js +++ b/src/materials/nodes/MeshSSSNodeMaterial.js @@ -4,16 +4,49 @@ import { transformedNormalView } from '../../nodes/accessors/Normal.js'; import { positionViewDirection } from '../../nodes/accessors/Position.js'; import { float, vec3 } from '../../nodes/tsl/TSLBase.js'; -class SSSLightingModel extends PhysicalLightingModel { - - constructor( useClearcoat, useSheen, useIridescence, useSSS ) { +/** @module MeshSSSNodeMaterial **/ - super( useClearcoat, useSheen, useIridescence ); +/** + * Represents the lighting model for {@link MeshSSSNodeMaterial}. + * + * @augments PhysicalLightingModel + */ +class SSSLightingModel extends PhysicalLightingModel { - this.useSSS = useSSS; + /** + * Constructs a new physical lighting model. + * + * @param {Boolean} [clearcoat=false] - Whether clearcoat is supported or not. + * @param {Boolean} [sheen=false] - Whether sheen is supported or not. + * @param {Boolean} [iridescence=false] - Whether iridescence is supported or not. + * @param {Boolean} [anisotropy=false] - Whether anisotropy is supported or not. + * @param {Boolean} [transmission=false] - Whether transmission is supported or not. + * @param {Boolean} [dispersion=false] - Whether dispersion is supported or not. + * @param {Boolean} [sss=false] - Whether SSS is supported or not. + */ + constructor( clearcoat = false, sheen = false, iridescence = false, anisotropy = false, transmission = false, dispersion = false, sss = false ) { + + super( clearcoat, sheen, iridescence, anisotropy, transmission, dispersion ); + + /** + * Whether the lighting model should use SSS or not. + * + * @type {Boolean} + * @default false + */ + this.useSSS = sss; } + /** + * Extends the default implementation with a SSS term. + * + * Reference: [Approximating Translucency for a Fast, Cheap and Convincing Subsurface Scattering Look]{@link https://colinbarrebrisebois.com/2011/03/07/gdc-2011-approximating-translucency-for-a-fast-cheap-and-convincing-subsurface-scattering-look/} + * + * @param {Object} input - The input data. + * @param {StackNode} stack - The current stack. + * @param {NodeBuilder} builder - The current node builder. + */ direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) { if ( this.useSSS === true ) { @@ -36,6 +69,12 @@ class SSSLightingModel extends PhysicalLightingModel { } +/** + * This node material is an experimental extension of {@link MeshPhysicalNodeMaterial} + * that implements a Subsurface scattering (SSS) term. + * + * @augments MeshPhysicalNodeMaterial + */ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { static get type() { @@ -44,28 +83,80 @@ class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial { } + /** + * Constructs a new mesh SSS node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super( parameters ); + /** + * Represents the thickness color. + * + * @type {Node?} + * @default null + */ this.thicknessColorNode = null; + + /** + * Represents the distortion factor. + * + * @type {Node?} + */ this.thicknessDistortionNode = float( 0.1 ); + + /** + * Represents the thickness ambient factor. + * + * @type {Node?} + */ this.thicknessAmbientNode = float( 0.0 ); + + /** + * Represents the thickness attenuation. + * + * @type {Node?} + */ this.thicknessAttenuationNode = float( .1 ); + + /** + * Represents the thickness power. + * + * @type {Node?} + */ this.thicknessPowerNode = float( 2.0 ); + + /** + * Represents the thickness scale. + * + * @type {Node?} + */ this.thicknessScaleNode = float( 10.0 ); } + /** + * Whether the lighting model should use SSS or not. + * + * @type {Boolean} + * @default true + */ get useSSS() { return this.thicknessColorNode !== null; } + /** + * Setups the lighting model. + * + * @return {SSSLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { - return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useSSS ); + return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion, this.useSSS ); } diff --git a/src/materials/nodes/MeshStandardNodeMaterial.js b/src/materials/nodes/MeshStandardNodeMaterial.js index e7b5bce191981a..ef84543c133354 100644 --- a/src/materials/nodes/MeshStandardNodeMaterial.js +++ b/src/materials/nodes/MeshStandardNodeMaterial.js @@ -11,6 +11,11 @@ import { MeshStandardMaterial } from '../MeshStandardMaterial.js'; const _defaultValues = /*@__PURE__*/ new MeshStandardMaterial(); +/** + * Node material version of `MeshStandardMaterial`. + * + * @augments NodeMaterial + */ class MeshStandardNodeMaterial extends NodeMaterial { static get type() { @@ -19,17 +24,69 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh standard node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshStandardNodeMaterial = true; + /** + * Set to `true` because standard materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; + /** + * The emissive color of standard materials is by default inferred from the `emissive`, + * `emissiveIntensity` and `emissiveMap` properties. This node property allows to + * overwrite the default and define the emissive color with a node instead. + * + * If you don't want to overwrite the emissive color but modify the existing + * value instead, use {@link module:MaterialNode.materialEmissive}. + * + * @type {Node?} + * @default null + */ this.emissiveNode = null; + /** + * The metalness of standard materials is by default inferred from the `metalness`, + * and `metalnessMap` properties. This node property allows to + * overwrite the default and define the metalness with a node instead. + * + * If you don't want to overwrite the metalness but modify the existing + * value instead, use {@link module:MaterialNode.materialMetalness}. + * + * @type {Node?} + * @default null + */ this.metalnessNode = null; + + /** + * The roughness of standard materials is by default inferred from the `roughness`, + * and `roughnessMap` properties. This node property allows to + * overwrite the default and define the roughness with a node instead. + * + * If you don't want to overwrite the roughness but modify the existing + * value instead, use {@link module:MaterialNode.materialRoughness}. + * + * @type {Node?} + * @default null + */ this.roughnessNode = null; this.setDefaultValues( _defaultValues ); @@ -38,6 +95,14 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Overwritten since this type of material uses {@link EnvironmentNode} + * to implement the PBR (PMREM based) environment mapping. Besides, the + * method honors `Scene.environment`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {EnvironmentNode?} The environment node. + */ setupEnvironment( builder ) { let envNode = super.setupEnvironment( builder ); @@ -52,12 +117,20 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {PhysicalLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new PhysicalLightingModel(); } + /** + * Setups the specular related node variables. + */ setupSpecular() { const specularColorNode = mix( vec3( 0.04 ), diffuseColor.rgb, metalness ); @@ -67,6 +140,11 @@ class MeshStandardNodeMaterial extends NodeMaterial { } + /** + * Setups the standard specific node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants() { // METALNESS diff --git a/src/materials/nodes/MeshToonNodeMaterial.js b/src/materials/nodes/MeshToonNodeMaterial.js index 4137dcd5db5f1e..adaee0cfb0960b 100644 --- a/src/materials/nodes/MeshToonNodeMaterial.js +++ b/src/materials/nodes/MeshToonNodeMaterial.js @@ -5,6 +5,11 @@ import { MeshToonMaterial } from '../MeshToonMaterial.js'; const _defaultValues = /*@__PURE__*/ new MeshToonMaterial(); +/** + * Node material version of `MeshToonMaterial`. + * + * @augments NodeMaterial + */ class MeshToonNodeMaterial extends NodeMaterial { static get type() { @@ -13,12 +18,30 @@ class MeshToonNodeMaterial extends NodeMaterial { } + /** + * Constructs a new mesh toon node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMeshToonNodeMaterial = true; + /** + * Set to `true` because toon materials react on lights. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues ); @@ -27,6 +50,11 @@ class MeshToonNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {ToonLightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new ToonLightingModel(); diff --git a/src/materials/nodes/NodeMaterial.js b/src/materials/nodes/NodeMaterial.js index 77e5658609a846..dbcaf9926cb152 100644 --- a/src/materials/nodes/NodeMaterial.js +++ b/src/materials/nodes/NodeMaterial.js @@ -4,7 +4,7 @@ import { NormalBlending } from '../../constants.js'; import { getNodeChildren, getCacheKey } from '../../nodes/core/NodeUtils.js'; import { attribute } from '../../nodes/core/AttributeNode.js'; import { output, diffuseColor, emissive, varyingProperty } from '../../nodes/core/PropertyNode.js'; -import { materialAlphaTest, materialColor, materialOpacity, materialEmissive, materialNormal, materialLightMap, materialAOMap } from '../../nodes/accessors/MaterialNode.js'; +import { materialAlphaTest, materialColor, materialOpacity, materialEmissive, materialNormal, materialLightMap, materialAO } from '../../nodes/accessors/MaterialNode.js'; import { modelViewProjection } from '../../nodes/accessors/ModelViewProjectionNode.js'; import { normalLocal } from '../../nodes/accessors/Normal.js'; import { instancedMesh } from '../../nodes/accessors/InstancedMeshNode.js'; @@ -19,11 +19,17 @@ import AONode from '../../nodes/lighting/AONode.js'; import { lightingContext } from '../../nodes/lighting/LightingContextNode.js'; import IrradianceNode from '../../nodes/lighting/IrradianceNode.js'; import { depth, viewZToLogarithmicDepth, viewZToOrthographicDepth } from '../../nodes/display/ViewportDepthNode.js'; -import { cameraFar, cameraNear } from '../../nodes/accessors/Camera.js'; +import { cameraFar, cameraNear, cameraProjectionMatrix } from '../../nodes/accessors/Camera.js'; import { clipping, clippingAlpha, hardwareClipping } from '../../nodes/accessors/ClippingNode.js'; import NodeMaterialObserver from './manager/NodeMaterialObserver.js'; import getAlphaHashThreshold from '../../nodes/functions/material/getAlphaHashThreshold.js'; +import { modelViewMatrix } from '../../nodes/accessors/ModelNode.js'; +/** + * Base class for all node materials. + * + * @augments Material + */ class NodeMaterial extends Material { static get type() { @@ -32,6 +38,11 @@ class NodeMaterial extends Material { } + /** + * Represents the type of the node material. + * + * @type {String} + */ get type() { return this.constructor.type; @@ -40,66 +51,364 @@ class NodeMaterial extends Material { set type( _value ) { /* */ } + /** + * Constructs a new node material. + */ constructor() { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isNodeMaterial = true; - this.forceSinglePass = false; - + /** + * Whether this material is affected by fog or not. + * + * @type {Boolean} + * @default true + */ this.fog = true; + + /** + * Whether this material is affected by lights or not. + * + * @type {Boolean} + * @default false + */ this.lights = false; + + /** + * Whether this material uses hardware clipping or not. + * This property is managed by the engine and should not be + * modified by apps. + * + * @type {Boolean} + * @default false + */ this.hardwareClipping = false; + /** + * Node materials which set their `lights` property to `true` + * are affected by all lights of the scene. Sometimes selective + * lighting is wanted which means only _some_ lights in the scene + * affect a material. This can be achieved by creating an instance + * of {@link module:LightsNode~LightsNode} with a list of selective + * lights and assign the node to this property. + * + * ```js + * const customLightsNode = lights( [ light1, light2 ] ); + * material.lightsNode = customLightsNode; + * ``` + * + * @type {LightsNode?} + * @default null + */ this.lightsNode = null; + + /** + * The environment of node materials can be defined by an environment + * map assigned to the `envMap` property or by `Scene.environment` + * if the node material is a PBR material. This node property allows to overwrite + * the default behavior and define the environment with a custom node. + * + * ```js + * material.envNode = pmremTexture( renderTarget.texture ); + * ``` + * + * @type {Node?} + * @default null + */ this.envNode = null; + + /** + * The lighting of node materials might be influenced by ambient occlusion. + * The default AO is inferred from an ambient occlusion map assigned to `aoMap` + * and the respective `aoMapIntensity`. This node property allows to overwrite + * the default and define the ambient occlusion with a custom node instead. + * + * If you don't want to overwrite the diffuse color but modify the existing + * values instead, use {@link module:MaterialNode.materialAO}. + * + * @type {Node?} + * @default null + */ this.aoNode = null; + /** + * The diffuse color of node materials is by default inferred from the + * `color` and `map` properties. This node property allows to overwrite the default + * and define the diffuse color with a node instead. + * + * ```js + * material.colorNode = color( 0xff0000 ); // define red color + * ``` + * + * If you don't want to overwrite the diffuse color but modify the existing + * values instead, use {@link module:MaterialNode.materialColor}. + * + * ```js + * material.colorNode = materialColor.mul( color( 0xff0000 ) ); // give diffuse colors a red tint + * ``` + * + * @type {Node?} + * @default null + */ this.colorNode = null; + + /** + * The normals of node materials are by default inferred from the `normalMap`/`normalScale` + * or `bumpMap`/`bumpScale` properties. This node property allows to overwrite the default + * and define the normals with a node instead. + * + * If you don't want to overwrite the normals but modify the existing values instead, + * use {@link module:MaterialNode.materialNormal}. + * + * @type {Node?} + * @default null + */ this.normalNode = null; + + /** + * The opacity of node materials is by default inferred from the `opacity` + * and `alphaMap` properties. This node property allows to overwrite the default + * and define the opacity with a node instead. + * + * If you don't want to overwrite the normals but modify the existing + * value instead, use {@link module:MaterialNode.materialOpacity}. + * + * @type {Node?} + * @default null + */ this.opacityNode = null; + + /** + * This node can be used to to implement a variety of filter-like effects. The idea is + * to store the current rendering into a texture e.g. via `viewportSharedTexture()`, use it + * to create an arbitrary effect and then assign the node composition to this property. + * Everything behind the object using this material will now be affected by a filter. + * + * ```js + * const material = new NodeMaterial() + * material.transparent = true; + * + * // everything behind the object will be monochromatic + * material.backdropNode = viewportSharedTexture().rgb.saturation( 0 ); + * ``` + * + * Backdrop computations are part of the lighting so only lit materials can use this property. + * + * @type {Node?} + * @default null + */ this.backdropNode = null; + + /** + * This node allows to modulate the influence of `backdropNode` to the outgoing light. + * + * @type {Node?} + * @default null + */ this.backdropAlphaNode = null; + + /** + * The alpha test of node materials is by default inferred from the `alphaTest` + * property. This node property allows to overwrite the default and define the + * alpha test with a node instead. + * + * If you don't want to overwrite the alpha test but modify the existing + * value instead, use {@link module:MaterialNode.materialAlphaTest}. + * + * @type {Node?} + * @default null + */ this.alphaTestNode = null; + /** + * The local vertex positions are computed based on multiple factors like the + * attribute data, morphing or skinning. This node property allows to overwrite + * the default and define local vertex positions with nodes instead. + * + * If you don't want to overwrite the vertex positions but modify the existing + * values instead, use {@link module:Position.positionLocal}. + * + *```js + * material.positionNode = positionLocal.add( displace ); + * ``` + * + * @type {Node?} + * @default null + */ this.positionNode = null; + + /** + * This node property is intended for logic which modifies geometry data once or per animation step. + * Apps usually place such logic randomly in initialization routines or in the animation loop. + * `geometryNode` is intended as a dedicated API so there is an intended spot where geometry modifications + * can be implemented. + * + * The idea is to assign a `Fn` definition that holds the geometry modification logic. A typical example + * would be a GPU based particle system that provides a node material for usage on app level. The particle + * simulation would be implemented as compute shaders and managed inside a `Fn` function. This function is + * eventually assigned to `geometryNode`. + * + * @type {Function} + * @default null + */ this.geometryNode = null; + /** + * Allows to overwrite depth values in the fragment shader. + * + * @type {Node?} + * @default null + */ this.depthNode = null; + + /** + * Allows to overwrite the position used for shadow map rendering which + * is by default {@link module:Position.positionWorld}, the vertex position + * in world space. + * + * @type {Node?} + * @default null + */ this.shadowPositionNode = null; + + /** + * This node can be used to influence how an object using this node material + * receive shadows. + * + * ```js + * const totalShadows = float( 1 ).toVar(); + * material.receivedShadowNode = Fn( ( [ shadow ] ) => { + * totalShadows.mulAssign( shadow ); + * //return float( 1 ); // bypass received shadows + * return shadow.mix( color( 0xff0000 ), 1 ); // modify shadow color + * } ); + * + * @type {Node?} + * @default null + */ this.receivedShadowNode = null; + + /** + * This node can be used to influence how an object using this node material + * casts shadows. To apply a color to shadows, you can simply do: + * + * ```js + * material.castShadowNode = vec4( 1, 0, 0, 1 ); + * ``` + * + * Which can be nice to fake colored shadows of semi-transparent objects. It + * is also common to use the property with `Fn` function so checks are performed + * per fragment. + * + * ```js + * materialCustomShadow.castShadowNode = Fn( () => { + * hash( vertexIndex ).greaterThan( 0.5 ).discard(); + * return materialColor; + * } )(); + * ``` + * + * @type {Node?} + * @default null + */ this.castShadowNode = null; + /** + * This node can be used to define the final output of the material. + * + * TODO: Explain the differences to `fragmentNode`. + * + * @type {Node?} + * @default null + */ this.outputNode = null; + + /** + * MRT configuration is done on renderer or pass level. This node allows to + * overwrite what values are written into MRT targets on material level. This + * can be useful for implementing selective FX features that should only affect + * specific objects. + * + * @type {MRTNode?} + * @default null + */ this.mrtNode = null; + /** + * This node property can be used if you need complete freedom in implementing + * the fragment shader. Assigning a node will replace the built-in material + * logic used in the fragment stage. + * + * @type {Node?} + * @default null + */ this.fragmentNode = null; + + /** + * This node property can be used if you need complete freedom in implementing + * the vertex shader. Assigning a node will replace the built-in material logic + * used in the vertex stage. + * + * @type {Node?} + * @default null + */ this.vertexNode = null; } + /** + * Allows to define a custom cache key that influence the material key computation + * for render objects. + * + * @return {String} The custom cache key. + */ customProgramCacheKey() { return this.type + getCacheKey( this ); } + /** + * Builds this material with the given node builder. + * + * @param {NodeBuilder} builder - The current node builder. + */ build( builder ) { this.setup( builder ); } + /** + * Setups a node material observer with the given builder. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {NodeMaterialObserver} The node material observer. + */ setupObserver( builder ) { return new NodeMaterialObserver( builder ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { builder.context.setupNormal = () => this.setupNormal( builder ); + builder.context.setupPositionView = () => this.setupPositionView( builder ); + builder.context.setupModelViewProjection = () => this.setupModelViewProjection( builder ); const renderer = builder.renderer; const renderTarget = renderer.getRenderTarget(); @@ -108,7 +417,9 @@ class NodeMaterial extends Material { builder.addStack(); - builder.stack.outputNode = this.vertexNode || this.setupPosition( builder ); + const vertexNode = this.vertexNode || this.setupVertex( builder ); + + builder.stack.outputNode = vertexNode; this.setupHardwareClipping( builder ); @@ -128,7 +439,7 @@ class NodeMaterial extends Material { const clippingNode = this.setupClipping( builder ); - if ( this.depthWrite === true ) { + if ( this.depthWrite === true || this.depthTest === true ) { // only write depth if depth buffer is configured @@ -216,6 +527,12 @@ class NodeMaterial extends Material { } + /** + * Setups the clipping node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {ClippingNode} The clipping node. + */ setupClipping( builder ) { if ( builder.clippingContext === null ) return null; @@ -245,6 +562,11 @@ class NodeMaterial extends Material { } + /** + * Setups the hardware clipping if available on the current device. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupHardwareClipping( builder ) { this.hardwareClipping = false; @@ -267,6 +589,11 @@ class NodeMaterial extends Material { } + /** + * Setups the depth of this material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setupDepth( builder ) { const { renderer, camera } = builder; @@ -307,14 +634,58 @@ class NodeMaterial extends Material { } - setupPosition( builder ) { + /** + * Setups the position node in view space. This method exists + * so derived node materials can modify the implementation e.g. sprite materials. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in view space. + */ + setupPositionView( /*builder*/ ) { - const { object } = builder; - const geometry = object.geometry; + return modelViewMatrix.mul( positionLocal ).xyz; + + } + + /** + * Setups the position in clip space. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in view space. + */ + setupModelViewProjection( /*builder*/ ) { + + return cameraProjectionMatrix.mul( positionView ); + + } + + /** + * Setups the logic for the vertex stage. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in clip space. + */ + setupVertex( builder ) { builder.addStack(); - // Vertex + this.setupPosition( builder ); + + builder.context.vertex = builder.removeStack(); + + return modelViewProjection; + + } + + /** + * Setups the computation of the position in local space. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in local space. + */ + setupPosition( builder ) { + + const { object, geometry } = builder; if ( geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color ) { @@ -356,15 +727,16 @@ class NodeMaterial extends Material { } - const mvp = modelViewProjection(); - - builder.context.vertex = builder.removeStack(); - builder.context.mvp = mvp; - - return mvp; + return positionLocal; } + /** + * Setups the computation of the material's diffuse color. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {BufferGeometry} geometry - The geometry. + */ setupDiffuseColor( { object, geometry } ) { let colorNode = this.colorNode ? vec4( this.colorNode ) : materialColor; @@ -431,24 +803,47 @@ class NodeMaterial extends Material { } + /** + * Abstract interface method that can be implemented by derived materials + * to setup material-specific node variables. + * + * @abstract + * @param {NodeBuilder} builder - The current node builder. + */ setupVariants( /*builder*/ ) { // Interface function. } + /** + * Setups the outgoing light node variable + * + * @return {Node} The outgoing light node. + */ setupOutgoingLight() { return ( this.lights === true ) ? vec3( 0 ) : diffuseColor.rgb; } + /** + * Setups the normal node from the material. + * + * @return {Node} The normal node. + */ setupNormal() { return this.normalNode ? vec3( this.normalNode ) : materialNormal; } + /** + * Setups the environment node from the material. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The environment node. + */ setupEnvironment( /*builder*/ ) { let node = null; @@ -467,6 +862,12 @@ class NodeMaterial extends Material { } + /** + * Setups the light map node from the material. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The light map node. + */ setupLightMap( builder ) { let node = null; @@ -481,6 +882,12 @@ class NodeMaterial extends Material { } + /** + * Setups the lights node based on the scene, environment and material. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {LightsNode} The lights node. + */ setupLights( builder ) { const materialLightsNode = []; @@ -505,7 +912,7 @@ class NodeMaterial extends Material { if ( this.aoNode !== null || builder.material.aoMap ) { - const aoNode = this.aoNode !== null ? this.aoNode : materialAOMap; + const aoNode = this.aoNode !== null ? this.aoNode : materialAO; materialLightsNode.push( new AONode( aoNode ) ); @@ -523,12 +930,26 @@ class NodeMaterial extends Material { } + /** + * This method should be implemented by most derived materials + * since it defines the material's lighting model. + * + * @abstract + * @param {NodeBuilder} builder - The current node builder. + * @return {LightingModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { // Interface function. } + /** + * Setups the outgoing light node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The outgoing light node. + */ setupLighting( builder ) { const { material } = builder; @@ -568,6 +989,13 @@ class NodeMaterial extends Material { } + /** + * Setups the output node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} outputNode - The existing output node. + * @return {Node} The output node. + */ setupOutput( builder, outputNode ) { // FOG @@ -578,9 +1006,9 @@ class NodeMaterial extends Material { if ( fogNode ) { - const fog = vec4( fogNode ); + output.assign( outputNode ); - outputNode = vec4( fog.a.mix( outputNode.rgb, fog.rgb ), outputNode.a ); + outputNode = vec4( fogNode ); } @@ -590,6 +1018,13 @@ class NodeMaterial extends Material { } + /** + * Most classic material types have a node pendant e.g. for `MeshBasicMaterial` + * there is `MeshBasicNodeMaterial`. This utility method is intended for + * defining all material properties of the classic type in the node type. + * + * @param {Material} material - The material to copy properties with their values to this node material. + */ setDefaultValues( material ) { // This approach is to reuse the native refreshUniforms* @@ -624,6 +1059,12 @@ class NodeMaterial extends Material { } + /** + * Serializes this material to JSON. + * + * @param {(Object|String)?} meta - The meta information for serialization. + * @return {Object} The serialized node. + */ toJSON( meta ) { const isRoot = ( meta === undefined || typeof meta === 'string' ); @@ -683,6 +1124,12 @@ class NodeMaterial extends Material { } + /** + * Copies the properties of the given node material to this instance. + * + * @param {NodeMaterial} source - The material to copy. + * @return {NodeMaterial} A reference to this node material. + */ copy( source ) { this.lightsNode = source.lightsNode; diff --git a/src/materials/nodes/NodeMaterials.js b/src/materials/nodes/NodeMaterials.js index 329131de68abc2..ef7f4a3f79c421 100644 --- a/src/materials/nodes/NodeMaterials.js +++ b/src/materials/nodes/NodeMaterials.js @@ -3,7 +3,6 @@ export { default as NodeMaterialObserver } from './manager/NodeMaterialObserver.js'; export { default as NodeMaterial } from './NodeMaterial.js'; -export { default as InstancedPointsNodeMaterial } from './InstancedPointsNodeMaterial.js'; export { default as LineBasicNodeMaterial } from './LineBasicNodeMaterial.js'; export { default as LineDashedNodeMaterial } from './LineDashedNodeMaterial.js'; export { default as Line2NodeMaterial } from './Line2NodeMaterial.js'; diff --git a/src/materials/nodes/PointsNodeMaterial.js b/src/materials/nodes/PointsNodeMaterial.js index 028402d95f625f..fe1fdc3847e2e0 100644 --- a/src/materials/nodes/PointsNodeMaterial.js +++ b/src/materials/nodes/PointsNodeMaterial.js @@ -1,10 +1,21 @@ -import NodeMaterial from './NodeMaterial.js'; +import SpriteNodeMaterial from './SpriteNodeMaterial.js'; +import { viewport } from '../../nodes/display/ScreenNode.js'; +import { positionGeometry, positionLocal, positionView } from '../../nodes/accessors/Position.js'; +import { modelViewMatrix } from '../../nodes/accessors/ModelNode.js'; +import { materialPointSize } from '../../nodes/accessors/MaterialNode.js'; +import { rotate } from '../../nodes/utils/RotateNode.js'; +import { float, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js'; import { PointsMaterial } from '../PointsMaterial.js'; const _defaultValues = /*@__PURE__*/ new PointsMaterial(); -class PointsNodeMaterial extends NodeMaterial { +/** + * Node material version of `PointsMaterial`. + * + * @augments NodeMaterial + */ +class PointsNodeMaterial extends SpriteNodeMaterial { static get type() { @@ -12,28 +23,128 @@ class PointsNodeMaterial extends NodeMaterial { } + /** + * Constructs a new points node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); - this.isPointsNodeMaterial = true; - - this.lights = false; - this.transparent = true; - + /** + * This node property provides an additional way to set the point size. + * + * @type {Node?} + * @default null + */ this.sizeNode = null; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isPointsNodeMaterial = true; + this.setDefaultValues( _defaultValues ); this.setValues( parameters ); } - copy( source ) { + setupPositionView() { + + const { positionNode } = this; + + return modelViewMatrix.mul( vec3( positionNode || positionLocal ) ).xyz; + + } + + setupVertex( builder ) { + + const mvp = super.setupVertex( builder ); + + // skip further processing if the material is not a node material + + if ( builder.material.isNodeMaterial !== true ) { + + return mvp; + + } + + // ndc space + + const { rotationNode, scaleNode, sizeNode } = this; + + const alignedPosition = positionGeometry.xy.toVar(); + const aspect = viewport.z.div( viewport.w ); + + // rotation + + if ( rotationNode && rotationNode.isNode ) { + + const rotation = float( rotationNode ); + + alignedPosition.assign( rotate( alignedPosition, rotation ) ); + + } + + // point size + + let pointSize = sizeNode !== null ? vec2( sizeNode ) : materialPointSize; + + if ( this.sizeAttenuation === true ) { + + pointSize = pointSize.mul( pointSize.div( positionView.z.negate() ) ); + + } + + // scale + + if ( scaleNode && scaleNode.isNode ) { + + pointSize = pointSize.mul( vec2( scaleNode ) ); + + } + + alignedPosition.mulAssign( pointSize.mul( 2 ) ); + + alignedPosition.assign( alignedPosition.div( viewport.z ) ); + alignedPosition.y.assign( alignedPosition.y.mul( aspect ) ); + + // back to clip space + alignedPosition.assign( alignedPosition.mul( mvp.w ) ); + + //clipPos.xy += offset; + mvp.addAssign( vec4( alignedPosition, 0, 0 ) ); + + return mvp; + + } + + /** + * Whether alpha to coverage should be used or not. + * + * @type {Boolean} + * @default true + */ + get alphaToCoverage() { + + return this._useAlphaToCoverage; + + } + + set alphaToCoverage( value ) { + + if ( this._useAlphaToCoverage !== value ) { - this.sizeNode = source.sizeNode; + this._useAlphaToCoverage = value; + this.needsUpdate = true; - return super.copy( source ); + } } diff --git a/src/materials/nodes/ShadowNodeMaterial.js b/src/materials/nodes/ShadowNodeMaterial.js index 756c22599ee1c4..7470783cfd9dfa 100644 --- a/src/materials/nodes/ShadowNodeMaterial.js +++ b/src/materials/nodes/ShadowNodeMaterial.js @@ -5,6 +5,11 @@ import { ShadowMaterial } from '../ShadowMaterial.js'; const _defaultValues = /*@__PURE__*/ new ShadowMaterial(); +/** + * Node material version of `ShadowMaterial`. + * + * @augments NodeMaterial + */ class ShadowNodeMaterial extends NodeMaterial { static get type() { @@ -13,12 +18,31 @@ class ShadowNodeMaterial extends NodeMaterial { } + /** + * Constructs a new shadow node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isShadowNodeMaterial = true; + /** + * Set to `true` because so it's possible to implement + * the shadow mask effect. + * + * @type {Boolean} + * @default true + */ this.lights = true; this.setDefaultValues( _defaultValues ); @@ -27,6 +51,11 @@ class ShadowNodeMaterial extends NodeMaterial { } + /** + * Setups the lighting model. + * + * @return {ShadowMaskModel} The lighting model. + */ setupLightingModel( /*builder*/ ) { return new ShadowMaskModel(); diff --git a/src/materials/nodes/SpriteNodeMaterial.js b/src/materials/nodes/SpriteNodeMaterial.js index f17fb97dbeaa97..a490f3e7b4fd0f 100644 --- a/src/materials/nodes/SpriteNodeMaterial.js +++ b/src/materials/nodes/SpriteNodeMaterial.js @@ -2,7 +2,7 @@ import NodeMaterial from './NodeMaterial.js'; import { cameraProjectionMatrix } from '../../nodes/accessors/Camera.js'; import { materialRotation } from '../../nodes/accessors/MaterialNode.js'; import { modelViewMatrix, modelWorldMatrix } from '../../nodes/accessors/ModelNode.js'; -import { positionLocal } from '../../nodes/accessors/Position.js'; +import { positionGeometry } from '../../nodes/accessors/Position.js'; import { rotate } from '../../nodes/utils/RotateNode.js'; import { float, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js'; @@ -11,6 +11,11 @@ import { reference } from '../../nodes/accessors/ReferenceBaseNode.js'; const _defaultValues = /*@__PURE__*/ new SpriteMaterial(); +/** + * Node material version of `SpriteMaterial`. + * + * @augments NodeMaterial + */ class SpriteNodeMaterial extends NodeMaterial { static get type() { @@ -19,17 +24,66 @@ class SpriteNodeMaterial extends NodeMaterial { } + /** + * Constructs a new sprite node material. + * + * @param {Object?} parameters - The configuration parameter. + */ constructor( parameters ) { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSpriteNodeMaterial = true; - this.lights = false; this._useSizeAttenuation = true; + /** + * This property makes it possible to define the position of the sprite with a + * node. That can be useful when the material is used with instanced rendering + * and node data are defined with an instanced attribute node: + * ```js + * const positionAttribute = new InstancedBufferAttribute( new Float32Array( positions ), 3 ); + * material.positionNode = instancedBufferAttribute( positionAttribute ); + * ``` + * Another possibility is to compute the instanced data with a compute shader: + * ```js + * const positionBuffer = instancedArray( particleCount, 'vec3' ); + * particleMaterial.positionNode = positionBuffer.toAttribute(); + * ``` + * + * @type {Node?} + * @default null + */ this.positionNode = null; + + /** + * The rotation of sprite materials is by default inferred from the `rotation`, + * property. This node property allows to overwrite the default and define + * the rotation with a node instead. + * + * If you don't want to overwrite the rotation but modify the existing + * value instead, use {@link module:MaterialNode.materialRotation}. + * + * @type {Node?} + * @default null + */ this.rotationNode = null; + + /** + * This node property provides an additional way to scale sprites next to + * `Object3D.scale`. The scale transformation based in `Object3D.scale` + * is multiplied with the scale value of this node in the vertex shader. + * + * @type {Node?} + * @default null + */ this.scaleNode = null; this.setDefaultValues( _defaultValues ); @@ -38,28 +92,32 @@ class SpriteNodeMaterial extends NodeMaterial { } - setupPosition( { object, camera, context } ) { + /** + * Setups the position node in view space. This method implements + * the sprite specific vertex shader. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The position in view space. + */ + setupPositionView( builder ) { - const sizeAttenuation = this.sizeAttenuation; + const { object, camera } = builder; - // < VERTEX STAGE > + const sizeAttenuation = this.sizeAttenuation; const { positionNode, rotationNode, scaleNode } = this; - const vertex = positionLocal; - - let mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) ); + const mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) ); let scale = vec2( modelWorldMatrix[ 0 ].xyz.length(), modelWorldMatrix[ 1 ].xyz.length() ); if ( scaleNode !== null ) { - scale = scale.mul( scaleNode ); + scale = scale.mul( float( scaleNode ) ); } - - if ( ! sizeAttenuation ) { + if ( sizeAttenuation === false ) { if ( camera.isPerspectiveCamera ) { @@ -74,11 +132,11 @@ class SpriteNodeMaterial extends NodeMaterial { } - let alignedPosition = vertex.xy; + let alignedPosition = positionGeometry.xy; if ( object.center && object.center.isVector2 === true ) { - const center = reference( 'center', 'vec2' ); + const center = reference( 'center', 'vec2', object ); alignedPosition = alignedPosition.sub( center.sub( 0.5 ) ); @@ -90,13 +148,7 @@ class SpriteNodeMaterial extends NodeMaterial { const rotatedPosition = rotate( alignedPosition, rotation ); - mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw ); - - const modelViewProjection = cameraProjectionMatrix.mul( mvPosition ); - - context.vertex = vertex; - - return modelViewProjection; + return vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw ); } @@ -110,6 +162,12 @@ class SpriteNodeMaterial extends NodeMaterial { } + /** + * Whether to use size attenuation or not. + * + * @type {Boolean} + * @default true + */ get sizeAttenuation() { return this._useSizeAttenuation; diff --git a/src/materials/nodes/VolumeNodeMaterial.js b/src/materials/nodes/VolumeNodeMaterial.js index 39940174305e48..a6a0f50c96f4a5 100644 --- a/src/materials/nodes/VolumeNodeMaterial.js +++ b/src/materials/nodes/VolumeNodeMaterial.js @@ -8,7 +8,16 @@ import { Fn, varying, float, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js import { min, max } from '../../nodes/math/MathNode.js'; import { Loop, Break } from '../../nodes/utils/LoopNode.js'; import { texture3D } from '../../nodes/accessors/Texture3DNode.js'; +import { Color } from '../../math/Color.js'; +/** @module VolumeNodeMaterial **/ + +/** + * Node material intended for volume rendering. The volumetric data are + * defined with an instance of {@link Data3DTexture}. + * + * @augments NodeMaterial + */ class VolumeNodeMaterial extends NodeMaterial { static get type() { @@ -17,18 +26,85 @@ class VolumeNodeMaterial extends NodeMaterial { } - constructor( params = {} ) { + /** + * Constructs a new volume node material. + * + * @param {Object?} parameters - The configuration parameter. + */ + constructor( parameters ) { super(); - this.lights = false; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVolumeNodeMaterial = true; + + /** + * The base color of the volume. + * + * @type {Color} + * @default 100 + */ + this.base = new Color( 0xffffff ); + + /** + * A 3D data texture holding the volumetric data. + * + * @type {Data3DTexture?} + * @default null + */ + this.map = null; + + /** + * This number of samples for each ray that hits the mesh's surface + * and travels through the volume. + * + * @type {Number} + * @default 100 + */ + this.steps = 100; + + /** + * Callback for {@link VolumeNodeMaterial#testNode}. + * + * @callback testNodeCallback + * @param {Data3DTexture} map - The 3D texture. + * @param {Node} mapValue - The sampled value inside the volume. + * @param {Node} probe - The probe which is the entry point of the ray on the mesh's surface. + * @param {Node} finalColor - The final color. + */ + + /** + * The volume rendering of this material works by shooting rays + * from the camera position through each fragment of the mesh's + * surface and sample the inner volume in a raymarching fashion + * multiple times. + * + * This node can be used to assign a callback function of type `Fn` + * that will be executed per sample. The callback receives the + * texture, the sampled texture value as well as position on the surface + * where the rays enters the volume. The last parameter is a color + * that allows the callback to determine the final color. + * + * @type {testNodeCallback?} + * @default null + */ this.testNode = null; - this.setValues( params ); + this.setValues( parameters ); } + /** + * Setups the vertex and fragment stage of this node material. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const map = texture3D( this.map, null, 0 ); diff --git a/src/materials/nodes/manager/NodeMaterialObserver.js b/src/materials/nodes/manager/NodeMaterialObserver.js index d7865a70fb6bf7..6a193f594093fd 100644 --- a/src/materials/nodes/manager/NodeMaterialObserver.js +++ b/src/materials/nodes/manager/NodeMaterialObserver.js @@ -51,18 +51,65 @@ const refreshUniforms = [ 'transmissionMap' ]; +/** + * This class is used by {@link WebGPURenderer} as management component. + * It's primary purpose is to determine whether render objects require a + * refresh right before they are going to be rendered or not. + */ class NodeMaterialObserver { + /** + * Constructs a new node material observer. + * + * @param {NodeBuilder} builder - The node builder. + */ constructor( builder ) { + /** + * A node material can be used by more than one render object so the + * monitor must maintain a list of render objects. + * + * @type {WeakMap} + */ this.renderObjects = new WeakMap(); + + /** + * Whether the material uses node objects or not. + * + * @type {Boolean} + */ this.hasNode = this.containsNode( builder ); + + /** + * Whether the node builder's 3D object is animated or not. + * + * @type {Boolean} + */ this.hasAnimation = builder.object.isSkinnedMesh === true; + + /** + * A list of all possible material uniforms + * + * @type {Array} + */ this.refreshUniforms = refreshUniforms; + + /** + * Holds the current render ID from the node frame. + * + * @type {Number} + * @default 0 + */ this.renderId = 0; } + /** + * Returns `true` if the given render object is verified for the first time of this observer. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object is verified for the first time of this observer. + */ firstInitialization( renderObject ) { const hasInitialized = this.renderObjects.has( renderObject ); @@ -79,6 +126,12 @@ class NodeMaterialObserver { } + /** + * Returns monitoring data for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Object} The monitoring data. + */ getRenderObjectData( renderObject ) { let data = this.renderObjects.get( renderObject ); @@ -132,6 +185,13 @@ class NodeMaterialObserver { } + /** + * Returns an attribute data structure holding the attributes versions for + * monitoring. + * + * @param {Object} attributes - The geometry attributes. + * @return {Object} An object for monitoring the versions of attributes. + */ getAttributesData( attributes ) { const attributesData = {}; @@ -150,6 +210,13 @@ class NodeMaterialObserver { } + /** + * Returns `true` if the node builder's material uses + * node properties. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Boolean} Whether the node builder's material uses node properties or not. + */ containsNode( builder ) { const material = builder.material; @@ -168,6 +235,13 @@ class NodeMaterialObserver { } + /** + * Returns a material data structure holding the material property values for + * monitoring. + * + * @param {Material} material - The material. + * @return {Object} An object for monitoring material properties. + */ getMaterialData( material ) { const data = {}; @@ -202,6 +276,12 @@ class NodeMaterialObserver { } + /** + * Returns `true` if the given render object has not changed its state. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object has changed its state or not. + */ equals( renderObject ) { const { object, material, geometry } = renderObject; @@ -382,6 +462,13 @@ class NodeMaterialObserver { } + /** + * Checks if the given render object requires a refresh. + * + * @param {RenderObject} renderObject - The render object. + * @param {NodeFrame} nodeFrame - The current node frame. + * @return {Boolean} Whether the given render object requires a refresh or not. + */ needsRefresh( renderObject, nodeFrame ) { if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) ) diff --git a/src/nodes/Nodes.js b/src/nodes/Nodes.js index 2ee1dc41730707..a9decb72e8255c 100644 --- a/src/nodes/Nodes.js +++ b/src/nodes/Nodes.js @@ -67,7 +67,6 @@ export { default as MaterialReferenceNode } from './accessors/MaterialReferenceN export { default as RendererReferenceNode } from './accessors/RendererReferenceNode.js'; export { default as MorphNode } from './accessors/MorphNode.js'; export { default as ModelNode } from './accessors/ModelNode.js'; -export { default as ModelViewProjectionNode } from './accessors/ModelViewProjectionNode.js'; export { default as Object3DNode } from './accessors/Object3DNode.js'; export { default as PointUVNode } from './accessors/PointUVNode.js'; export { default as ReferenceNode } from './accessors/ReferenceNode.js'; diff --git a/src/nodes/TSL.js b/src/nodes/TSL.js index 0f9e49e086e9d6..d4e8963e73dfa5 100644 --- a/src/nodes/TSL.js +++ b/src/nodes/TSL.js @@ -131,6 +131,7 @@ export * from './gpgpu/AtomicFunctionNode.js'; export * from './accessors/Lights.js'; export * from './lighting/LightsNode.js'; export * from './lighting/LightingContextNode.js'; +export * from './lighting/ShadowBaseNode.js'; export * from './lighting/ShadowNode.js'; export * from './lighting/PointLightNode.js'; @@ -141,6 +142,9 @@ export * from './pmrem/PMREMUtils.js'; // procedural export * from './procedural/Checker.js'; +// shapes +export * from './shapes/Shapes.js'; + // materialX export * from './materialx/MaterialXNodes.js'; diff --git a/src/nodes/accessors/AccessorsUtils.js b/src/nodes/accessors/AccessorsUtils.js index bcd2d72863e432..28c5dd851f634d 100644 --- a/src/nodes/accessors/AccessorsUtils.js +++ b/src/nodes/accessors/AccessorsUtils.js @@ -6,11 +6,38 @@ import { mix } from '../math/MathNode.js'; import { anisotropy, anisotropyB, roughness } from '../core/PropertyNode.js'; import { positionViewDirection } from './Position.js'; +/** @module AccessorsUtils **/ + +/** + * TSL object that represents the TBN matrix in view space. + * + * @type {Node} + */ export const TBNViewMatrix = /*@__PURE__*/ mat3( tangentView, bitangentView, normalView ); +/** + * TSL object that represents the parallax direction. + * + * @type {Node} + */ export const parallaxDirection = /*@__PURE__*/ positionViewDirection.mul( TBNViewMatrix )/*.normalize()*/; + +/** + * TSL function for computing parallax uv coordinates. + * + * @function + * @param {Node} uv - A uv node. + * @param {Node} scale - A scale node. + * @returns {Node} Parallax uv coordinates. + */ export const parallaxUV = ( uv, scale ) => uv.sub( parallaxDirection.mul( scale ) ); +/** + * TSL function for computing bent normals. + * + * @function + * @returns {Node} Bent normals. + */ export const transformedBentNormalView = /*@__PURE__*/ ( () => { // https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/anisotropy diff --git a/src/nodes/accessors/Arrays.js b/src/nodes/accessors/Arrays.js index 8108669fc63965..219ebe8b7bf575 100644 --- a/src/nodes/accessors/Arrays.js +++ b/src/nodes/accessors/Arrays.js @@ -1,25 +1,44 @@ import StorageInstancedBufferAttribute from '../../renderers/common/StorageInstancedBufferAttribute.js'; import StorageBufferAttribute from '../../renderers/common/StorageBufferAttribute.js'; import { storage } from './StorageBufferNode.js'; -import { getLengthFromType } from '../core/NodeUtils.js'; - +import { getLengthFromType, getTypedArrayFromType } from '../core/NodeUtils.js'; + +/** @module Arrays **/ + +/** + * TSL function for creating a storage buffer node with a configured `StorageBufferAttribute`. + * + * @function + * @param {Number} count - The data count. + * @param {String} [type='float'] - The data type. + * @returns {StorageBufferNode} + */ export const attributeArray = ( count, type = 'float' ) => { const itemSize = getLengthFromType( type ); + const typedArray = getTypedArrayFromType( type ); - const buffer = new StorageBufferAttribute( count, itemSize ); + const buffer = new StorageBufferAttribute( count, itemSize, typedArray ); const node = storage( buffer, type, count ); return node; }; - +/** + * TSL function for creating a storage buffer node with a configured `StorageInstancedBufferAttribute`. + * + * @function + * @param {Number} count - The data count. + * @param {String} [type='float'] - The data type. + * @returns {StorageBufferNode} + */ export const instancedArray = ( count, type = 'float' ) => { const itemSize = getLengthFromType( type ); + const typedArray = getTypedArrayFromType( type ); - const buffer = new StorageInstancedBufferAttribute( count, itemSize ); + const buffer = new StorageInstancedBufferAttribute( count, itemSize, typedArray ); const node = storage( buffer, type, count ); return node; diff --git a/src/nodes/accessors/BatchNode.js b/src/nodes/accessors/BatchNode.js index 74661a0a71fe05..16dad25b412077 100644 --- a/src/nodes/accessors/BatchNode.js +++ b/src/nodes/accessors/BatchNode.js @@ -8,6 +8,15 @@ import { tangentLocal } from './Tangent.js'; import { instanceIndex, drawIndex } from '../core/IndexNode.js'; import { varyingProperty } from '../core/PropertyNode.js'; +/** @module BatchNode **/ + +/** + * This node implements the vertex shader logic which is required + * when rendering 3D objects via batching. `BatchNode` must be used + * with instances of {@link BatchedMesh}. + * + * @augments Node + */ class BatchNode extends Node { static get type() { @@ -16,21 +25,41 @@ class BatchNode extends Node { } + /** + * Constructs a new batch node. + * + * @param {BatchedMesh} batchMesh - A reference to batched mesh. + */ constructor( batchMesh ) { super( 'void' ); + /** + * A reference to batched mesh. + * + * @type {BatchedMesh} + */ this.batchMesh = batchMesh; - + /** + * The batching index node. + * + * @type {IndexNode?} + * @default null + */ this.batchingIdNode = null; } + /** + * Setups the internal buffers and nodes and assigns the transformed vertex data + * to predefined node variables for accumulation. That follows the same patterns + * like with morph and skinning nodes. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { - // POSITION - if ( this.batchingIdNode === null ) { if ( builder.getDrawIndex() === null ) { @@ -125,4 +154,11 @@ class BatchNode extends Node { export default BatchNode; +/** + * TSL function for creating a batch node. + * + * @function + * @param {BatchedMesh} batchMesh - A reference to batched mesh. + * @returns {BatchNode} + */ export const batch = /*@__PURE__*/ nodeProxy( BatchNode ); diff --git a/src/nodes/accessors/Bitangent.js b/src/nodes/accessors/Bitangent.js index ff76e5fffd105e..87af35b760ea73 100644 --- a/src/nodes/accessors/Bitangent.js +++ b/src/nodes/accessors/Bitangent.js @@ -3,11 +3,48 @@ import { cameraViewMatrix } from './Camera.js'; import { normalGeometry, normalLocal, normalView, normalWorld, transformedNormalView } from './Normal.js'; import { tangentGeometry, tangentLocal, tangentView, tangentWorld, transformedTangentView } from './Tangent.js'; +/** @module Bitangent **/ + const getBitangent = ( crossNormalTangent ) => crossNormalTangent.mul( tangentGeometry.w ).xyz; +/** + * TSL object that represents the bitangent attribute of the current rendered object. + * + * @type {Node} + */ export const bitangentGeometry = /*@__PURE__*/ varying( getBitangent( normalGeometry.cross( tangentGeometry ) ), 'v_bitangentGeometry' ).normalize().toVar( 'bitangentGeometry' ); + +/** + * TSL object that represents the vertex bitangent in local space of the current rendered object. + * + * @type {Node} + */ export const bitangentLocal = /*@__PURE__*/ varying( getBitangent( normalLocal.cross( tangentLocal ) ), 'v_bitangentLocal' ).normalize().toVar( 'bitangentLocal' ); + +/** + * TSL object that represents the vertex bitangent in view space of the current rendered object. + * + * @type {Node} + */ export const bitangentView = /*@__PURE__*/ varying( getBitangent( normalView.cross( tangentView ) ), 'v_bitangentView' ).normalize().toVar( 'bitangentView' ); + +/** + * TSL object that represents the vertex bitangent in world space of the current rendered object. + * + * @type {Node} + */ export const bitangentWorld = /*@__PURE__*/ varying( getBitangent( normalWorld.cross( tangentWorld ) ), 'v_bitangentWorld' ).normalize().toVar( 'bitangentWorld' ); + +/** + * TSL object that represents the transformed vertex bitangent in view space of the current rendered object. + * + * @type {Node} + */ export const transformedBitangentView = /*@__PURE__*/ getBitangent( transformedNormalView.cross( transformedTangentView ) ).normalize().toVar( 'transformedBitangentView' ); + +/** + * TSL object that represents the transformed vertex bitangent in world space of the current rendered object. + * + * @type {Node} + */ export const transformedBitangentWorld = /*@__PURE__*/ transformedBitangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedBitangentWorld' ); diff --git a/src/nodes/accessors/BufferAttributeNode.js b/src/nodes/accessors/BufferAttributeNode.js index 26ea11c0c5c00b..3b135c47b3506f 100644 --- a/src/nodes/accessors/BufferAttributeNode.js +++ b/src/nodes/accessors/BufferAttributeNode.js @@ -6,6 +6,30 @@ import { InterleavedBufferAttribute } from '../../core/InterleavedBufferAttribut import { InterleavedBuffer } from '../../core/InterleavedBuffer.js'; import { StaticDrawUsage, DynamicDrawUsage } from '../../constants.js'; +/** @module BufferAttributeNode **/ + +/** + * In earlier `three.js` versions it was only possible to define attribute data + * on geometry level. With `BufferAttributeNode`, it is also possible to do this + * on the node level. + * ```js + * const geometry = new THREE.PlaneGeometry(); + * const positionAttribute = geometry.getAttribute( 'position' ); + * + * const colors = []; + * for ( let i = 0; i < position.count; i ++ ) { + * colors.push( 1, 0, 0 ); + * } + * + * material.colorNode = bufferAttribute( new THREE.Float32BufferAttribute( colors, 3 ) ); + * ``` + * This new approach is especially interesting when geometry data are generated via + * compute shaders. The below line converts a storage buffer into an attribute node. + * ```js + * material.positionNode = positionBuffer.toAttribute(); + * ``` + * @augments InputNode + */ class BufferAttributeNode extends InputNode { static get type() { @@ -14,21 +38,82 @@ class BufferAttributeNode extends InputNode { } + /** + * Constructs a new buffer attribute node. + * + * @param {BufferAttribute|InterleavedBuffer|TypedArray} value - The attribute data. + * @param {String?} [bufferType=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [bufferStride=0] - The buffer stride. + * @param {Number} [bufferOffset=0] - The buffer offset. + */ constructor( value, bufferType = null, bufferStride = 0, bufferOffset = 0 ) { super( value, bufferType ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBufferNode = true; + /** + * The buffer type (e.g. `'vec3'`). + * + * @type {String} + * @default null + */ this.bufferType = bufferType; + + /** + * The buffer stride. + * + * @type {Number} + * @default 0 + */ this.bufferStride = bufferStride; + + /** + * The buffer offset. + * + * @type {Number} + * @default 0 + */ this.bufferOffset = bufferOffset; + /** + * The usage property. Set this to `THREE.DynamicDrawUsage` via `.setUsage()`, + * if you are planning to update the attribute data per frame. + * + * @type {Number} + * @default StaticDrawUsage + */ this.usage = StaticDrawUsage; + + /** + * Whether the attribute is instanced or not. + * + * @type {Boolean} + * @default false + */ this.instanced = false; + /** + * A reference to the buffer attribute. + * + * @type {BufferAttribute?} + * @default null + */ this.attribute = null; + /** + * `BufferAttributeNode` sets this property to `true` by default. + * + * @type {Boolean} + * @default true + */ this.global = true; if ( value && value.isBufferAttribute === true ) { @@ -41,6 +126,13 @@ class BufferAttributeNode extends InputNode { } + /** + * This method is overwritten since the attribute data might be shared + * and thus the hash should be shared as well. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The hash. + */ getHash( builder ) { if ( this.bufferStride === 0 && this.bufferOffset === 0 ) { @@ -65,6 +157,13 @@ class BufferAttributeNode extends InputNode { } + /** + * This method is overwritten since the node type is inferred from + * the buffer attribute. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( this.bufferType === null ) { @@ -77,6 +176,13 @@ class BufferAttributeNode extends InputNode { } + /** + * Depending on which value was passed to the node, `setup()` behaves + * differently. If no instance of `BufferAttribute` was passed, the method + * creates an internal attribute and configures it respectively. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { if ( this.attribute !== null ) return; @@ -97,6 +203,12 @@ class BufferAttributeNode extends InputNode { } + /** + * Generates the code snippet of the buffer attribute node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( builder ) { const nodeType = this.getNodeType( builder ); @@ -124,12 +236,24 @@ class BufferAttributeNode extends InputNode { } + /** + * Overwrites the default implementation to return a fixed value `'bufferAttribute'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'bufferAttribute'; } + /** + * Sets the `usage` property to the given value. + * + * @param {Number} value - The usage to set. + * @return {BufferAttributeNode} A reference to this node. + */ setUsage( value ) { this.usage = value; @@ -144,6 +268,12 @@ class BufferAttributeNode extends InputNode { } + /** + * Sets the `instanced` property to the given value. + * + * @param {Boolean} value - The value to set. + * @return {BufferAttributeNode} A reference to this node. + */ setInstanced( value ) { this.instanced = value; @@ -156,10 +286,53 @@ class BufferAttributeNode extends InputNode { export default BufferAttributeNode; -export const bufferAttribute = ( array, type, stride, offset ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) ); -export const dynamicBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage ); - -export const instancedBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setInstanced( true ); -export const instancedDynamicBufferAttribute = ( array, type, stride, offset ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true ); +/** + * TSL function for creating a buffer attribute node. + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +export const bufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) ); + +/** + * TSL function for creating a buffer attribute node but with dynamic draw usage. + * Use this function if attribute data are updated per frame. + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +export const dynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage ); + +/** + * TSL function for creating a buffer attribute node but with enabled instancing + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +export const instancedBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => bufferAttribute( array, type, stride, offset ).setInstanced( true ); + +/** + * TSL function for creating a buffer attribute node but with dynamic draw usage and enabled instancing + * + * @function + * @param {BufferAttribute|InterleavedBuffer|TypedArray} array - The attribute data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [stride=0] - The buffer stride. + * @param {Number} [offset=0] - The buffer offset. + * @returns {BufferAttributeNode} + */ +export const instancedDynamicBufferAttribute = ( array, type = null, stride = 0, offset = 0 ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true ); addMethodChaining( 'toAttribute', ( bufferNode ) => bufferAttribute( bufferNode.value ) ); diff --git a/src/nodes/accessors/BufferNode.js b/src/nodes/accessors/BufferNode.js index 80ce74f4c4a220..bf0ffd7747041d 100644 --- a/src/nodes/accessors/BufferNode.js +++ b/src/nodes/accessors/BufferNode.js @@ -1,6 +1,22 @@ import UniformNode from '../core/UniformNode.js'; import { nodeObject } from '../tsl/TSLBase.js'; +/** @module BufferNode **/ + +/** + * A special type of uniform node which represents array-like data + * as uniform buffers. The access usually happens via `element()` + * which returns an instance of {@link ArrayElementNode}. For example: + * + * ```js + * const bufferNode = buffer( array, 'mat4', count ); + * const matrixNode = bufferNode.element( index ); // access a matrix from the buffer + * ``` + * In general, it is recommended to use the more managed {@link UniformArrayNode} + * since it handles more input types and automatically cares about buffer paddings. + * + * @augments module:UniformNode~UniformNode + */ class BufferNode extends UniformNode { static get type() { @@ -9,23 +25,61 @@ class BufferNode extends UniformNode { } + /** + * Constructs a new buffer node. + * + * @param {Array} value - Array-like buffer data. + * @param {String} bufferType - The data type of the buffer. + * @param {Number} [bufferCount=0] - The count of buffer elements. + */ constructor( value, bufferType, bufferCount = 0 ) { super( value, bufferType ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBufferNode = true; + /** + * The data type of the buffer. + * + * @type {String} + */ this.bufferType = bufferType; + + /** + * The uniform node that holds the value of the reference node. + * + * @type {Number} + * @default 0 + */ this.bufferCount = bufferCount; } + /** + * The data type of the buffer elements. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The element type. + */ getElementType( builder ) { return this.getNodeType( builder ); } + /** + * Overwrites the default implementation to return a fixed value `'buffer'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'buffer'; @@ -36,4 +90,13 @@ class BufferNode extends UniformNode { export default BufferNode; +/** + * TSL function for creating a buffer node. + * + * @function + * @param {Array} value - Array-like buffer data. + * @param {String} type - The data type of a buffer element. + * @param {Number} count - The count of buffer elements. + * @returns {BufferNode} + */ export const buffer = ( value, type, count ) => nodeObject( new BufferNode( value, type, count ) ); diff --git a/src/nodes/accessors/BuiltinNode.js b/src/nodes/accessors/BuiltinNode.js index 50c88643b09ea0..e694f0a83b6451 100644 --- a/src/nodes/accessors/BuiltinNode.js +++ b/src/nodes/accessors/BuiltinNode.js @@ -1,18 +1,49 @@ import Node from '../core/Node.js'; import { nodeProxy } from '../tsl/TSLBase.js'; +/** @module BuiltinNode **/ + +/** + * The node allows to set values for built-in shader variables. That is + * required for features like hardware-accelerated vertex clipping. + * + * @augments Node + */ class BuiltinNode extends Node { + /** + * Constructs a new builtin node. + * + * @param {String} name - The name of the built-in shader variable. + */ constructor( name ) { super( 'float' ); + /** + * The name of the built-in shader variable. + * + * @type {String} + */ this.name = name; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBuiltinNode = true; } + /** + * Generates the code snippet of the builtin node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( /* builder */ ) { return this.name; @@ -23,4 +54,11 @@ class BuiltinNode extends Node { export default BuiltinNode; +/** + * TSL function for creating a builtin node. + * + * @function + * @param {String} name - The name of the built-in shader variable. + * @returns {BuiltinNode} + */ export const builtin = nodeProxy( BuiltinNode ); diff --git a/src/nodes/accessors/Camera.js b/src/nodes/accessors/Camera.js index ae67f4385bab21..660c4684ff2f0f 100644 --- a/src/nodes/accessors/Camera.js +++ b/src/nodes/accessors/Camera.js @@ -54,7 +54,7 @@ export const cameraWorldMatrix = /*@__PURE__*/ uniform( 'mat4' ).label( 'cameraW export const cameraNormalMatrix = /*@__PURE__*/ uniform( 'mat3' ).label( 'cameraNormalMatrix' ).setGroup( renderGroup ).onRenderUpdate( ( { camera } ) => camera.normalMatrix ); /** - * TSL object that represents the positon in world space of the camera used for the current render. + * TSL object that represents the position in world space of the camera used for the current render. * * @type {UniformNode} */ diff --git a/src/nodes/accessors/ClippingNode.js b/src/nodes/accessors/ClippingNode.js index f87014deb75c58..58dc03240761cb 100644 --- a/src/nodes/accessors/ClippingNode.js +++ b/src/nodes/accessors/ClippingNode.js @@ -8,6 +8,16 @@ import { smoothstep } from '../math/MathNode.js'; import { uniformArray } from './UniformArrayNode.js'; import { builtin } from './BuiltinNode.js'; +/** @module ClippingNode **/ + +/** + * ``` + * This node is used in {@link NodeMaterial} to setup the clipping + * which can happen hardware-accelerated (if supported) and optionally + * use alpha-to-coverage for anti-aliasing clipped edges. + * ``` + * @augments Node + */ class ClippingNode extends Node { static get type() { @@ -16,14 +26,32 @@ class ClippingNode extends Node { } + /** + * Constructs a new clipping node. + * + * @param {('default'|'hardware'|'alphaToCoverage')} [scope='default'] - The node's scope. Similar to other nodes, + * the selected scope influences the behavior of the node and what type of code is generated. + */ constructor( scope = ClippingNode.DEFAULT ) { super(); + /** + * The node's scope. Similar to other nodes, the selected scope influences + * the behavior of the node and what type of code is generated. + * + * @type {('default'|'hardware'|'alphaToCoverage')} + */ this.scope = scope; } + /** + * Setups the node depending on the selected scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The result node. + */ setup( builder ) { super.setup( builder ); @@ -49,6 +77,13 @@ class ClippingNode extends Node { } + /** + * Setups alpha to coverage. + * + * @param {Array} intersectionPlanes - The intersection planes. + * @param {Array} unionPlanes - The union planes. + * @return {Node} The result node. + */ setupAlphaToCoverage( intersectionPlanes, unionPlanes ) { return Fn( () => { @@ -60,7 +95,7 @@ class ClippingNode extends Node { const numUnionPlanes = unionPlanes.length; - if ( ! this.hardwareClipping && numUnionPlanes > 0 ) { + if ( this.hardwareClipping === false && numUnionPlanes > 0 ) { const clippingPlanes = uniformArray( unionPlanes ); @@ -107,13 +142,20 @@ class ClippingNode extends Node { } + /** + * Setups the default clipping. + * + * @param {Array} intersectionPlanes - The intersection planes. + * @param {Array} unionPlanes - The union planes. + * @return {Node} The result node. + */ setupDefault( intersectionPlanes, unionPlanes ) { return Fn( () => { const numUnionPlanes = unionPlanes.length; - if ( ! this.hardwareClipping && numUnionPlanes > 0 ) { + if ( this.hardwareClipping === false && numUnionPlanes > 0 ) { const clippingPlanes = uniformArray( unionPlanes ); @@ -148,6 +190,13 @@ class ClippingNode extends Node { } + /** + * Setups hardware clipping. + * + * @param {Array} unionPlanes - The union planes. + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The result node. + */ setupHardwareClipping( unionPlanes, builder ) { const numUnionPlanes = unionPlanes.length; @@ -180,6 +229,26 @@ ClippingNode.HARDWARE = 'hardware'; export default ClippingNode; +/** + * TSL function for setting up the default clipping logic. + * + * @function + * @returns {ClippingNode} + */ export const clipping = () => nodeObject( new ClippingNode() ); + +/** + * TSL function for setting up alpha to coverage. + * + * @function + * @returns {ClippingNode} + */ export const clippingAlpha = () => nodeObject( new ClippingNode( ClippingNode.ALPHA_TO_COVERAGE ) ); + +/** + * TSL function for setting up hardware-based clipping. + * + * @function + * @returns {ClippingNode} + */ export const hardwareClipping = () => nodeObject( new ClippingNode( ClippingNode.HARDWARE ) ); diff --git a/src/nodes/accessors/CubeTextureNode.js b/src/nodes/accessors/CubeTextureNode.js index a376268976cda0..18cedc7c0233d6 100644 --- a/src/nodes/accessors/CubeTextureNode.js +++ b/src/nodes/accessors/CubeTextureNode.js @@ -4,6 +4,13 @@ import { nodeProxy, vec3 } from '../tsl/TSLBase.js'; import { CubeReflectionMapping, CubeRefractionMapping, WebGPUCoordinateSystem } from '../../constants.js'; +/** @module CubeTextureNode **/ + +/** + * This type of uniform node represents a cube texture. + * + * @augments module:TextureNode~TextureNode + */ class CubeTextureNode extends TextureNode { static get type() { @@ -12,20 +19,46 @@ class CubeTextureNode extends TextureNode { } + /** + * Constructs a new cube texture node. + * + * @param {CubeTexture} value - The cube texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + */ constructor( value, uvNode = null, levelNode = null, biasNode = null ) { super( value, uvNode, levelNode, biasNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isCubeTextureNode = true; } + /** + * Overwrites the default implementation to return a fixed value `'cubeTexture'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'cubeTexture'; } + /** + * Returns a default uvs based on the mapping type of the cube texture. + * + * @return {Node} The default uv attribute. + */ getDefaultUV() { const texture = this.value; @@ -48,8 +81,22 @@ class CubeTextureNode extends TextureNode { } + /** + * Overwritten with an empty implementation since the `updateMatrix` flag is ignored + * for cube textures. The uv transformation matrix is not applied to cube textures. + * + * @param {Boolean} value - The update toggle. + */ setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for CubeTextureNode + /** + * Setups the uv node. Depending on the backend as well as the texture type, it might be necessary + * to modify the uv node for correct sampling. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to setup. + * @return {Node} The updated uv node. + */ setupUV( builder, uvNode ) { const texture = this.value; @@ -66,6 +113,13 @@ class CubeTextureNode extends TextureNode { } + /** + * Generates the uv code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} cubeUV - The uv node to generate code for. + * @return {String} The generated code snippet. + */ generateUV( builder, cubeUV ) { return cubeUV.build( builder, 'vec3' ); @@ -76,4 +130,14 @@ class CubeTextureNode extends TextureNode { export default CubeTextureNode; +/** + * TSL function for creating a cube texture node. + * + * @function + * @param {CubeTexture} value - The cube texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + * @returns {CubeTextureNode} + */ export const cubeTexture = /*@__PURE__*/ nodeProxy( CubeTextureNode ); diff --git a/src/nodes/accessors/InstanceNode.js b/src/nodes/accessors/InstanceNode.js index 5a552441947fa9..213504076cb736 100644 --- a/src/nodes/accessors/InstanceNode.js +++ b/src/nodes/accessors/InstanceNode.js @@ -12,6 +12,16 @@ import { InstancedInterleavedBuffer } from '../../core/InstancedInterleavedBuffe import { InstancedBufferAttribute } from '../../core/InstancedBufferAttribute.js'; import { DynamicDrawUsage } from '../../constants.js'; +/** @module InstanceNode **/ + +/** + * This node implements the vertex shader logic which is required + * when rendering 3D objects via instancing. The code makes sure + * vertex positions, normals and colors can be modified via instanced + * data. + * + * @augments Node + */ class InstanceNode extends Node { static get type() { @@ -20,25 +30,84 @@ class InstanceNode extends Node { } + /** + * Constructs a new instance node. + * + * @param {Number} count - The number of instances. + * @param {InstancedBufferAttribute} instanceMatrix - Instanced buffer attribute representing the instance transformations. + * @param {InstancedBufferAttribute} instanceColor - Instanced buffer attribute representing the instance colors. + */ constructor( count, instanceMatrix, instanceColor ) { super( 'void' ); + /** + * The number of instances. + * + * @type {Number} + */ this.count = count; + + /** + * Instanced buffer attribute representing the transformation of instances. + * + * @type {InstancedBufferAttribute} + */ this.instanceMatrix = instanceMatrix; + + /** + * Instanced buffer attribute representing the color of instances. + * + * @type {InstancedBufferAttribute} + */ this.instanceColor = instanceColor; + /** + * The node that represents the instance matrix data. + * + * @type {Node} + */ this.instanceMatrixNode = null; + /** + * The node that represents the instance color data. + * + * @type {Node} + */ this.instanceColorNode = null; + /** + * The update type is set to `frame` since an update + * of instanced buffer data must be checked per frame. + * + * @type {String} + * @default 'frame' + */ this.updateType = NodeUpdateType.FRAME; + /** + * A reference to a buffer that is used by `instanceMatrixNode`. + * + * @type {InstancedInterleavedBuffer} + */ this.buffer = null; + + /** + * A reference to a buffer that is used by `instanceColorNode`. + * + * @type {InstancedBufferAttribute} + */ this.bufferColor = null; } + /** + * Setups the internal buffers and nodes and assigns the transformed vertex data + * to predefined node variables for accumulation. That follows the same patterns + * like with morph and skinning nodes. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const { count, instanceMatrix, instanceColor } = this; @@ -118,6 +187,11 @@ class InstanceNode extends Node { } + /** + * Checks if the internal buffers required an update. + * + * @param {NodeFrame} frame - The current node frame. + */ update( /*frame*/ ) { if ( this.instanceMatrix.usage !== DynamicDrawUsage && this.buffer !== null && this.instanceMatrix.version !== this.buffer.version ) { @@ -138,4 +212,13 @@ class InstanceNode extends Node { export default InstanceNode; +/** + * TSL function for creating an instance node. + * + * @function + * @param {Number} count - The number of instances. + * @param {InstancedBufferAttribute} instanceMatrix - Instanced buffer attribute representing the instance transformations. + * @param {InstancedBufferAttribute} instanceColor - Instanced buffer attribute representing the instance colors. + * @returns {InstanceNode} + */ export const instance = /*@__PURE__*/ nodeProxy( InstanceNode ); diff --git a/src/nodes/accessors/InstancedMeshNode.js b/src/nodes/accessors/InstancedMeshNode.js index 162893d7c8002b..f9a76cd1749096 100644 --- a/src/nodes/accessors/InstancedMeshNode.js +++ b/src/nodes/accessors/InstancedMeshNode.js @@ -1,6 +1,14 @@ import InstanceNode from './InstanceNode.js'; import { nodeProxy } from '../tsl/TSLBase.js'; +/** @module InstancedMeshNode **/ + +/** + * This is a special version of `InstanceNode` which requires the usage of {@link InstancedMesh}. + * It allows an easier setup of the instance node. + * + * @augments module:InstanceNode~InstanceNode + */ class InstancedMeshNode extends InstanceNode { static get type() { @@ -9,13 +17,23 @@ class InstancedMeshNode extends InstanceNode { } - constructor( instanceMesh ) { + /** + * Constructs a new instanced mesh node. + * + * @param {InstancedMesh} instancedMesh - The instanced mesh. + */ + constructor( instancedMesh ) { - const { count, instanceMatrix, instanceColor } = instanceMesh; + const { count, instanceMatrix, instanceColor } = instancedMesh; super( count, instanceMatrix, instanceColor ); - this.instanceMesh = instanceMesh; + /** + * A reference to the instanced mesh. + * + * @type {InstancedMesh} + */ + this.instancedMesh = instancedMesh; } @@ -23,4 +41,11 @@ class InstancedMeshNode extends InstanceNode { export default InstancedMeshNode; +/** + * TSL function for creating an instanced mesh node. + * + * @function + * @param {InstancedMesh} instancedMesh - The instancedMesh. + * @returns {InstancedMeshNode} + */ export const instancedMesh = /*@__PURE__*/ nodeProxy( InstancedMeshNode ); diff --git a/src/nodes/accessors/InstancedPointsMaterialNode.js b/src/nodes/accessors/InstancedPointsMaterialNode.js deleted file mode 100644 index 4a34ac6380ed72..00000000000000 --- a/src/nodes/accessors/InstancedPointsMaterialNode.js +++ /dev/null @@ -1,24 +0,0 @@ -import MaterialNode from './MaterialNode.js'; -import { nodeImmutable } from '../tsl/TSLBase.js'; - -class InstancedPointsMaterialNode extends MaterialNode { - - static get type() { - - return 'InstancedPointsMaterialNode'; - - } - - setup( /*builder*/ ) { - - return this.getFloat( this.scope ); - - } - -} - -InstancedPointsMaterialNode.POINT_WIDTH = 'pointWidth'; - -export default InstancedPointsMaterialNode; - -export const materialPointWidth = /*@__PURE__*/ nodeImmutable( InstancedPointsMaterialNode, InstancedPointsMaterialNode.POINT_WIDTH ); diff --git a/src/nodes/accessors/Lights.js b/src/nodes/accessors/Lights.js index 0cf512d1d4ac2f..f0d0a0e10c8340 100644 --- a/src/nodes/accessors/Lights.js +++ b/src/nodes/accessors/Lights.js @@ -4,6 +4,8 @@ import { Vector3 } from '../../math/Vector3.js'; import { cameraViewMatrix } from './Camera.js'; import { positionWorld } from './Position.js'; +/** @module Lights **/ + let uniformsLib; function getLightData( light ) { @@ -18,6 +20,13 @@ function getLightData( light ) { } +/** + * TSL function for getting a shadow matrix uniform node for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The shadow matrix uniform node. + */ export function lightShadowMatrix( light ) { const data = getLightData( light ); @@ -36,6 +45,14 @@ export function lightShadowMatrix( light ) { } +/** + * TSL function for getting projected uv coordinates for the given light. + * Relevant when using maps with spot lights. + * + * @function + * @param {Light} light -The light source. + * @returns {Node} The projected uvs. + */ export function lightProjectionUV( light ) { const data = getLightData( light ); @@ -53,6 +70,13 @@ export function lightProjectionUV( light ) { } +/** + * TSL function for getting the position in world space for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The light's position in world space. + */ export function lightPosition( light ) { const data = getLightData( light ); @@ -61,6 +85,13 @@ export function lightPosition( light ) { } +/** + * TSL function for getting the light target position in world space for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The light target position in world space. + */ export function lightTargetPosition( light ) { const data = getLightData( light ); @@ -69,6 +100,13 @@ export function lightTargetPosition( light ) { } +/** + * TSL function for getting the position in view space for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {UniformNode} The light's position in view space. + */ export function lightViewPosition( light ) { const data = getLightData( light ); @@ -84,4 +122,11 @@ export function lightViewPosition( light ) { } +/** + * TSL function for getting the light target direction for the given light. + * + * @function + * @param {Light} light -The light source. + * @returns {Node} The light's target direction. + */ export const lightTargetDirection = ( light ) => cameraViewMatrix.transformDirection( lightPosition( light ).sub( lightTargetPosition( light ) ) ); diff --git a/src/nodes/accessors/MaterialNode.js b/src/nodes/accessors/MaterialNode.js index aa92847247d75b..73415c16b65f06 100644 --- a/src/nodes/accessors/MaterialNode.js +++ b/src/nodes/accessors/MaterialNode.js @@ -6,11 +6,20 @@ import { nodeImmutable, float, vec2, vec3, mat2 } from '../tsl/TSLBase.js'; import { uniform } from '../core/UniformNode.js'; import { normalMap } from '../display/NormalMapNode.js'; import { bumpMap } from '../display/BumpMapNode.js'; - import { Vector2 } from '../../math/Vector2.js'; +/** @module MaterialNode **/ + const _propertyCache = new Map(); +/** + * This class should simplify the node access to material properties. + * It internal uses reference nodes to make sure changes to material + * properties are automatically reflected to predefined TSL objects + * like e.g. `materialColor`. + * + * @augments Node + */ class MaterialNode extends Node { static get type() { @@ -19,14 +28,31 @@ class MaterialNode extends Node { } + /** + * Constructs a new material node. + * + * @param {String} scope - The scope defines what kind of material property is referred by the node. + */ constructor( scope ) { super(); + /** + * The scope defines what material property is referred by the node. + * + * @type {String} + */ this.scope = scope; } + /** + * Returns a cached reference node for the given property and type. + * + * @param {String} property - The name of the material property. + * @param {String} type - The uniform type of the property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getCache( property, type ) { let node = _propertyCache.get( property ); @@ -43,24 +69,49 @@ class MaterialNode extends Node { } + /** + * Returns a float-typed material reference node for the given property name. + * + * @param {String} property - The name of the material property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getFloat( property ) { return this.getCache( property, 'float' ); } + /** + * Returns a color-typed material reference node for the given property name. + * + * @param {String} property - The name of the material property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getColor( property ) { return this.getCache( property, 'color' ); } + /** + * Returns a texture-typed material reference node for the given property name. + * + * @param {String} property - The name of the material property. + * @return {MaterialReferenceNode} A material reference node representing the property access. + */ getTexture( property ) { return this.getCache( property === 'map' ? 'map' : property + 'Map', 'texture' ); } + /** + * The node setup is done depending on the selected scope. Multiple material properties + * might be grouped into a single node composition if they logically belong together. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The node representing the selected scope. + */ setup( builder ) { const material = builder.context.material; @@ -110,15 +161,15 @@ class MaterialNode extends Node { } else if ( scope === MaterialNode.SPECULAR_INTENSITY ) { - const specularIntensity = this.getFloat( scope ); + const specularIntensityNode = this.getFloat( scope ); - if ( material.specularMap ) { + if ( material.specularIntensityMap && material.specularIntensityMap.isTexture === true ) { - node = specularIntensity.mul( this.getTexture( scope ).a ); + node = specularIntensityNode.mul( this.getTexture( scope ).a ); } else { - node = specularIntensity; + node = specularIntensityNode; } @@ -333,7 +384,7 @@ class MaterialNode extends Node { node = this.getTexture( scope ).rgb.mul( this.getFloat( 'lightMapIntensity' ) ); - } else if ( scope === MaterialNode.AO_MAP ) { + } else if ( scope === MaterialNode.AO ) { node = this.getTexture( scope ).r.sub( 1.0 ).mul( this.getFloat( 'aoMapIntensity' ) ).add( 1.0 ); @@ -384,52 +435,295 @@ MaterialNode.LINE_DASH_SIZE = 'dashSize'; MaterialNode.LINE_GAP_SIZE = 'gapSize'; MaterialNode.LINE_WIDTH = 'linewidth'; MaterialNode.LINE_DASH_OFFSET = 'dashOffset'; -MaterialNode.POINT_WIDTH = 'pointWidth'; +MaterialNode.POINT_SIZE = 'size'; MaterialNode.DISPERSION = 'dispersion'; MaterialNode.LIGHT_MAP = 'light'; -MaterialNode.AO_MAP = 'ao'; +MaterialNode.AO = 'ao'; export default MaterialNode; +/** + * TSL object that represents alpha test of the current material. + * + * @type {Node} + */ export const materialAlphaTest = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ALPHA_TEST ); + +/** + * TSL object that represents the diffuse color of the current material. + * The value is composed via `color` * `map`. + * + * @type {Node} + */ export const materialColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.COLOR ); + +/** + * TSL object that represents the shininess of the current material. + * + * @type {Node} + */ export const materialShininess = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHININESS ); + +/** + * TSL object that represents the emissive color of the current material. + * The value is composed via `emissive` * `emissiveIntensity` * `emissiveMap`. + * + * @type {Node} + */ export const materialEmissive = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.EMISSIVE ); + +/** + * TSL object that represents the opacity of the current material. + * The value is composed via `opacity` * `alphaMap`. + * + * @type {Node} + */ export const materialOpacity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.OPACITY ); + +/** + * TSL object that represents the specular of the current material. + * + * @type {Node} + */ export const materialSpecular = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR ); +/** + * TSL object that represents the specular intensity of the current material. + * The value is composed via `specularIntensity` * `specularMap.a`. + * + * @type {Node} + */ export const materialSpecularIntensity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_INTENSITY ); + +/** + * TSL object that represents the specular color of the current material. + * The value is composed via `specularColor` * `specularMap.rgb`. + * + * @type {Node} + */ export const materialSpecularColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR ); +/** + * TSL object that represents the specular strength of the current material. + * The value is composed via `specularMap.r`. + * + * @type {Node} + */ export const materialSpecularStrength = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SPECULAR_STRENGTH ); + +/** + * TSL object that represents the reflectivity of the current material. + * + * @type {Node} + */ export const materialReflectivity = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.REFLECTIVITY ); + +/** + * TSL object that represents the roughness of the current material. + * The value is composed via `roughness` * `roughnessMap.g`. + * + * @type {Node} + */ export const materialRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS ); + +/** + * TSL object that represents the metalness of the current material. + * The value is composed via `metalness` * `metalnessMap.b`. + * + * @type {Node} + */ export const materialMetalness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.METALNESS ); -export const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.NORMAL ).context( { getUV: null } ); + +/** + * TSL object that represents the normal of the current material. + * The value will be either `normalMap` * `normalScale`, `bumpMap` * `bumpScale` or `normalView`. + * + * @type {Node} + */ +export const materialNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.NORMAL ); + +/** + * TSL object that represents the clearcoat of the current material. + * The value is composed via `clearcoat` * `clearcoatMap.r` + * + * @type {Node} + */ export const materialClearcoat = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT ); + +/** + * TSL object that represents the clearcoat roughness of the current material. + * The value is composed via `clearcoatRoughness` * `clearcoatRoughnessMap.r`. + * + * @type {Node} + */ export const materialClearcoatRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_ROUGHNESS ); -export const materialClearcoatNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL ).context( { getUV: null } ); + +/** + * TSL object that represents the clearcoat normal of the current material. + * The value will be either `clearcoatNormalMap` or `normalView`. + * + * @type {Node} + */ +export const materialClearcoatNormal = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL ); + +/** + * TSL object that represents the rotation of the current sprite material. + * + * @type {Node} + */ export const materialRotation = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ROTATION ); + +/** + * TSL object that represents the sheen color of the current material. + * The value is composed via `sheen` * `sheenColor` * `sheenColorMap`. + * + * @type {Node} + */ export const materialSheen = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN ); + +/** + * TSL object that represents the sheen roughness of the current material. + * The value is composed via `sheenRoughness` * `sheenRoughnessMap.a`. + * + * @type {Node} + */ export const materialSheenRoughness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.SHEEN_ROUGHNESS ); + +/** + * TSL object that represents the anisotropy of the current material. + * + * @type {Node} + */ export const materialAnisotropy = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ANISOTROPY ); + +/** + * TSL object that represents the iridescence of the current material. + * + * @type {Node} + */ export const materialIridescence = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE ); + +/** + * TSL object that represents the iridescence IOR of the current material. + * + * @type {Node} + */ export const materialIridescenceIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_IOR ); + +/** + * TSL object that represents the iridescence thickness of the current material. + * + * @type {Node} + */ export const materialIridescenceThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_THICKNESS ); + +/** + * TSL object that represents the transmission of the current material. + * The value is composed via `transmission` * `transmissionMap.r`. + * + * @type {Node} + */ export const materialTransmission = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.TRANSMISSION ); + +/** + * TSL object that represents the thickness of the current material. + * The value is composed via `thickness` * `thicknessMap.g`. + * + * @type {Node} + */ export const materialThickness = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.THICKNESS ); + +/** + * TSL object that represents the IOR of the current material. + * + * @type {Node} + */ export const materialIOR = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.IOR ); + +/** + * TSL object that represents the attenuation distance of the current material. + * + * @type {Node} + */ export const materialAttenuationDistance = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_DISTANCE ); + +/** + * TSL object that represents the attenuation color of the current material. + * + * @type {Node} + */ export const materialAttenuationColor = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_COLOR ); + +/** + * TSL object that represents the scale of the current dashed line material. + * + * @type {Node} + */ export const materialLineScale = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_SCALE ); + +/** + * TSL object that represents the dash size of the current dashed line material. + * + * @type {Node} + */ export const materialLineDashSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_SIZE ); + +/** + * TSL object that represents the gap size of the current dashed line material. + * + * @type {Node} + */ export const materialLineGapSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_GAP_SIZE ); + +/** + * TSL object that represents the line width of the current line material. + * + * @type {Node} + */ export const materialLineWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_WIDTH ); + +/** + * TSL object that represents the dash offset of the current line material. + * + * @type {Node} + */ export const materialLineDashOffset = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_OFFSET ); -export const materialPointWidth = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.POINT_WIDTH ); + +/** + * TSL object that represents the point size of the current points material. + * + * @type {Node} + */ +export const materialPointSize = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.POINT_SIZE ); + +/** + * TSL object that represents the dispersion of the current material. + * + * @type {Node} + */ export const materialDispersion = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.DISPERSION ); + +/** + * TSL object that represents the light map of the current material. + * The value is composed via `lightMapIntensity` * `lightMap.rgb`. + * + * @type {Node} + */ export const materialLightMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.LIGHT_MAP ); -export const materialAOMap = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.AO_MAP ); + +/** + * TSL object that represents the ambient occlusion map of the current material. + * The value is composed via `aoMap.r` - 1 * `aoMapIntensity` + 1. + * + * @type {Node} + */ +export const materialAO = /*@__PURE__*/ nodeImmutable( MaterialNode, MaterialNode.AO ); + +/** + * TSL object that represents the anisotropy vector of the current material. + * + * @type {Node} + */ export const materialAnisotropyVector = /*@__PURE__*/ uniform( new Vector2() ).onReference( function ( frame ) { return frame.material; diff --git a/src/nodes/accessors/MaterialProperties.js b/src/nodes/accessors/MaterialProperties.js index 117214b7422dff..15951acaf4deb9 100644 --- a/src/nodes/accessors/MaterialProperties.js +++ b/src/nodes/accessors/MaterialProperties.js @@ -1,3 +1,10 @@ import { uniform } from '../core/UniformNode.js'; +/** @module MaterialProperties **/ + +/** + * TSL object that represents the refraction ratio of the material used for rendering the current object. + * + * @type {UniformNode} + */ export const materialRefractionRatio = /*@__PURE__*/ uniform( 0 ).onReference( ( { material } ) => material ).onRenderUpdate( ( { material } ) => material.refractionRatio ); diff --git a/src/nodes/accessors/MaterialReferenceNode.js b/src/nodes/accessors/MaterialReferenceNode.js index c2c0585c692b9e..11fc4218a67700 100644 --- a/src/nodes/accessors/MaterialReferenceNode.js +++ b/src/nodes/accessors/MaterialReferenceNode.js @@ -1,8 +1,19 @@ import ReferenceNode from './ReferenceNode.js'; -//import { renderGroup } from '../core/UniformGroupNode.js'; -//import { NodeUpdateType } from '../core/constants.js'; import { nodeObject } from '../tsl/TSLBase.js'; +/** @module MaterialReferenceNode **/ + +/** + * This node is a special type of reference node which is intended + * for linking material properties with node values. + * ```js + * const opacityNode = materialReference( 'opacity', 'float', material ); + * ``` + * When changing `material.opacity`, the node value of `opacityNode` will + * automatically be updated. + * + * @augments module:ReferenceNode~ReferenceNode + */ class MaterialReferenceNode extends ReferenceNode { static get type() { @@ -11,26 +22,45 @@ class MaterialReferenceNode extends ReferenceNode { } + /** + * Constructs a new material reference node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} inputType - The uniform type that should be used to represent the property value. + * @param {Material?} [material=null] - The material the property belongs to. When no material is set, + * the node refers to the material of the current rendered object. + */ constructor( property, inputType, material = null ) { super( property, inputType, material ); + /** + * The material the property belongs to. When no material is set, + * the node refers to the material of the current rendered object. + * + * @type {Material?} + * @default null + */ this.material = material; - //this.updateType = NodeUpdateType.RENDER; - + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMaterialReferenceNode = true; } - /*setNodeType( node ) { - - super.setNodeType( node ); - - this.node.groupNode = renderGroup; - - }*/ - + /** + * Updates the reference based on the given state. The state is only evaluated + * {@link module:MaterialReferenceNode~MaterialReferenceNode#material} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.material !== null ? this.material : state.material; @@ -43,4 +73,14 @@ class MaterialReferenceNode extends ReferenceNode { export default MaterialReferenceNode; -export const materialReference = ( name, type, material ) => nodeObject( new MaterialReferenceNode( name, type, material ) ); +/** + * TSL function for creating a material reference node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Material?} [material=null] - The material the property belongs to. + * When no material is set, the node refers to the material of the current rendered object. + * @returns {MaterialReferenceNode} + */ +export const materialReference = ( name, type, material = null ) => nodeObject( new MaterialReferenceNode( name, type, material ) ); diff --git a/src/nodes/accessors/ModelNode.js b/src/nodes/accessors/ModelNode.js index 0c78375beabf72..49f1a10d073bf5 100644 --- a/src/nodes/accessors/ModelNode.js +++ b/src/nodes/accessors/ModelNode.js @@ -6,6 +6,16 @@ import { Matrix4 } from '../../math/Matrix4.js'; import { cameraViewMatrix } from './Camera.js'; import { Matrix3 } from '../../math/Matrix3.js'; +/** @module ModelNode **/ + +/** + * This type of node is a specialized version of `Object3DNode` + * with larger set of model related metrics. Unlike `Object3DNode`, + * `ModelNode` extracts the reference to the 3D object from the + * current node frame state. + * + * @augments module:Object3DNode~Object3DNode + */ class ModelNode extends Object3DNode { static get type() { @@ -14,12 +24,23 @@ class ModelNode extends Object3DNode { } + /** + * Constructs a new object model node. + * + * @param {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} scope - The node represents a different type of transformation depending on the scope. + */ constructor( scope ) { super( scope ); } + /** + * Extracts the model reference from the frame state and then + * updates the uniform value depending on the scope. + * + * @param {NodeFrame} frame - The current node frame. + */ update( frame ) { this.object3d = frame.object; @@ -32,16 +53,84 @@ class ModelNode extends Object3DNode { export default ModelNode; +/** + * TSL object that represents the object's direction in world space. + * + * @type {ModelNode} + */ export const modelDirection = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.DIRECTION ); + +/** + * TSL object that represents the object's world matrix. + * + * @type {ModelNode} + */ export const modelWorldMatrix = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX ); + +/** + * TSL object that represents the object's position in world space. + * + * @type {ModelNode} + */ export const modelPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.POSITION ); + +/** + * TSL object that represents the object's scale in world space. + * + * @type {ModelNode} + */ export const modelScale = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.SCALE ); + +/** + * TSL object that represents the object's position in view/camera space. + * + * @type {ModelNode} + */ export const modelViewPosition = /*@__PURE__*/ nodeImmutable( ModelNode, ModelNode.VIEW_POSITION ); + +/** + * TSL object that represents the object's normal matrix. + * + * @type {UniformNode} + */ export const modelNormalMatrix = /*@__PURE__*/ uniform( new Matrix3() ).onObjectUpdate( ( { object }, self ) => self.value.getNormalMatrix( object.matrixWorld ) ); + +/** + * TSL object that represents the object's inverse world matrix. + * + * @type {UniformNode} + */ export const modelWorldMatrixInverse = /*@__PURE__*/ uniform( new Matrix4() ).onObjectUpdate( ( { object }, self ) => self.value.copy( object.matrixWorld ).invert() ); -export const modelViewMatrix = /*@__PURE__*/ cameraViewMatrix.mul( modelWorldMatrix ).toVar( 'modelViewMatrix' ); -export const highPrecisionModelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { +/** + * TSL object that represents the object's model view matrix. + * + * @type {Node} + */ +export const modelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { + + return builder.renderer.nodes.modelViewMatrix || mediumpModelViewMatrix; + +} ).once() )().toVar( 'modelViewMatrix' ); + +// GPU Precision + +/** + * TSL object that represents the object's model view in `mediump` precision. + * + * @type {Node} + */ +export const mediumpModelViewMatrix = /*@__PURE__*/ cameraViewMatrix.mul( modelWorldMatrix ); + +// CPU Precision + +/** + * TSL object that represents the object's model view in `highp` precision + * which is achieved by computing the matrix in JS and not in the shader. + * + * @type {Node} + */ +export const highpModelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { builder.context.isHighPrecisionModelViewMatrix = true; @@ -51,9 +140,15 @@ export const highPrecisionModelViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { } ); -} ).once() )().toVar( 'highPrecisionModelViewMatrix' ); +} ).once() )().toVar( 'highpModelViewMatrix' ); -export const highPrecisionModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { +/** + * TSL object that represents the object's model normal view in `highp` precision + * which is achieved by computing the matrix in JS and not in the shader. + * + * @type {Node} + */ +export const highpModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder ) => { const isHighPrecisionModelViewMatrix = builder.context.isHighPrecisionModelViewMatrix; @@ -69,4 +164,4 @@ export const highPrecisionModelNormalViewMatrix = /*@__PURE__*/ ( Fn( ( builder } ); -} ).once() )().toVar( 'highPrecisionModelNormalMatrix' ); +} ).once() )().toVar( 'highpModelNormalViewMatrix' ); diff --git a/src/nodes/accessors/ModelViewProjectionNode.js b/src/nodes/accessors/ModelViewProjectionNode.js index 85cb1250132164..07e5b78ba82c08 100644 --- a/src/nodes/accessors/ModelViewProjectionNode.js +++ b/src/nodes/accessors/ModelViewProjectionNode.js @@ -1,42 +1,14 @@ -import TempNode from '../core/TempNode.js'; -import { cameraProjectionMatrix } from './Camera.js'; -import { positionLocal } from './Position.js'; -import { nodeProxy, varying } from '../tsl/TSLBase.js'; -import { modelViewMatrix } from './ModelNode.js'; +import { Fn } from '../tsl/TSLCore.js'; -class ModelViewProjectionNode extends TempNode { +/** @module ModelViewProjectionNode **/ - static get type() { +/** + * TSL object that represents the position in clip space after the model-view-projection transform of the current rendered object. + * + * @type {VaryingNode} + */ +export const modelViewProjection = /*@__PURE__*/ ( Fn( ( builder ) => { - return 'ModelViewProjectionNode'; + return builder.context.setupModelViewProjection(); - } - - 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 ); - - } - -} - -export default ModelViewProjectionNode; - -export const modelViewProjection = /*@__PURE__*/ nodeProxy( ModelViewProjectionNode ); +}, 'vec4' ).once() )().varying( 'v_modelViewProjection' ); diff --git a/src/nodes/accessors/MorphNode.js b/src/nodes/accessors/MorphNode.js index 5df34188d46b22..45a2c13cb1d9de 100644 --- a/src/nodes/accessors/MorphNode.js +++ b/src/nodes/accessors/MorphNode.js @@ -14,6 +14,8 @@ import { Vector2 } from '../../math/Vector2.js'; import { Vector4 } from '../../math/Vector4.js'; import { FloatType } from '../../constants.js'; +/** @module MorphNode **/ + const _morphTextures = /*@__PURE__*/ new WeakMap(); const _morphVec4 = /*@__PURE__*/ new Vector4(); @@ -156,7 +158,12 @@ function getEntry( geometry ) { } - +/** + * This node implements the vertex transformation shader logic which is required + * for morph target animation. + * + * @augments Node + */ class MorphNode extends Node { static get type() { @@ -165,17 +172,43 @@ class MorphNode extends Node { } + /** + * Constructs a new morph node. + * + * @param {Mesh} mesh - The mesh holding the morph targets. + */ constructor( mesh ) { super( 'void' ); + /** + * The mesh holding the morph targets. + * + * @type {Mesh} + */ this.mesh = mesh; + + /** + * A uniform node which represents the morph base influence value. + * + * @type {UniformNode} + */ this.morphBaseInfluence = uniform( 1 ); + /** + * The update type overwritten since morph nodes are updated per object. + * + * @type {String} + */ this.updateType = NodeUpdateType.OBJECT; } + /** + * Setups the morph node by assigning the transformed vertex data to predefined node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const { geometry } = builder; @@ -239,7 +272,12 @@ class MorphNode extends Node { } - update() { + /** + * Updates the state of the morphed mesh by updating the base influence. + * + * @param {NodeFrame} frame - The current node frame. + */ + update( /*frame*/ ) { const morphBaseInfluence = this.morphBaseInfluence; @@ -259,4 +297,11 @@ class MorphNode extends Node { export default MorphNode; +/** + * TSL function for creating a morph node. + * + * @function + * @param {Mesh} mesh - The mesh holding the morph targets. + * @returns {MorphNode} + */ export const morphReference = /*@__PURE__*/ nodeProxy( MorphNode ); diff --git a/src/nodes/accessors/Normal.js b/src/nodes/accessors/Normal.js index 105cbc8c00d9f5..e27723bf48e56b 100644 --- a/src/nodes/accessors/Normal.js +++ b/src/nodes/accessors/Normal.js @@ -5,8 +5,20 @@ import { mat3, vec3, Fn, varying } from '../tsl/TSLBase.js'; import { positionView } from './Position.js'; import { faceDirection } from '../display/FrontFacingNode.js'; +/** @module Normal **/ + +/** + * TSL object that represents the normal attribute of the current rendered object. + * + * @type {Node} + */ export const normalGeometry = /*@__PURE__*/ attribute( 'normal', 'vec3' ); +/** + * TSL object that represents the vertex normal in local space of the current rendered object. + * + * @type {Node} + */ export const normalLocal = /*@__PURE__*/ ( Fn( ( builder ) => { if ( builder.geometry.hasAttribute( 'normal' ) === false ) { @@ -21,8 +33,18 @@ export const normalLocal = /*@__PURE__*/ ( Fn( ( builder ) => { }, 'vec3' ).once() )().toVar( 'normalLocal' ); +/** + * TSL object that represents the flat vertex normal in view space of the current rendered object. + * + * @type {Node} + */ export const normalFlat = /*@__PURE__*/ positionView.dFdx().cross( positionView.dFdy() ).normalize().toVar( 'normalFlat' ); +/** + * TSL object that represents the vertex normal in view space of the current rendered object. + * + * @type {Node} + */ export const normalView = /*@__PURE__*/ ( Fn( ( builder ) => { let node; @@ -41,23 +63,54 @@ export const normalView = /*@__PURE__*/ ( Fn( ( builder ) => { }, 'vec3' ).once() )().toVar( 'normalView' ); +/** + * TSL object that represents the vertex normal in world space of the current rendered object. + * + * @type {Node} + */ export const normalWorld = /*@__PURE__*/ varying( normalView.transformDirection( cameraViewMatrix ), 'v_normalWorld' ).normalize().toVar( 'normalWorld' ); +/** + * TSL object that represents the transformed vertex normal in view space of the current rendered object. + * + * @type {Node} + */ export const transformedNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { - return builder.context.setupNormal(); + // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode) -}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedNormalView' ); + return builder.context.setupNormal().context( { getUV: null } ); +}, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedNormalView' ); +/** + * TSL object that represents the transformed vertex normal in world space of the current rendered object. + * + * @type {Node} + */ export const transformedNormalWorld = /*@__PURE__*/ transformedNormalView.transformDirection( cameraViewMatrix ).toVar( 'transformedNormalWorld' ); +/** + * TSL object that represents the transformed clearcoat vertex normal in view space of the current rendered object. + * + * @type {Node} + */ export const transformedClearcoatNormalView = /*@__PURE__*/ ( Fn( ( builder ) => { - return builder.context.setupClearcoatNormal(); + // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode) + + return builder.context.setupClearcoatNormal().context( { getUV: null } ); }, 'vec3' ).once() )().mul( faceDirection ).toVar( 'transformedClearcoatNormalView' ); +/** + * Transforms the normal with the given matrix. + * + * @function + * @param {Node} normal - The normal. + * @param {Node} [matrix=modelWorldMatrix] - The matrix. + * @return {Node} The transformed normal. + */ export const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorldMatrix ] ) => { const m = mat3( matrix ); @@ -68,6 +121,14 @@ export const transformNormal = /*@__PURE__*/ Fn( ( [ normal, matrix = modelWorld } ); +/** + * Transforms the given normal from local to view space. + * + * @function + * @param {Node} normal - The normal. + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The transformed normal. + */ export const transformNormalToView = /*@__PURE__*/ Fn( ( [ normal ], builder ) => { const modelNormalViewMatrix = builder.renderer.nodes.modelNormalViewMatrix; diff --git a/src/nodes/accessors/Object3DNode.js b/src/nodes/accessors/Object3DNode.js index 97e9f28cdb9fb5..3becdb8fea2d33 100644 --- a/src/nodes/accessors/Object3DNode.js +++ b/src/nodes/accessors/Object3DNode.js @@ -2,9 +2,23 @@ import Node from '../core/Node.js'; import { NodeUpdateType } from '../core/constants.js'; import UniformNode from '../core/UniformNode.js'; import { nodeProxy } from '../tsl/TSLBase.js'; - import { Vector3 } from '../../math/Vector3.js'; +/** @module Object3DNode **/ + +/** + * This node can be used to access transformation related metrics of 3D objects. + * Depending on the selected scope, a different metric is represented as a uniform + * in the shader. The following scopes are supported: + * + * - `POSITION`: The object's position in world space. + * - `VIEW_POSITION`: The object's position in view/camera space. + * - `DIRECTION`: The object's direction in world space. + * - `SCALE`: The object's scale in world space. + * - `WORLD_MATRIX`: The object's matrix in world space. + * + * @augments Node + */ class Object3DNode extends Node { static get type() { @@ -13,19 +27,54 @@ class Object3DNode extends Node { } + /** + * Constructs a new object 3D node. + * + * @param {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} scope - The node represents a different type of transformation depending on the scope. + * @param {Object3D?} [object3d=null] - The 3D object. + */ constructor( scope, object3d = null ) { super(); + /** + * The node reports a different type of transformation depending on the scope. + * + * @type {('position'|'viewPosition'|'direction'|'scale'|'worldMatrix')} + */ this.scope = scope; + + /** + * The 3D object. + * + * @type {Object3D?} + * @default null + */ this.object3d = object3d; + /** + * Overwritten since this type of node is updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; + /** + * Holds the value of the node as a uniform. + * + * @private + * @type {UniformNode} + */ this._uniformNode = new UniformNode( null ); } + /** + * Overwritten since the node type is inferred from the scope. + * + * @return {String} The node type. + */ getNodeType() { const scope = this.scope; @@ -42,6 +91,11 @@ class Object3DNode extends Node { } + /** + * Updates the uniform value depending on the scope. + * + * @param {NodeFrame} frame - The current node frame. + */ update( frame ) { const object = this.object3d; @@ -83,6 +137,13 @@ class Object3DNode extends Node { } + /** + * Generates the code snippet of the uniform node. The node type of the uniform + * node also depends on the selected scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( builder ) { const scope = this.scope; @@ -127,8 +188,47 @@ Object3DNode.DIRECTION = 'direction'; export default Object3DNode; +/** + * TSL function for creating an object 3D node that represents the object's direction in world space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ export const objectDirection = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.DIRECTION ); + +/** + * TSL function for creating an object 3D node that represents the object's world matrix. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ export const objectWorldMatrix = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX ); + +/** + * TSL function for creating an object 3D node that represents the object's position in world space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ export const objectPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.POSITION ); + +/** + * TSL function for creating an object 3D node that represents the object's scale in world space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ export const objectScale = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.SCALE ); + +/** + * TSL function for creating an object 3D node that represents the object's position in view/camera space. + * + * @function + * @param {Object3D?} [object3d=null] - The 3D object. + * @returns {Object3DNode} + */ export const objectViewPosition = /*@__PURE__*/ nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION ); diff --git a/src/nodes/accessors/Position.js b/src/nodes/accessors/Position.js index 7c898f0ee75f5b..1f9a5220494fbb 100644 --- a/src/nodes/accessors/Position.js +++ b/src/nodes/accessors/Position.js @@ -1,5 +1,6 @@ import { attribute } from '../core/AttributeNode.js'; -import { modelWorldMatrix, modelViewMatrix } from './ModelNode.js'; +import { Fn } from '../tsl/TSLCore.js'; +import { modelWorldMatrix } from './ModelNode.js'; /** @module Position **/ @@ -19,7 +20,7 @@ export const positionLocal = /*@__PURE__*/ positionGeometry.varying( 'positionLo /** * TSL object that represents the previous vertex position in local space of the current rendered object. - * Used in context of {@link VelocityNode} for rendering motion vectors. + * Used in context of {@link module:VelocityNode~VelocityNode} for rendering motion vectors. * * @type {AttributeNode} */ @@ -44,7 +45,11 @@ export const positionWorldDirection = /*@__PURE__*/ positionLocal.transformDirec * * @type {VaryingNode} */ -export const positionView = /*@__PURE__*/ modelViewMatrix.mul( positionLocal ).xyz.varying( 'v_positionView' ).context( { needsPositionReassign: true } ); +export const positionView = /*@__PURE__*/ ( Fn( ( builder ) => { + + return builder.context.setupPositionView(); + +}, 'vec3' ).once() )().varying( 'v_positionView' ).context( { needsPositionReassign: true } ); /** * TSL object that represents the position view direction of the current rendered object. diff --git a/src/nodes/accessors/ReferenceBaseNode.js b/src/nodes/accessors/ReferenceBaseNode.js index fe273476cce94d..43552c5457f40f 100644 --- a/src/nodes/accessors/ReferenceBaseNode.js +++ b/src/nodes/accessors/ReferenceBaseNode.js @@ -4,6 +4,17 @@ import { uniform } from '../core/UniformNode.js'; import { nodeObject } from '../tsl/TSLCore.js'; import ArrayElementNode from '../utils/ArrayElementNode.js'; +// TODO: Avoid duplicated code and ues only ReferenceBaseNode or ReferenceNode + +/** @module ReferenceBaseNode **/ + +/** + * This class is only relevant if the referenced property is array-like. + * In this case, `ReferenceElementNode` allows to refer to a specific + * element inside the data structure via an index. + * + * @augments ArrayElementNode + */ class ReferenceElementNode extends ArrayElementNode { static get type() { @@ -12,16 +23,42 @@ class ReferenceElementNode extends ArrayElementNode { } + /** + * Constructs a new reference element node. + * + * @param {ReferenceBaseNode?} referenceNode - The reference node. + * @param {Node} indexNode - The index node that defines the element access. + */ constructor( referenceNode, indexNode ) { super( referenceNode, indexNode ); + /** + * Similar to {@link module:ReferenceBaseNode~ReferenceBaseNode#reference}, an additional + * property references to the current node. + * + * @type {ReferenceBaseNode?} + * @default null + */ this.referenceNode = referenceNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isReferenceElementNode = true; } + /** + * This method is overwritten since the node type is inferred from + * the uniform type of the reference node. + * + * @return {String} The node type. + */ getNodeType() { return this.referenceNode.uniformType; @@ -40,6 +77,14 @@ class ReferenceElementNode extends ArrayElementNode { } +/** + * Base class for nodes which establishes a reference to a property of another object. + * In this way, the value of the node is automatically linked to the value of + * referenced object. Reference nodes internally represent the linked value + * as a uniform. + * + * @augments Node + */ class ReferenceBaseNode extends Node { static get type() { @@ -48,24 +93,97 @@ class ReferenceBaseNode extends Node { } + /** + * Constructs a new reference base node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} uniformType - The uniform type that should be used to represent the property value. + * @param {Object?} [object=null] - The object the property belongs to. + * @param {Number?} [count=null] - When the linked property is an array-like, this parameter defines its length. + */ constructor( property, uniformType, object = null, count = null ) { super(); + /** + * The name of the property the node refers to. + * + * @type {String} + */ this.property = property; + + /** + * The uniform type that should be used to represent the property value. + * + * @type {String} + */ this.uniformType = uniformType; + + /** + * The object the property belongs to. + * + * @type {Object?} + * @default null + */ this.object = object; + + /** + * When the linked property is an array, this parameter defines its length. + * + * @type {Number?} + * @default null + */ this.count = count; + /** + * The property name might have dots so nested properties can be referred. + * The hierarchy of the names is stored inside this array. + * + * @type {Array} + */ this.properties = property.split( '.' ); + + /** + * Points to the current referred object. This property exists next to {@link module:ReferenceNode~ReferenceNode#object} + * since the final reference might be updated from calling code. + * + * @type {Object?} + * @default null + */ this.reference = object; + + /** + * The uniform node that holds the value of the reference node. + * + * @type {UniformNode} + * @default null + */ this.node = null; + + /** + * The uniform group of the internal uniform. + * + * @type {UniformGroupNode} + * @default null + */ this.group = null; + /** + * Overwritten since reference nodes are updated per object. + * + * @type {String} + * @default 'object' + */ this.updateType = NodeUpdateType.OBJECT; } + /** + * Sets the uniform group for this reference node. + * + * @param {UniformGroupNode} group - The uniform group to set. + * @return {ReferenceBaseNode} A reference to this node. + */ setGroup( group ) { this.group = group; @@ -74,12 +192,25 @@ class ReferenceBaseNode extends Node { } + /** + * When the referred property is array-like, this method can be used + * to access elements via an index node. + * + * @param {IndexNode} indexNode - indexNode. + * @return {ReferenceElementNode} A reference to an element. + */ element( indexNode ) { return nodeObject( new ReferenceElementNode( this, nodeObject( indexNode ) ) ); } + /** + * Sets the node type which automatically defines the internal + * uniform type. + * + * @param {String} uniformType - The type to set. + */ setNodeType( uniformType ) { const node = uniform( null, uniformType ).getSelf(); @@ -94,6 +225,13 @@ class ReferenceBaseNode extends Node { } + /** + * This method is overwritten since the node type is inferred from + * the type of the reference node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( this.node === null ) { @@ -107,6 +245,12 @@ class ReferenceBaseNode extends Node { } + /** + * Returns the property value from the given referred object. + * + * @param {Object} [object=this.reference] - The object to retrieve the property value from. + * @return {Any} The value. + */ getValueFromReference( object = this.reference ) { const { properties } = this; @@ -123,6 +267,13 @@ class ReferenceBaseNode extends Node { } + /** + * Allows to update the reference based on the given state. The state is only + * evaluated {@link module:ReferenceBaseNode~ReferenceBaseNode#object} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.object !== null ? this.object : state.object; @@ -131,6 +282,11 @@ class ReferenceBaseNode extends Node { } + /** + * The output of the reference node is the internal uniform node. + * + * @return {UniformNode} The output node. + */ setup() { this.updateValue(); @@ -139,12 +295,21 @@ class ReferenceBaseNode extends Node { } + /** + * Overwritten to to update the internal uniform value. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( /*frame*/ ) { this.updateValue(); } + /** + * Retrieves the value from the referred object property and uses it + * to updated the internal uniform. + */ updateValue() { if ( this.node === null ) this.setNodeType( this.uniformType ); @@ -167,5 +332,26 @@ class ReferenceBaseNode extends Node { export default ReferenceBaseNode; +/** + * TSL function for creating a reference base node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Object} object - The object the property belongs to. + * @returns {ReferenceBaseNode} + */ export const reference = ( name, type, object ) => nodeObject( new ReferenceBaseNode( name, type, object ) ); + +/** + * TSL function for creating a reference base node. Use this function if you want need a reference + * to an array-like property that should be represented as a uniform buffer. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Number} count - The number of value inside the array-like object. + * @param {Object} object - An array-like object the property belongs to. + * @returns {ReferenceBaseNode} + */ export const referenceBuffer = ( name, type, count, object ) => nodeObject( new ReferenceBaseNode( name, type, object, count ) ); diff --git a/src/nodes/accessors/ReferenceNode.js b/src/nodes/accessors/ReferenceNode.js index e511c5d381e9f4..7ce864fd3bdc34 100644 --- a/src/nodes/accessors/ReferenceNode.js +++ b/src/nodes/accessors/ReferenceNode.js @@ -8,6 +8,8 @@ import { nodeObject } from '../tsl/TSLBase.js'; import { uniformArray } from './UniformArrayNode.js'; import ArrayElementNode from '../utils/ArrayElementNode.js'; +// TODO: Avoid duplicated code and ues only ReferenceBaseNode or ReferenceNode + /** @module ReferenceNode **/ /** @@ -28,7 +30,7 @@ class ReferenceElementNode extends ArrayElementNode { /** * Constructs a new reference element node. * - * @param {Node} referenceNode - The reference node. + * @param {ReferenceNode?} referenceNode - The reference node. * @param {Node} indexNode - The index node that defines the element access. */ constructor( referenceNode, indexNode ) { @@ -36,10 +38,10 @@ class ReferenceElementNode extends ArrayElementNode { super( referenceNode, indexNode ); /** - * Similar to {@link ReferenceNode#reference}, an additional + * Similar to {@link module:ReferenceNode~ReferenceNode#reference}, an additional * property references to the current node. * - * @type {Node} + * @type {ReferenceNode?} * @default null */ this.referenceNode = referenceNode; @@ -59,7 +61,6 @@ class ReferenceElementNode extends ArrayElementNode { * This method is overwritten since the node type is inferred from * the uniform type of the reference node. * - * @param {NodeBuilder} builder - The current node builder. * @return {String} The node type. */ getNodeType() { @@ -83,7 +84,7 @@ class ReferenceElementNode extends ArrayElementNode { /** * This type of node establishes a reference to a property of another object. * In this way, the value of the node is automatically linked to the value of - * referenced object. Reference nodes internally represents the linked value + * referenced object. Reference nodes internally represent the linked value * as a uniform. * * @augments Node @@ -147,7 +148,7 @@ class ReferenceNode extends Node { this.properties = property.split( '.' ); /** - * Points to the current referred object. This property exists next to {@link ReferenceNode#object} + * Points to the current referred object. This property exists next to {@link module:ReferenceNode~ReferenceNode#object} * since the final reference might be updated from calling code. * * @type {Object?} @@ -172,7 +173,7 @@ class ReferenceNode extends Node { this.group = null; /** - * An optinal label of the internal uniform node. + * An optional label of the internal uniform node. * * @type {String?} * @default null @@ -180,7 +181,7 @@ class ReferenceNode extends Node { this.name = null; /** - * Overwritten since velocity nodes are updated per object. + * Overwritten since reference nodes are updated per object. * * @type {String} * @default 'object' @@ -318,7 +319,7 @@ class ReferenceNode extends Node { /** * Allows to update the reference based on the given state. The state is only - * evaluated {@link ReferenceNode#object} is not set. + * evaluated {@link module:ReferenceNode~ReferenceNode#object} is not set. * * @param {(NodeFrame|NodeBuilder)} state - The current state. * @return {Object} The updated reference. @@ -383,7 +384,7 @@ class ReferenceNode extends Node { export default ReferenceNode; /** - * TSL function for creating a reference node with the given paramters. + * TSL function for creating a reference node. * * @function * @param {String} name - The name of the property the node refers to. @@ -394,7 +395,8 @@ export default ReferenceNode; export const reference = ( name, type, object ) => nodeObject( new ReferenceNode( name, type, object ) ); /** - * TSL function for creating a reference node with the given paramters. + * TSL function for creating a reference node. Use this function if you want need a reference + * to an array-like property that should be represented as a uniform buffer. * * @function * @param {String} name - The name of the property the node refers to. diff --git a/src/nodes/accessors/ReflectVector.js b/src/nodes/accessors/ReflectVector.js index eafd166528c771..252a0fe73225a4 100644 --- a/src/nodes/accessors/ReflectVector.js +++ b/src/nodes/accessors/ReflectVector.js @@ -3,8 +3,32 @@ import { transformedNormalView } from './Normal.js'; import { positionViewDirection } from './Position.js'; import { materialRefractionRatio } from './MaterialProperties.js'; +/** @module ReflectVector **/ + +/** + * The reflect vector in view space. + * + * @type {Node} + */ export const reflectView = /*@__PURE__*/ positionViewDirection.negate().reflect( transformedNormalView ); + +/** + * The refract vector in view space. + * + * @type {Node} + */ export const refractView = /*@__PURE__*/ positionViewDirection.negate().refract( transformedNormalView, materialRefractionRatio ); +/** + * Used for sampling cube maps when using cube reflection mapping. + * + * @type {Node} + */ export const reflectVector = /*@__PURE__*/ reflectView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); + +/** + * Used for sampling cube maps when using cube refraction mapping. + * + * @type {Node} + */ export const refractVector = /*@__PURE__*/ refractView.transformDirection( cameraViewMatrix ).toVar( 'reflectVector' ); diff --git a/src/nodes/accessors/RendererReferenceNode.js b/src/nodes/accessors/RendererReferenceNode.js index 4ca517efc4b415..c62bfd86dbcd67 100644 --- a/src/nodes/accessors/RendererReferenceNode.js +++ b/src/nodes/accessors/RendererReferenceNode.js @@ -2,6 +2,19 @@ import ReferenceBaseNode from './ReferenceBaseNode.js'; import { nodeObject } from '../tsl/TSLCore.js'; import { renderGroup } from '../core/UniformGroupNode.js'; +/** @module RendererReferenceNode **/ + +/** + * This node is a special type of reference node which is intended + * for linking renderer properties with node values. + * ```js + * const exposureNode = rendererReference( 'toneMappingExposure', 'float', renderer ); + * ``` + * When changing `renderer.toneMappingExposure`, the node value of `exposureNode` will + * automatically be updated. + * + * @augments ReferenceBaseNode + */ class RendererReferenceNode extends ReferenceBaseNode { static get type() { @@ -10,16 +23,38 @@ class RendererReferenceNode extends ReferenceBaseNode { } + /** + * Constructs a new renderer reference node. + * + * @param {String} property - The name of the property the node refers to. + * @param {String} inputType - The uniform type that should be used to represent the property value. + * @param {Renderer?} [renderer=null] - The renderer the property belongs to. When no renderer is set, + * the node refers to the renderer of the current state. + */ constructor( property, inputType, renderer = null ) { super( property, inputType, renderer ); + /** + * The renderer the property belongs to. When no renderer is set, + * the node refers to the renderer of the current state. + * + * @type {Renderer?} + * @default null + */ this.renderer = renderer; this.setGroup( renderGroup ); } + /** + * Updates the reference based on the given state. The state is only evaluated + * {@link module:RendererReferenceNode~RendererReferenceNode#renderer} is not set. + * + * @param {(NodeFrame|NodeBuilder)} state - The current state. + * @return {Object} The updated reference. + */ updateReference( state ) { this.reference = this.renderer !== null ? this.renderer : state.renderer; @@ -32,4 +67,14 @@ class RendererReferenceNode extends ReferenceBaseNode { export default RendererReferenceNode; -export const rendererReference = ( name, type, renderer ) => nodeObject( new RendererReferenceNode( name, type, renderer ) ); +/** + * TSL function for creating a renderer reference node. + * + * @function + * @param {String} name - The name of the property the node refers to. + * @param {String} type - The uniform type that should be used to represent the property value. + * @param {Renderer?} [renderer=null] - The renderer the property belongs to. When no renderer is set, + * the node refers to the renderer of the current state. + * @returns {RendererReferenceNode} + */ +export const rendererReference = ( name, type, renderer = null ) => nodeObject( new RendererReferenceNode( name, type, renderer ) ); diff --git a/src/nodes/accessors/SkinningNode.js b/src/nodes/accessors/SkinningNode.js index 25b33a00953bdf..f3c62ac5f77796 100644 --- a/src/nodes/accessors/SkinningNode.js +++ b/src/nodes/accessors/SkinningNode.js @@ -9,9 +9,18 @@ import { positionLocal, positionPrevious } from './Position.js'; import { tangentLocal } from './Tangent.js'; import { uniform } from '../core/UniformNode.js'; import { buffer } from './BufferNode.js'; +import { getDataFromObject } from '../core/NodeUtils.js'; + +/** @module SkinningNode **/ const _frameId = new WeakMap(); +/** + * This node implements the vertex transformation shader logic which is required + * for skinning/skeletal animation. + * + * @augments Node + */ class SkinningNode extends Node { static get type() { @@ -20,18 +29,52 @@ class SkinningNode extends Node { } + /** + * Constructs a new skinning node. + * + * @param {SkinnedMesh} skinnedMesh - The skinned mesh. + * @param {Boolean} [useReference=false] - Whether to use reference nodes for internal skinned mesh related data or not. + */ constructor( skinnedMesh, useReference = false ) { super( 'void' ); + /** + * The skinned mesh. + * + * @type {SkinnedMesh} + */ this.skinnedMesh = skinnedMesh; + + /** + * Whether to use reference nodes for internal skinned mesh related data or not. + * TODO: Explain the purpose of the property. + * + * @type {Boolean} + */ this.useReference = useReference; + /** + * The update type overwritten since skinning nodes are updated per object. + * + * @type {String} + */ this.updateType = NodeUpdateType.OBJECT; // + /** + * The skin index attribute. + * + * @type {AttributeNode} + */ this.skinIndexNode = attribute( 'skinIndex', 'uvec4' ); + + /** + * The skin weight attribute. + * + * @type {AttributeNode} + */ this.skinWeightNode = attribute( 'skinWeight', 'vec4' ); let bindMatrixNode, bindMatrixInverseNode, boneMatricesNode; @@ -50,13 +93,45 @@ class SkinningNode extends Node { } + /** + * The bind matrix node. + * + * @type {Node} + */ this.bindMatrixNode = bindMatrixNode; + + /** + * The bind matrix inverse node. + * + * @type {Node} + */ this.bindMatrixInverseNode = bindMatrixInverseNode; + + /** + * The bind matrices as a uniform buffer node. + * + * @type {Node} + */ this.boneMatricesNode = boneMatricesNode; + + /** + * The previous bind matrices as a uniform buffer node. + * Required for computing motion vectors. + * + * @type {Node?} + * @default null + */ this.previousBoneMatricesNode = null; } + /** + * Transforms the given vertex position via skinning. + * + * @param {Node} [boneMatrices=this.boneMatricesNode] - The bone matrices + * @param {Node} [position=positionLocal] - The vertex position in local space. + * @return {Node} The transformed vertex position. + */ getSkinnedPosition( boneMatrices = this.boneMatricesNode, position = positionLocal ) { const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; @@ -81,6 +156,13 @@ class SkinningNode extends Node { } + /** + * Transforms the given vertex normal via skinning. + * + * @param {Node} [boneMatrices=this.boneMatricesNode] - The bone matrices + * @param {Node} [normal=normalLocal] - The vertex normal in local space. + * @return {Node} The transformed vertex normal. + */ getSkinnedNormal( boneMatrices = this.boneMatricesNode, normal = normalLocal ) { const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode } = this; @@ -105,6 +187,12 @@ class SkinningNode extends Node { } + /** + * Transforms the given vertex normal via skinning. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Node} The skinned position from the previous frame. + */ getPreviousSkinnedPosition( builder ) { const skinnedMesh = builder.object; @@ -121,14 +209,25 @@ class SkinningNode extends Node { } + /** + * Returns `true` if bone matrices from the previous frame are required. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {Boolean} Whether bone matrices from the previous frame are required or not. + */ needsPreviousBoneMatrices( builder ) { const mrt = builder.renderer.getMRT(); - return mrt && mrt.has( 'velocity' ); + return ( mrt && mrt.has( 'velocity' ) ) || getDataFromObject( builder.object ).useVelocity === true; } + /** + * Setups the skinning node by assigning the transformed vertex data to predefined node variables. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { if ( this.needsPreviousBoneMatrices( builder ) ) { @@ -158,6 +257,13 @@ class SkinningNode extends Node { } + /** + * Generates the code snippet of the skinning node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output. + * @return {String} The generated code snippet. + */ generate( builder, output ) { if ( output !== 'void' ) { @@ -168,6 +274,11 @@ class SkinningNode extends Node { } + /** + * Updates the state of the skinned mesh by updating the skeleton once per frame. + * + * @param {NodeFrame} frame - The current node frame. + */ update( frame ) { const object = this.useReference ? frame.object : this.skinnedMesh; @@ -187,5 +298,20 @@ class SkinningNode extends Node { export default SkinningNode; +/** + * TSL function for creating a skinning node. + * + * @function + * @param {SkinnedMesh} skinnedMesh - The skinned mesh. + * @returns {SkinningNode} + */ export const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) ); + +/** + * TSL function for creating a skinning node with reference usage. + * + * @function + * @param {SkinnedMesh} skinnedMesh - The skinned mesh. + * @returns {SkinningNode} + */ export const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) ); diff --git a/src/nodes/accessors/StorageBufferNode.js b/src/nodes/accessors/StorageBufferNode.js index cb9798c05bc854..fcc2c172b42de7 100644 --- a/src/nodes/accessors/StorageBufferNode.js +++ b/src/nodes/accessors/StorageBufferNode.js @@ -5,6 +5,39 @@ import { storageElement } from '../utils/StorageArrayElementNode.js'; import { NodeAccess } from '../core/constants.js'; import { getTypeFromLength } from '../core/NodeUtils.js'; +/** @module StorageBufferNode **/ + +/** + * This node is used in context of compute shaders and allows to define a + * storage buffer for data. A typical workflow is to create instances of + * this node with the convenience functions `attributeArray()` or `instancedArray()`, + * setup up a compute shader that writes into the buffers and then convert + * the storage buffers to attribute nodes for rendering. + * + * ```js + * const positionBuffer = instancedArray( particleCount, 'vec3' ); // the storage buffer node + * + * const computeInit = Fn( () => { // the compute shader + * + * const position = positionBuffer.element( instanceIndex ); + * + * // compute position data + * + * position.x = 1; + * position.y = 1; + * position.z = 1; + * + * } )().compute( particleCount ); + * + * const particleMaterial = new THREE.SpriteNodeMaterial(); + * particleMaterial.positionNode = positionBuffer.toAttribute(); + * + * renderer.computeAsync( computeInit ); + * + * ``` + * + * @augments BufferNode + */ class StorageBufferNode extends BufferNode { static get type() { @@ -13,6 +46,13 @@ class StorageBufferNode extends BufferNode { } + /** + * Constructs a new storage buffer node. + * + * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. + * @param {String?} [bufferType=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [bufferCount=0] - The buffer count. + */ constructor( value, bufferType = null, bufferCount = 0 ) { if ( bufferType === null && ( value.isStorageBufferAttribute || value.isStorageInstancedBufferAttribute ) ) { @@ -24,17 +64,62 @@ class StorageBufferNode extends BufferNode { super( value, bufferType, bufferCount ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageBufferNode = true; + /** + * The access type of the texture node. + * + * @type {String} + * @default 'readWrite' + */ this.access = NodeAccess.READ_WRITE; + + /** + * Whether the node is atomic or not. + * + * @type {Boolean} + * @default false + */ this.isAtomic = false; - this.isPBO = false; - this.bufferCount = bufferCount; + /** + * Whether the node represents a PBO or not. + * Only relevant for WebGL. + * + * @type {Boolean} + * @default false + */ + this.isPBO = false; + /** + * A reference to the internal buffer attribute node. + * + * @type {BufferAttributeNode?} + * @default null + */ this._attribute = null; + + /** + * A reference to the internal varying node. + * + * @type {VaryingNode?} + * @default null + */ this._varying = null; + /** + * `StorageBufferNode` sets this property to `true` by default. + * + * @type {Boolean} + * @default true + */ this.global = true; if ( value.isStorageBufferAttribute !== true && value.isStorageInstancedBufferAttribute !== true ) { @@ -48,6 +133,13 @@ class StorageBufferNode extends BufferNode { } + /** + * This method is overwritten since the buffer data might be shared + * and thus the hash should be shared as well. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The hash. + */ getHash( builder ) { if ( this.bufferCount === 0 ) { @@ -72,18 +164,36 @@ class StorageBufferNode extends BufferNode { } + /** + * Overwrites the default implementation to return a fixed value `'indirectStorageBuffer'` or `'storageBuffer'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return this.value.isIndirectStorageBufferAttribute ? 'indirectStorageBuffer' : 'storageBuffer'; } + /** + * Enables element access with the given index node. + * + * @param {IndexNode} indexNode - The index node. + * @return {StorageArrayElementNode} A node representing the element access. + */ element( indexNode ) { return storageElement( this, indexNode ); } + /** + * Defines whether this node is a PBO or not. Only relevant for WebGL. + * + * @param {Boolean} value - The value so set. + * @return {StorageBufferNode} A reference to this node. + */ setPBO( value ) { this.isPBO = value; @@ -92,12 +202,23 @@ class StorageBufferNode extends BufferNode { } + /** + * Returns the `isPBO` value. + * + * @return {Boolean} Whether the node represents a PBO or not. + */ getPBO() { return this.isPBO; } + /** + * Defines the node access. + * + * @param {String} value - The node access. + * @return {StorageBufferNode} A reference to this node. + */ setAccess( value ) { this.access = value; @@ -106,12 +227,23 @@ class StorageBufferNode extends BufferNode { } + /** + * Convenience method for configuring a read-only node access. + * + * @return {StorageBufferNode} A reference to this node. + */ toReadOnly() { return this.setAccess( NodeAccess.READ_ONLY ); } + /** + * Defines whether the node is atomic or not. + * + * @param {Boolean} value - The atomic flag. + * @return {StorageBufferNode} A reference to this node. + */ setAtomic( value ) { this.isAtomic = value; @@ -120,12 +252,22 @@ class StorageBufferNode extends BufferNode { } + /** + * Convenience method for making this node atomic. + * + * @return {StorageBufferNode} A reference to this node. + */ toAtomic() { return this.setAtomic( true ); } + /** + * Returns attribute data for this storage buffer node. + * + * @return {{attribute: BufferAttributeNode, varying: VaryingNode}} The attribute data. + */ getAttributeData() { if ( this._attribute === null ) { @@ -142,6 +284,13 @@ class StorageBufferNode extends BufferNode { } + /** + * This method is overwritten since the node type from the availability of storage buffers + * and the attribute data. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { if ( builder.isAvailable( 'storageBuffer' ) || builder.isAvailable( 'indirectStorageBuffer' ) ) { @@ -156,6 +305,12 @@ class StorageBufferNode extends BufferNode { } + /** + * Generates the code snippet of the storage buffer node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The generated code snippet. + */ generate( builder ) { if ( builder.isAvailable( 'storageBuffer' ) || builder.isAvailable( 'indirectStorageBuffer' ) ) { @@ -178,8 +333,26 @@ class StorageBufferNode extends BufferNode { export default StorageBufferNode; -export const storage = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ) ); - +/** + * TSL function for creating a storage buffer node. + * + * @function + * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. + * @param {String?} [type=null] - The buffer type (e.g. `'vec3'`). + * @param {Number} [count=0] - The buffer count. + * @returns {StorageBufferNode} + */ +export const storage = ( value, type = null, count = 0 ) => nodeObject( new StorageBufferNode( value, type, count ) ); + +/** + * @function + * @deprecated since r171. Use `storage().setPBO( true )` instead. + * + * @param {StorageBufferAttribute|StorageInstancedBufferAttribute|BufferAttribute} value - The buffer data. + * @param {String?} type - The buffer type (e.g. `'vec3'`). + * @param {Number} count - The buffer count. + * @returns {StorageBufferNode} + */ export const storageObject = ( value, type, count ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "storageObject()" is deprecated. Use "storage().setPBO( true )" instead.' ); diff --git a/src/nodes/accessors/StorageTextureNode.js b/src/nodes/accessors/StorageTextureNode.js index db7063b1618a67..1fdcfa53ba6c82 100644 --- a/src/nodes/accessors/StorageTextureNode.js +++ b/src/nodes/accessors/StorageTextureNode.js @@ -2,6 +2,39 @@ import TextureNode from './TextureNode.js'; import { nodeProxy } from '../tsl/TSLBase.js'; import { NodeAccess } from '../core/constants.js'; +/** @module StorageTextureNode **/ + +/** + * This special version of a texture node can be used to + * write data into a storage texture with a compute shader. + * + * ```js + * const storageTexture = new THREE.StorageTexture( width, height ); + * + * const computeTexture = Fn( ( { storageTexture } ) => { + * + * const posX = instanceIndex.modInt( width ); + * const posY = instanceIndex.div( width ); + * const indexUV = uvec2( posX, posY ); + * + * // generate RGB values + * + * const r = 1; + * const g = 1; + * const b = 1; + * + * textureStore( storageTexture, indexUV, vec4( r, g, b, 1 ) ).toWriteOnly(); + * + * } ); + * + * const computeNode = computeTexture( { storageTexture } ).compute( width * height ); + * renderer.computeAsync( computeNode ); + * ``` + * + * This node can only be used with a WebGPU backend. + * + * @augments module:TextureNode~TextureNode + */ class StorageTextureNode extends TextureNode { static get type() { @@ -10,18 +43,50 @@ class StorageTextureNode extends TextureNode { } + /** + * Constructs a new storage texture node. + * + * @param {StorageTexture} value - The storage texture. + * @param {Node} uvNode - The uv node. + * @param {Node?} [storeNode=null] - The value node that should be stored in the texture. + */ constructor( value, uvNode, storeNode = null ) { super( value, uvNode ); + /** + * The value node that should be stored in the texture. + * + * @type {Node?} + * @default null + */ this.storeNode = storeNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageTextureNode = true; + /** + * The access type of the texture node. + * + * @type {String} + * @default 'writeOnly' + */ this.access = NodeAccess.WRITE_ONLY; } + /** + * Overwrites the default implementation to return a fixed value `'storageTexture'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'storageTexture'; @@ -37,6 +102,12 @@ class StorageTextureNode extends TextureNode { } + /** + * Defines the node access. + * + * @param {String} value - The node access. + * @return {StorageTextureNode} A reference to this node. + */ setAccess( value ) { this.access = value; @@ -44,6 +115,14 @@ class StorageTextureNode extends TextureNode { } + /** + * Generates the code snippet of the stroge node. If no `storeNode` + * is defined, the texture node is generated as normal texture. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output. + * @return {String} The generated code snippet. + */ generate( builder, output ) { let snippet; @@ -62,24 +141,44 @@ class StorageTextureNode extends TextureNode { } + /** + * Convenience method for configuring a read/write node access. + * + * @return {StorageTextureNode} A reference to this node. + */ toReadWrite() { return this.setAccess( NodeAccess.READ_WRITE ); } + /** + * Convenience method for configuring a read-only node access. + * + * @return {StorageTextureNode} A reference to this node. + */ toReadOnly() { return this.setAccess( NodeAccess.READ_ONLY ); } + /** + * Convenience method for configuring a write-only node access. + * + * @return {StorageTextureNode} A reference to this node. + */ toWriteOnly() { return this.setAccess( NodeAccess.WRITE_ONLY ); } + /** + * Generates the code snippet of the storage texture node. + * + * @param {NodeBuilder} builder - The current node builder. + */ generateStore( builder ) { const properties = builder.getNodeProperties( this ); @@ -100,8 +199,27 @@ class StorageTextureNode extends TextureNode { export default StorageTextureNode; +/** + * TSL function for creating a storage texture node. + * + * @function + * @param {StorageTexture} value - The storage texture. + * @param {Node} uvNode - The uv node. + * @param {Node?} [storeNode=null] - The value node that should be stored in the texture. + * @returns {StorageTextureNode} + */ export const storageTexture = /*@__PURE__*/ nodeProxy( StorageTextureNode ); + +/** + * TODO: Explain difference to `storageTexture()`. + * + * @function + * @param {StorageTexture} value - The storage texture. + * @param {Node} uvNode - The uv node. + * @param {Node?} [storeNode=null] - The value node that should be stored in the texture. + * @returns {StorageTextureNode} + */ export const textureStore = ( value, uvNode, storeNode ) => { const node = storageTexture( value, uvNode, storeNode ); diff --git a/src/nodes/accessors/Tangent.js b/src/nodes/accessors/Tangent.js index 18ca58a29a78fe..f8a3c9c563c015 100644 --- a/src/nodes/accessors/Tangent.js +++ b/src/nodes/accessors/Tangent.js @@ -3,6 +3,13 @@ import { cameraViewMatrix } from './Camera.js'; import { modelViewMatrix } from './ModelNode.js'; import { Fn, vec4 } from '../tsl/TSLBase.js'; +/** @module Tangent **/ + +/** + * TSL object that represents the tangent attribute of the current rendered object. + * + * @type {Node} + */ export const tangentGeometry = /*@__PURE__*/ Fn( ( builder ) => { if ( builder.geometry.hasAttribute( 'tangent' ) === false ) { @@ -15,8 +22,37 @@ export const tangentGeometry = /*@__PURE__*/ Fn( ( builder ) => { } )(); +/** + * TSL object that represents the vertex tangent in local space of the current rendered object. + * + * @type {Node} + */ export const tangentLocal = /*@__PURE__*/ tangentGeometry.xyz.toVar( 'tangentLocal' ); + +/** + * TSL object that represents the vertex tangent in view space of the current rendered object. + * + * @type {Node} + */ export const tangentView = /*@__PURE__*/ modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.varying( 'v_tangentView' ).normalize().toVar( 'tangentView' ); + +/** + * TSL object that represents the vertex tangent in world space of the current rendered object. + * + * @type {Node} + */ export const tangentWorld = /*@__PURE__*/ tangentView.transformDirection( cameraViewMatrix ).varying( 'v_tangentWorld' ).normalize().toVar( 'tangentWorld' ); + +/** + * TSL object that represents the transformed vertex tangent in view space of the current rendered object. + * + * @type {Node} + */ export const transformedTangentView = /*@__PURE__*/ tangentView.toVar( 'transformedTangentView' ); + +/** + * TSL object that represents the transformed vertex tangent in world space of the current rendered object. + * + * @type {Node} + */ export const transformedTangentWorld = /*@__PURE__*/ transformedTangentView.transformDirection( cameraViewMatrix ).normalize().toVar( 'transformedTangentWorld' ); diff --git a/src/nodes/accessors/Texture3DNode.js b/src/nodes/accessors/Texture3DNode.js index af92c679e2547c..86b0973b0d0f9b 100644 --- a/src/nodes/accessors/Texture3DNode.js +++ b/src/nodes/accessors/Texture3DNode.js @@ -1,5 +1,8 @@ import TextureNode from './TextureNode.js'; -import { nodeProxy, vec3, Fn, If } from '../tsl/TSLBase.js'; +import { nodeProxy, vec3, Fn, If, int } from '../tsl/TSLBase.js'; +import { textureSize } from './TextureSizeNode.js'; + +/** @module Texture3DNode **/ const normal = Fn( ( { texture, uv } ) => { @@ -47,7 +50,11 @@ const normal = Fn( ( { texture, uv } ) => { } ); - +/** + * This type of uniform node represents a 3D texture. + * + * @augments module:TextureNode~TextureNode + */ class Texture3DNode extends TextureNode { static get type() { @@ -56,40 +63,108 @@ class Texture3DNode extends TextureNode { } + /** + * Constructs a new 3D texture node. + * + * @param {Data3DTexture} value - The 3D texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + */ constructor( value, uvNode = null, levelNode = null ) { super( value, uvNode, levelNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isTexture3DNode = true; } + /** + * Overwrites the default implementation to return a fixed value `'texture3D'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'texture3D'; } + /** + * Returns a default uv node which is in context of 3D textures a three-dimensional + * uv node. + * + * @return {Node} The default uv node. + */ getDefaultUV() { return vec3( 0.5, 0.5, 0.5 ); } - setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for 3d TextureNode - + /** + * Overwritten with an empty implementation since the `updateMatrix` flag is ignored + * for 3D textures. The uv transformation matrix is not applied to 3D textures. + * + * @param {Boolean} value - The update toggle. + */ + setUpdateMatrix( /*value*/ ) { } // Ignore .updateMatrix for 3d TextureNode + + /** + * Overwrites the default implementation to return the unmodified uv node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to setup. + * @return {Node} The unmodified uv node. + */ setupUV( builder, uvNode ) { + const texture = this.value; + + if ( builder.isFlipY() && ( texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true ) ) { + + if ( this.sampler ) { + + uvNode = uvNode.flipY(); + + } else { + + uvNode = uvNode.setY( int( textureSize( this, this.levelNode ).y ).sub( uvNode.y ).sub( 1 ) ); + + } + + } + return uvNode; } + /** + * Generates the uv code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to generate code for. + * @return {String} The generated code snippet. + */ generateUV( builder, uvNode ) { return uvNode.build( builder, 'vec3' ); } + /** + * TODO. + * + * @param {Node} uvNode - The uv node . + * @return {Node} TODO. + */ normal( uvNode ) { return normal( { texture: this, uv: uvNode } ); @@ -100,4 +175,13 @@ class Texture3DNode extends TextureNode { export default Texture3DNode; +/** + * TSL function for creating a 3D texture node. + * + * @function + * @param {Data3DTexture} value - The 3D texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @returns {Texture3DNode} + */ export const texture3D = /*@__PURE__*/ nodeProxy( Texture3DNode ); diff --git a/src/nodes/accessors/TextureBicubic.js b/src/nodes/accessors/TextureBicubic.js index 8f8f0523de183b..09b56fa1e76ade 100644 --- a/src/nodes/accessors/TextureBicubic.js +++ b/src/nodes/accessors/TextureBicubic.js @@ -2,6 +2,8 @@ import { add, mul, div } from '../math/OperatorNode.js'; import { floor, ceil, fract, pow } from '../math/MathNode.js'; import { Fn, float, vec2, vec4, int } from '../tsl/TSLBase.js'; +/** @module TextureBicubic **/ + // Mipped Bicubic Texture Filtering by N8 // https://www.shadertoy.com/view/Dl2SDW @@ -51,6 +53,14 @@ const bicubic = ( textureNode, texelSize, lod ) => { }; +/** + * Applies mipped bicubic texture filtering to the given texture node. + * + * @method + * @param {TextureNode} textureNode - The texture node that should be filtered. + * @param {Node} [lodNode=float(3)] - Defines the LOD to sample from. + * @return {Node} The filtered texture sample. + */ export const textureBicubic = /*@__PURE__*/ Fn( ( [ textureNode, lodNode = float( 3 ) ] ) => { const fLodSize = vec2( textureNode.size( int( lodNode ) ) ); diff --git a/src/nodes/accessors/TextureNode.js b/src/nodes/accessors/TextureNode.js index a4f118282314b8..cb3b6b602cae2e 100644 --- a/src/nodes/accessors/TextureNode.js +++ b/src/nodes/accessors/TextureNode.js @@ -9,6 +9,13 @@ import { NodeUpdateType } from '../core/constants.js'; import { IntType, UnsignedIntType } from '../../constants.js'; +/** @module TextureNode **/ + +/** + * This type of uniform node represents a 2D texture. + * + * @augments module:UniformNode~UniformNode + */ class TextureNode extends UniformNode { static get type() { @@ -17,26 +24,125 @@ class TextureNode extends UniformNode { } + /** + * Constructs a new texture node. + * + * @param {Texture} value - The texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + */ constructor( value, uvNode = null, levelNode = null, biasNode = null ) { super( value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isTextureNode = true; + /** + * Represents the texture coordinates. + * + * @type {Node?} + * @default null + */ this.uvNode = uvNode; + + /** + * Represents the mip level that should be selected. + * + * @type {Node?} + * @default null + */ this.levelNode = levelNode; + + /** + * Represents the bias to be applied during level-of-detail computation. + * + * @type {Node?} + * @default null + */ this.biasNode = biasNode; + + /** + * Represents a reference value a texture sample is compared to. + * + * @type {Node?} + * @default null + */ this.compareNode = null; + + /** + * When using texture arrays, the depth node defines the layer to select. + * + * @type {Node?} + * @default null + */ this.depthNode = null; + + /** + * When defined, a texture is sampled using explicit gradients. + * + * @type {Array>?} + * @default null + */ this.gradNode = null; + /** + * Whether texture values should be sampled or fetched. + * + * @type {Boolean} + * @default true + */ this.sampler = true; + + /** + * Whether the uv transformation matrix should be + * automatically updated or not. Use `setUpdateMatrix()` + * if you want to change the value of the property. + * + * @type {Boolean} + * @default false + */ this.updateMatrix = false; + + /** + * By default the `update()` method is not executed. `setUpdateMatrix()` + * sets the value to `frame` when the uv transformation matrix should + * automatically be updated. + * + * @type {String} + * @default 'none' + */ this.updateType = NodeUpdateType.NONE; + /** + * The reference node. + * + * @type {Node?} + * @default null + */ this.referenceNode = null; + /** + * The texture value is stored in a private property. + * + * @private + * @type {Texture} + */ this._value = value; + + /** + * The uniform node that represents the uv transformation matrix. + * + * @private + * @type {UniformNode?} + */ this._matrixUniform = null; this.setUpdateMatrix( uvNode === null ); @@ -57,18 +163,35 @@ class TextureNode extends UniformNode { } + /** + * The texture value. + * + * @type {Texture} + */ get value() { return this.referenceNode ? this.referenceNode.value : this._value; } + /** + * Overwritten since the uniform hash is defined by the texture's UUID. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The uniform hash. + */ getUniformHash( /*builder*/ ) { return this.value.uuid; } + /** + * Overwritten since the node type is inferred from the texture type. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( /*builder*/ ) { if ( this.value.isDepthTexture === true ) return 'float'; @@ -87,24 +210,47 @@ class TextureNode extends UniformNode { } + /** + * Overwrites the default implementation to return a fixed value `'texture'`. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return 'texture'; } + /** + * Returns a default uvs based on the current texture's channel. + * + * @return {AttributeNode} The default uvs. + */ getDefaultUV() { return uv( this.value.channel ); } + /** + * Overwritten to always return the texture reference of the node. + * + * @param {Any} state - This method can be invocated in different contexts so `state` can refer to any object type. + * @return {Texture} The texture reference. + */ updateReference( /*state*/ ) { return this.value; } + /** + * Transforms the given uv node with the texture transformation matrix. + * + * @param {Node} uvNode - The uv node to transform. + * @return {Node} The transformed uv node. + */ getTransformedUV( uvNode ) { if ( this._matrixUniform === null ) this._matrixUniform = uniform( this.value.matrix ); @@ -113,15 +259,29 @@ class TextureNode extends UniformNode { } + /** + * Defines whether the uv transformation matrix should automatically be updated or not. + * + * @param {Boolean} value - The update toggle. + * @return {TextureNode} A reference to this node. + */ setUpdateMatrix( value ) { this.updateMatrix = value; - this.updateType = value ? NodeUpdateType.FRAME : NodeUpdateType.NONE; + this.updateType = value ? NodeUpdateType.RENDER : NodeUpdateType.NONE; return this; } + /** + * Setups the uv node. Depending on the backend as well as texture's image and type, it might be necessary + * to modify the uv node for correct sampling. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to setup. + * @return {Node} The updated uv node. + */ setupUV( builder, uvNode ) { const texture = this.value; @@ -144,6 +304,11 @@ class TextureNode extends UniformNode { } + /** + * Setups texture node by preparing the internal nodes for code generation. + * + * @param {NodeBuilder} builder - The current node builder. + */ setup( builder ) { const properties = builder.getNodeProperties( this ); @@ -151,6 +316,16 @@ class TextureNode extends UniformNode { // + const texture = this.value; + + if ( ! texture || texture.isTexture !== true ) { + + throw new Error( 'THREE.TSL: `texture( value )` function expects a valid instance of THREE.Texture().' ); + + } + + // + let uvNode = this.uvNode; if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) { @@ -190,12 +365,32 @@ class TextureNode extends UniformNode { } + /** + * Generates the uv code snippet. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {Node} uvNode - The uv node to generate code for. + * @return {String} The generated code snippet. + */ generateUV( builder, uvNode ) { return uvNode.build( builder, this.sampler === true ? 'vec2' : 'ivec2' ); } + /** + * Generates the snippet for the texture sampling. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} textureProperty - The texture property. + * @param {String} uvSnippet - The uv snippet. + * @param {String?} levelSnippet - The level snippet. + * @param {String?} biasSnippet - The bias snippet. + * @param {String?} depthSnippet - The depth snippet. + * @param {String?} compareSnippet - The compare snippet. + * @param {Array?} gradSnippet - The grad snippet. + * @return {String} The generated code snippet. + */ generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, biasSnippet, depthSnippet, compareSnippet, gradSnippet ) { const texture = this.value; @@ -232,18 +427,18 @@ class TextureNode extends UniformNode { } + /** + * Generates the code snippet of the texture node. + * + * @param {NodeBuilder} builder - The current node builder. + * @param {String} output - The current output. + * @return {String} The generated code 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 properties = builder.getNodeProperties( this ); const textureProperty = super.generate( builder, 'property' ); if ( output === 'sampler' ) { @@ -299,6 +494,12 @@ class TextureNode extends UniformNode { } + /** + * Sets the sampler value. + * + * @param {Boolean} value - The sampler value to set. + * @return {TextureNode} A reference to this texture node. + */ setSampler( value ) { this.sampler = value; @@ -307,6 +508,11 @@ class TextureNode extends UniformNode { } + /** + * Returns the sampler value. + * + * @return {Boolean} The sampler value. + */ getSampler() { return this.sampler; @@ -315,6 +521,13 @@ class TextureNode extends UniformNode { // @TODO: Move to TSL + /** + * @function + * @deprecated since r172. Use {@link TextureNode#sample} instead. + * + * @param {Node} uvNode - The uv node. + * @return {TextureNode} A texture node representing the texture sample. + */ uv( uvNode ) { // @deprecated, r172 console.warn( 'THREE.TextureNode: .uv() has been renamed. Use .sample() instead.' ); @@ -323,6 +536,12 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture with the given uv node. + * + * @param {Node} uvNode - The uv node. + * @return {TextureNode} A texture node representing the texture sample. + */ sample( uvNode ) { const textureNode = this.clone(); @@ -333,6 +552,12 @@ class TextureNode extends UniformNode { } + /** + * Samples a blurred version of the texture by defining an internal bias. + * + * @param {Node} amountNode - How blurred the texture should be. + * @return {TextureNode} A texture node representing the texture sample. + */ blur( amountNode ) { const textureNode = this.clone(); @@ -343,6 +568,12 @@ class TextureNode extends UniformNode { } + /** + * Samples a specific mip of the texture. + * + * @param {Node} levelNode - The mip level to sample. + * @return {TextureNode} A texture node representing the texture sample. + */ level( levelNode ) { const textureNode = this.clone(); @@ -353,12 +584,24 @@ class TextureNode extends UniformNode { } + /** + * Returns the texture size of the requested level. + * + * @param {Node} levelNode - The level to compute the size for. + * @return {TextureSizeNode} The texture size. + */ size( levelNode ) { return textureSize( this, levelNode ); } + /** + * Samples the texture with the given bias. + * + * @param {Node} biasNode - The bias node. + * @return {TextureNode} A texture node representing the texture sample. + */ bias( biasNode ) { const textureNode = this.clone(); @@ -369,6 +612,12 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture by executing a compare operation. + * + * @param {Node} compareNode - The node that defines the compare value. + * @return {TextureNode} A texture node representing the texture sample. + */ compare( compareNode ) { const textureNode = this.clone(); @@ -379,6 +628,13 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture using an explicit gradient. + * + * @param {Node} gradNodeX - The gradX node. + * @param {Node} gradNodeY - The gradY node. + * @return {TextureNode} A texture node representing the texture sample. + */ grad( gradNodeX, gradNodeY ) { const textureNode = this.clone(); @@ -389,6 +645,12 @@ class TextureNode extends UniformNode { } + /** + * Samples the texture by defining a depth node. + * + * @param {Node} depthNode - The depth node. + * @return {TextureNode} A texture node representing the texture sample. + */ depth( depthNode ) { const textureNode = this.clone(); @@ -423,6 +685,9 @@ class TextureNode extends UniformNode { } + /** + * The update is used to implement the update of the uv transformation matrix. + */ update() { const texture = this.value; @@ -438,6 +703,11 @@ class TextureNode extends UniformNode { } + /** + * Clones the texture node. + * + * @return {TextureNode} The cloned texture node. + */ clone() { const newNode = new this.constructor( this.value, this.uvNode, this.levelNode, this.biasNode ); @@ -451,9 +721,37 @@ class TextureNode extends UniformNode { export default TextureNode; +/** + * TSL function for creating a texture node. + * + * @function + * @param {Texture} value - The texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + * @returns {TextureNode} + */ export const texture = /*@__PURE__*/ nodeProxy( TextureNode ); + +/** + * TSL function for creating a texture node that fetches/loads texels without interpolation. + * + * @function + * @param {Texture} value - The texture. + * @param {Node?} [uvNode=null] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Node?} [biasNode=null] - The bias node. + * @returns {TextureNode} + */ export const textureLoad = ( ...params ) => texture( ...params ).setSampler( false ); //export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level ); +/** + * Converts a texture or texture node to a sampler. + * + * @function + * @param {TextureNode|Texture} aTexture - The texture or texture node to convert. + * @returns {Node} + */ export const sampler = ( aTexture ) => ( aTexture.isNode === true ? aTexture : texture( aTexture ) ).convert( 'sampler' ); diff --git a/src/nodes/accessors/TextureSizeNode.js b/src/nodes/accessors/TextureSizeNode.js index 9d05a47e7439c8..87b0fafc690739 100644 --- a/src/nodes/accessors/TextureSizeNode.js +++ b/src/nodes/accessors/TextureSizeNode.js @@ -68,7 +68,7 @@ class TextureSizeNode extends Node { export default TextureSizeNode; /** - * TSL function for creating a texture size node with the given paramters. + * TSL function for creating a texture size node. * * @function * @param {TextureNode} textureNode - A texture node which size should be retrieved. diff --git a/src/nodes/accessors/UV.js b/src/nodes/accessors/UV.js index 6c94158bfdc8c0..c1a157d26c4cd0 100644 --- a/src/nodes/accessors/UV.js +++ b/src/nodes/accessors/UV.js @@ -6,7 +6,7 @@ import { attribute } from '../core/AttributeNode.js'; * TSL function for creating an uv attribute node with the given index. * * @function - * @param {Number} index - The uv index. + * @param {Number} [index=0] - The uv index. * @return {AttributeNode} The uv attribute node. */ -export const uv = ( index ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); +export const uv = ( index = 0 ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' ); diff --git a/src/nodes/accessors/UniformArrayNode.js b/src/nodes/accessors/UniformArrayNode.js index 7c0d81d442982f..a6365d698fdc51 100644 --- a/src/nodes/accessors/UniformArrayNode.js +++ b/src/nodes/accessors/UniformArrayNode.js @@ -4,6 +4,13 @@ import { getValueType } from '../core/NodeUtils.js'; import ArrayElementNode from '../utils/ArrayElementNode.js'; import BufferNode from './BufferNode.js'; +/** @module UniformArrayNode **/ + +/** + * Represents the element access on uniform array nodes. + * + * @augments ArrayElementNode + */ class UniformArrayElementNode extends ArrayElementNode { static get type() { @@ -12,10 +19,23 @@ class UniformArrayElementNode extends ArrayElementNode { } - constructor( arrayBuffer, indexNode ) { - - super( arrayBuffer, indexNode ); - + /** + * Constructs a new buffer node. + * + * @param {UniformArrayNode} uniformArrayNode - The uniform array node to access. + * @param {IndexNode} indexNode - The index data that define the position of the accessed element in the array. + */ + constructor( uniformArrayNode, indexNode ) { + + super( uniformArrayNode, indexNode ); + + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isArrayBufferElementNode = true; } @@ -32,6 +52,23 @@ class UniformArrayElementNode extends ArrayElementNode { } +/** + * Similar to {@link module:BufferNode~BufferNode} this module represents array-like data as + * uniform buffers. Unlike {@link module:BufferNode~BufferNode}, it can handle more common + * data types in the array (e.g `three.js` primitives) and automatically + * manage buffer padding. It should be the first choice when working with + * uniforms buffers. + * ```js + * const tintColors = uniformArray( [ + * new Color( 1, 0, 0 ), + * new Color( 0, 1, 0 ), + * new Color( 0, 0, 1 ) + * ], 'color' ); + * + * const redColor = tintColors.element( 0 ); + * + * @augments module:BufferNode~BufferNode + */ class UniformArrayNode extends BufferNode { static get type() { @@ -40,32 +77,89 @@ class UniformArrayNode extends BufferNode { } + /** + * Constructs a new uniform array node. + * + * @param {Array} value - Array holding the buffer data. + * @param {String?} [elementType=null] - The data type of a buffer element. + */ constructor( value, elementType = null ) { super( null ); + /** + * Array holding the buffer data. Unlike {@link module:BufferNode~BufferNode}, the array can + * hold number primitives as well as three.js objects like vectors, matrices + * or colors. + * + * @type {Array} + */ this.array = value; + + /** + * The data type of an array element. + * + * @type {String} + */ this.elementType = elementType === null ? getValueType( value[ 0 ] ) : elementType; + + /** + * The padded type. Uniform buffers must conform to a certain buffer layout + * so a separate type is computed to ensure correct buffer size. + * + * @type {String} + */ this.paddedType = this.getPaddedType(); + /** + * Overwritten since uniform array nodes are updated per render. + * + * @type {String} + * @default 'render' + */ this.updateType = NodeUpdateType.RENDER; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isArrayBufferNode = true; } - getNodeType() { + /** + * This method is overwritten since the node type is inferred from the + * {@link module:UniformArrayNode~UniformArrayNode#paddedType}. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ + getNodeType( /*builder*/ ) { return this.paddedType; } + /** + * The data type of the array elements. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The element type. + */ getElementType() { return this.elementType; } + /** + * Returns the padded type based on the element type. + * + * @return {String} The padded type. + */ getPaddedType() { const elementType = this.elementType; @@ -94,6 +188,12 @@ class UniformArrayNode extends BufferNode { } + /** + * The update makes sure to correctly transfer the data from the (complex) objects + * in the array to the internal, correctly padded value buffer. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ update( /*frame*/ ) { const { array, value } = this; @@ -194,6 +294,12 @@ class UniformArrayNode extends BufferNode { } + /** + * Implement the value buffer creation based on the array data. + * + * @param {NodeBuilder} builder - A reference to the current node builder. + * @return {null} + */ setup( builder ) { const length = this.array.length; @@ -215,6 +321,13 @@ class UniformArrayNode extends BufferNode { } + /** + * Overwrites the default `element()` method to provide element access + * based on {@link module:UniformArrayNode~UniformArrayNode}. + * + * @param {IndexNode} indexNode - The index node. + * @return {UniformArrayElementNode} + */ element( indexNode ) { return nodeObject( new UniformArrayElementNode( this, nodeObject( indexNode ) ) ); @@ -225,10 +338,24 @@ class UniformArrayNode extends BufferNode { export default UniformArrayNode; +/** + * TSL function for creating an uniform array node. + * + * @function + * @param {Array} values - Array-like data. + * @param {String?} nodeType - The data type of the array elements. + * @returns {UniformArrayNode} + */ export const uniformArray = ( values, nodeType ) => nodeObject( new UniformArrayNode( values, nodeType ) ); -// - +/** + * @function + * @deprecated since r168. Use {@link uniformArray} instead. + * + * @param {Array} values - Array-like data. + * @param {String} nodeType - The data type of the array elements. + * @returns {UniformArrayNode} + */ export const uniforms = ( values, nodeType ) => { // @deprecated, r168 console.warn( 'TSL.UniformArrayNode: uniforms() has been renamed to uniformArray().' ); diff --git a/src/nodes/accessors/UserDataNode.js b/src/nodes/accessors/UserDataNode.js index 01665518bcef30..dcfc8660f729a1 100644 --- a/src/nodes/accessors/UserDataNode.js +++ b/src/nodes/accessors/UserDataNode.js @@ -12,10 +12,10 @@ import { nodeObject } from '../tsl/TSLBase.js'; * const material = new THREE.SpriteNodeMaterial(); * material.rotationNode = userData( 'rotation', 'float' ); * ``` - * Since `UserDataNode` is extended from {@link ReferenceNode}, the node value + * Since `UserDataNode` is extended from {@link module:ReferenceNode~ReferenceNode}, the node value * will automatically be updated when the `rotation` user data field changes. * - * @augments ReferenceNode + * @augments module:ReferenceNode~ReferenceNode */ class UserDataNode extends ReferenceNode { @@ -48,7 +48,7 @@ class UserDataNode extends ReferenceNode { } /** - * Overwritten to make sure {@link ReferenceNode#reference} points to the correct + * Overwritten to make sure {@link module:ReferenceNode~ReferenceNode#reference} points to the correct * `userData` field. * * @param {(NodeFrame|NodeBuilder)} state - The current state to evaluate. @@ -67,7 +67,7 @@ class UserDataNode extends ReferenceNode { export default UserDataNode; /** - * TSL function for creating a user data node with the given paramters. + * TSL function for creating a user data node. * * @function * @param {String} name - The property name that should be referenced by the node. diff --git a/src/nodes/accessors/VelocityNode.js b/src/nodes/accessors/VelocityNode.js index bf9252f24fe441..e6c05f67d86232 100644 --- a/src/nodes/accessors/VelocityNode.js +++ b/src/nodes/accessors/VelocityNode.js @@ -33,8 +33,6 @@ class VelocityNode extends TempNode { /** * Constructs a new vertex color node. - * - * @param {Number} [index=0] - The attribute index. */ constructor() { diff --git a/src/nodes/accessors/VertexColorNode.js b/src/nodes/accessors/VertexColorNode.js index 4049a24653ed2b..a756fe88bc089e 100644 --- a/src/nodes/accessors/VertexColorNode.js +++ b/src/nodes/accessors/VertexColorNode.js @@ -7,7 +7,7 @@ import { Vector4 } from '../../math/Vector4.js'; /** * An attribute node for representing vertex colors. * - * @augments AttributeNode + * @augments module:AttributeNode~AttributeNode */ class VertexColorNode extends AttributeNode { @@ -102,7 +102,7 @@ class VertexColorNode extends AttributeNode { export default VertexColorNode; /** - * TSL function for creating a reference node with the given paramters. + * TSL function for creating a reference node. * * @function * @param {Number} index - The attribute index. diff --git a/src/nodes/code/CodeNode.js b/src/nodes/code/CodeNode.js index b3ea6d49884efd..402b14738300b2 100644 --- a/src/nodes/code/CodeNode.js +++ b/src/nodes/code/CodeNode.js @@ -141,7 +141,7 @@ class CodeNode extends Node { export default CodeNode; /** - * TSL function for creating a code node with the given paramters. + * TSL function for creating a code node. * * @function * @param {String} [code=''] - The native code. @@ -152,7 +152,7 @@ export default CodeNode; export const code = /*@__PURE__*/ nodeProxy( CodeNode ); /** - * TSL function for creating a JS code node with the given paramters. + * TSL function for creating a JS code node. * * @function * @param {String} src - The native code. @@ -162,7 +162,7 @@ export const code = /*@__PURE__*/ nodeProxy( CodeNode ); export const js = ( src, includes ) => code( src, includes, 'js' ); /** - * TSL function for creating a WGSL code node with the given paramters. + * TSL function for creating a WGSL code node. * * @function * @param {String} src - The native code. @@ -172,7 +172,7 @@ export const js = ( src, includes ) => code( src, includes, 'js' ); export const wgsl = ( src, includes ) => code( src, includes, 'wgsl' ); /** - * TSL function for creating a GLSL code node with the given paramters. + * TSL function for creating a GLSL code node. * * @function * @param {String} src - The native code. diff --git a/src/nodes/code/ExpressionNode.js b/src/nodes/code/ExpressionNode.js index b2c9e2c434a458..ec8ee839d2c7a0 100644 --- a/src/nodes/code/ExpressionNode.js +++ b/src/nodes/code/ExpressionNode.js @@ -59,7 +59,7 @@ class ExpressionNode extends Node { export default ExpressionNode; /** - * TSL function for creating an expression node with the given paramters. + * TSL function for creating an expression node. * * @function * @param {String} [snippet=''] - The native code snippet. diff --git a/src/nodes/code/ScriptableNode.js b/src/nodes/code/ScriptableNode.js index 90137e322d9af4..23bd6cbc69dc1d 100644 --- a/src/nodes/code/ScriptableNode.js +++ b/src/nodes/code/ScriptableNode.js @@ -3,6 +3,13 @@ import { scriptableValue } from './ScriptableValueNode.js'; import { nodeProxy, float } from '../tsl/TSLBase.js'; import { hashArray, hashString } from '../core/NodeUtils.js'; +/** @module ScriptableNode **/ + +/** + * A Map-like data structure for managing resources of scriptable nodes. + * + * @augments Map + */ class Resources extends Map { get( key, callback = null, ...params ) { @@ -58,8 +65,49 @@ class Parameters { } +/** + * Defines the resources (e.g. namespaces) of scriptable nodes. + * + * @type {Resources} + */ export const ScriptableNodeResources = new Resources(); +/** + * This type of node allows to implement nodes with custom scripts. The script + * section is represented as an instance of `CodeNode` written with JavaScript. + * The script itself must adhere to a specific structure. + * + * - main(): Executed once by default and every time `node.needsUpdate` is set. + * - layout: The layout object defines the script's interface (inputs and outputs). + * + * ```js + * ScriptableNodeResources.set( 'TSL', TSL ); + * + * const scriptableNode = scriptable( js( ` + * layout = { + * outputType: 'node', + * elements: [ + * { name: 'source', inputType: 'node' }, + * ] + * }; + * + * const { mul, oscSine } = TSL; + * + * function main() { + * const source = parameters.get( 'source' ) || float(); + * return mul( source, oscSine() ) ); + * } + * + * ` ) ); + * + * scriptableNode.setParameter( 'source', color( 1, 0, 0 ) ); + * + * const material = new THREE.MeshBasicNodeMaterial(); + * material.colorNode = scriptableNode; + * ``` + * + * @augments Node + */ class ScriptableNode extends Node { static get type() { @@ -68,11 +116,30 @@ class ScriptableNode extends Node { } + /** + * Constructs a new scriptable node. + * + * @param {CodeNode?} [codeNode=null] - The code node. + * @param {Object} [parameters={}] - The parameters definition. + */ constructor( codeNode = null, parameters = {} ) { super(); + /** + * The code node. + * + * @type {CodeNode?} + * @default null + */ this.codeNode = codeNode; + + /** + * The parameters definition. + * + * @type {Object} + * @default {} + */ this.parameters = parameters; this._local = new Resources(); @@ -86,34 +153,68 @@ class ScriptableNode extends Node { this.onRefresh = this.onRefresh.bind( this ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isScriptableNode = true; } + /** + * The source code of the scriptable node. + * + * @type {String} + */ get source() { return this.codeNode ? this.codeNode.code : ''; } + /** + * Sets the reference of a local script variable. + * + * @param {String} name - The variable name. + * @param {Object} value - The reference to set. + * @return {Resources} The resource map + */ setLocal( name, value ) { return this._local.set( name, value ); } + /** + * Gets the value of a local script variable. + * + * @param {String} name - The variable name. + * @return {Object} The value. + */ getLocal( name ) { return this._local.get( name ); } + /** + * Event listener for the `refresh` event. + */ onRefresh() { this._refresh(); } + /** + * Returns an input from the layout with the given id/name. + * + * @param {String} id - The id/name of the input. + * @return {Object} The element entry. + */ getInputLayout( id ) { for ( const element of this.getLayout() ) { @@ -128,6 +229,12 @@ class ScriptableNode extends Node { } + /** + * Returns an output from the layout with the given id/name. + * + * @param {String} id - The id/name of the output. + * @return {Object} The element entry. + */ getOutputLayout( id ) { for ( const element of this.getLayout() ) { @@ -142,6 +249,13 @@ class ScriptableNode extends Node { } + /** + * Defines a script output for the given name and value. + * + * @param {String} name - The name of the output. + * @param {Node} value - The node value. + * @return {ScriptableNode} A reference to this node. + */ setOutput( name, value ) { const outputs = this._outputs; @@ -160,18 +274,37 @@ class ScriptableNode extends Node { } + /** + * Returns a script output for the given name. + * + * @param {String} name - The name of the output. + * @return {ScriptableValueNode} The node value. + */ getOutput( name ) { return this._outputs[ name ]; } + /** + * Returns a parameter for the given name + * + * @param {String} name - The name of the parameter. + * @return {ScriptableValueNode} The node value. + */ getParameter( name ) { return this.parameters[ name ]; } + /** + * Sets a value for the given parameter name. + * + * @param {String} name - The parameter name. + * @param {Any} value - The parameter value. + * @return {ScriptableNode} A reference to this node. + */ setParameter( name, value ) { const parameters = this.parameters; @@ -205,12 +338,24 @@ class ScriptableNode extends Node { } + /** + * Returns the value of this node which is the value of + * the default output. + * + * @return {Node} The value. + */ getValue() { return this.getDefaultOutput().getValue(); } + /** + * Deletes a parameter from the script. + * + * @param {String} name - The parameter to remove. + * @return {ScriptableNode} A reference to this node. + */ deleteParameter( name ) { let valueNode = this.parameters[ name ]; @@ -227,6 +372,11 @@ class ScriptableNode extends Node { } + /** + * Deletes all parameters from the script. + * + * @return {ScriptableNode} A reference to this node. + */ clearParameters() { for ( const name of Object.keys( this.parameters ) ) { @@ -241,6 +391,13 @@ class ScriptableNode extends Node { } + /** + * Calls a function from the script. + * + * @param {String} name - The function name. + * @param {...Any} params - A list of parameters. + * @return {Any} The result of the function call. + */ call( name, ...params ) { const object = this.getObject(); @@ -254,6 +411,13 @@ class ScriptableNode extends Node { } + /** + * Asynchronously calls a function from the script. + * + * @param {String} name - The function name. + * @param {...Any} params - A list of parameters. + * @return {Promise} The result of the function call. + */ async callAsync( name, ...params ) { const object = this.getObject(); @@ -267,12 +431,23 @@ class ScriptableNode extends Node { } + /** + * Overwritten since the node types is inferred from the script's output. + * + * @param {NodeBuilder} builder - The current node builder + * @return {String} The node type. + */ getNodeType( builder ) { return this.getDefaultOutputNode().getNodeType( builder ); } + /** + * Refreshes the script node. + * + * @param {String?} [output=null] - An optional output. + */ refresh( output = null ) { if ( output !== null ) { @@ -287,6 +462,11 @@ class ScriptableNode extends Node { } + /** + * Returns an object representation of the script. + * + * @return {Object} The result object. + */ getObject() { if ( this.needsUpdate ) this.dispose(); @@ -302,7 +482,7 @@ class ScriptableNode extends Node { const THREE = ScriptableNodeResources.get( 'THREE' ); const TSL = ScriptableNodeResources.get( 'TSL' ); - const method = this.getMethod( this.codeNode ); + const method = this.getMethod(); const params = [ parameters, this._local, ScriptableNodeResources, refresh, setOutput, THREE, TSL ]; this._object = method( ...params ); @@ -368,12 +548,22 @@ class ScriptableNode extends Node { } + /** + * Returns the layout of the script. + * + * @return {Object} The script's layout. + */ getLayout() { return this.getObject().layout; } + /** + * Returns default node output of the script. + * + * @return {Node} The default node output. + */ getDefaultOutputNode() { const output = this.getDefaultOutput().value; @@ -388,12 +578,22 @@ class ScriptableNode extends Node { } + /** + * Returns default output of the script. + * + * @return {ScriptableValueNode} The default output. + */ getDefaultOutput() { return this._exec()._output; } + /** + * Returns a function created from the node's script. + * + * @return {Function} The function representing the node's code. + */ getMethod() { if ( this.needsUpdate ) this.dispose(); @@ -418,6 +618,9 @@ class ScriptableNode extends Node { } + /** + * Frees all internal resources. + */ dispose() { if ( this._method === null ) return; @@ -470,6 +673,12 @@ class ScriptableNode extends Node { } + /** + * Executes the `main` function of the script. + * + * @private + * @return {ScriptableNode} A reference to this node. + */ _exec() { if ( this.codeNode === null ) return this; @@ -488,6 +697,11 @@ class ScriptableNode extends Node { } + /** + * Executes the refresh. + * + * @private + */ _refresh() { this.needsUpdate = true; @@ -502,4 +716,12 @@ class ScriptableNode extends Node { export default ScriptableNode; +/** + * TSL function for creating a scriptable node. + * + * @function + * @param {CodeNode?} [codeNode=null] - The code node. + * @param {Object} [parameters={}] - The parameters definition. + * @returns {ScriptableNode} + */ export const scriptable = /*@__PURE__*/ nodeProxy( ScriptableNode ); diff --git a/src/nodes/code/ScriptableValueNode.js b/src/nodes/code/ScriptableValueNode.js index 29c8d86af37b74..9114b55a2accb7 100644 --- a/src/nodes/code/ScriptableValueNode.js +++ b/src/nodes/code/ScriptableValueNode.js @@ -4,6 +4,13 @@ import { nodeProxy, float } from '../tsl/TSLBase.js'; import { EventDispatcher } from '../../core/EventDispatcher.js'; +/** @module ScriptableValueNode **/ + +/** + * `ScriptableNode` uses this class to manage script inputs and outputs. + * + * @augments Node + */ class ScriptableValueNode extends Node { static get type() { @@ -12,22 +19,72 @@ class ScriptableValueNode extends Node { } + /** + * Constructs a new scriptable node. + * + * @param {Any} [value=null] - The value. + */ constructor( value = null ) { super(); + /** + * A reference to the value. + * + * @private + * @default null + */ this._value = value; + + /** + * Depending on the type of `_value`, this property might cache parsed data. + * + * @private + * @default null + */ this._cache = null; + /** + * If this node represents an input, this property represents the input type. + * + * @type {String?} + * @default null + */ this.inputType = null; + + /** + * If this node represents an output, this property represents the output type. + * + * @type {String?} + * @default null + */ this.outputType = null; + /** + * An event dispatcher for managing events. + * + * @type {EventDispatcher} + */ this.events = new EventDispatcher(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isScriptableValueNode = true; } + /** + * Whether this node represents an output or not. + * + * @type {Boolean} + * @readonly + * @default true + */ get isScriptableOutputNode() { return this.outputType !== null; @@ -54,18 +111,32 @@ class ScriptableValueNode extends Node { } + /** + * The node's value. + * + * @type {Any} + */ get value() { return this._value; } + /** + * Dispatches the `refresh` event. + */ refresh() { this.events.dispatchEvent( { type: 'refresh' } ); } + /** + * The `value` property usually represents a node or even binary data in form of array buffers. + * In this case, this method tries to return the actual value behind the complex type. + * + * @return {Any} The value. + */ getValue() { const value = this.value; @@ -93,6 +164,12 @@ class ScriptableValueNode extends Node { } + /** + * Overwritten since the node type is inferred from the value. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { return this.value && this.value.isNode ? this.value.getNodeType( builder ) : 'float'; @@ -167,4 +244,11 @@ class ScriptableValueNode extends Node { export default ScriptableValueNode; +/** + * TSL function for creating a scriptable value node. + * + * @function + * @param {Any} [value=null] - The value. + * @returns {ScriptableValueNode} + */ export const scriptableValue = /*@__PURE__*/ nodeProxy( ScriptableValueNode ); diff --git a/src/nodes/core/AssignNode.js b/src/nodes/core/AssignNode.js index e339742be2ba37..491967fbf7d64e 100644 --- a/src/nodes/core/AssignNode.js +++ b/src/nodes/core/AssignNode.js @@ -165,7 +165,7 @@ class AssignNode extends TempNode { export default AssignNode; /** - * TSL function for creating an assign node with the given parameters. + * TSL function for creating an assign node. * * @function * @param {Node} targetNode - The target node. diff --git a/src/nodes/core/AttributeNode.js b/src/nodes/core/AttributeNode.js index 453a2ec6ac1993..8e47916a1b81e9 100644 --- a/src/nodes/core/AttributeNode.js +++ b/src/nodes/core/AttributeNode.js @@ -158,7 +158,7 @@ class AttributeNode extends Node { export default AttributeNode; /** - * TSL function for creating an attribute node with the given parameters. + * TSL function for creating an attribute node. * * @function * @param {String} name - The name of the attribute. diff --git a/src/nodes/core/BypassNode.js b/src/nodes/core/BypassNode.js index 6edb2f9b8aaae4..8cfdc2d9c986ac 100644 --- a/src/nodes/core/BypassNode.js +++ b/src/nodes/core/BypassNode.js @@ -82,7 +82,7 @@ class BypassNode extends Node { export default BypassNode; /** - * TSL function for creating a bypass node with the given parameters. + * TSL function for creating a bypass node. * * @function * @param {Node} outputNode - The output node. diff --git a/src/nodes/core/CacheNode.js b/src/nodes/core/CacheNode.js index 7e8025322360ae..d7a5be87bd7773 100644 --- a/src/nodes/core/CacheNode.js +++ b/src/nodes/core/CacheNode.js @@ -56,7 +56,16 @@ class CacheNode extends Node { getNodeType( builder ) { - return this.node.getNodeType( builder ); + const previousCache = builder.getCache(); + const cache = builder.getCacheFromNode( this, this.parent ); + + builder.setCache( cache ); + + const nodeType = this.node.getNodeType( builder ); + + builder.setCache( previousCache ); + + return nodeType; } @@ -80,7 +89,7 @@ class CacheNode extends Node { export default CacheNode; /** - * TSL function for creating a cache node with the given parameters. + * TSL function for creating a cache node. * * @function * @param {Node} node - The node that should be cached. diff --git a/src/nodes/core/ContextNode.js b/src/nodes/core/ContextNode.js index 7db8b400ac85af..110aecc10dc427 100644 --- a/src/nodes/core/ContextNode.js +++ b/src/nodes/core/ContextNode.js @@ -58,9 +58,9 @@ class ContextNode extends Node { } /** - * This method is overwritten to ensure it returns the reference to {@link ContextNode#node}. + * This method is overwritten to ensure it returns the reference to {@link module:ContextNode~ContextNode#node}. * - * @return {Node} A reference to {@link ContextNode#node}. + * @return {Node} A reference to {@link module:ContextNode~ContextNode#node}. */ getScope() { @@ -69,10 +69,10 @@ class ContextNode extends Node { } /** - * This method is overwritten to ensure it returns the type to {@link ContextNode#node}. + * This method is overwritten to ensure it returns the type of {@link module:ContextNode~ContextNode#node}. * * @param {NodeBuilder} builder - The current node builder. - * @return {String} The type of {@link ContextNode#node}. + * @return {String} The node type. */ getNodeType( builder ) { @@ -119,7 +119,7 @@ class ContextNode extends Node { export default ContextNode; /** - * TSL function for creating a context node with the given parameters. + * TSL function for creating a context node. * * @function * @param {Node} node - The node whose context should be modified. diff --git a/src/nodes/core/MRTNode.js b/src/nodes/core/MRTNode.js index ef60b5a7464c68..125798fc4ea996 100644 --- a/src/nodes/core/MRTNode.js +++ b/src/nodes/core/MRTNode.js @@ -142,7 +142,7 @@ class MRTNode extends OutputStructNode { export default MRTNode; /** - * TSL function for creating a MRT node with the given parameters. + * TSL function for creating a MRT node. * * @function * @param {Object} outputNodes - The MRT outputs. diff --git a/src/nodes/core/Node.js b/src/nodes/core/Node.js index 577533b6c9a69a..5a2741e2e49694 100644 --- a/src/nodes/core/Node.js +++ b/src/nodes/core/Node.js @@ -474,8 +474,9 @@ class Node extends EventDispatcher { } - // return a outputNode if exists - return null; + // return a outputNode if exists or null + + return nodeProperties.outputNode || null; } @@ -609,17 +610,19 @@ class Node extends EventDispatcher { if ( properties.initialized !== true ) { - const stackNodesBeforeSetup = builder.stack.nodes.length; + //const stackNodesBeforeSetup = builder.stack.nodes.length; properties.initialized = true; - properties.outputNode = this.setup( builder ); - if ( properties.outputNode !== null && builder.stack.nodes.length !== stackNodesBeforeSetup ) { + const outputNode = this.setup( builder ); // return a node or null + const isNodeOutput = outputNode && outputNode.isNode === true; + + /*if ( isNodeOutput && builder.stack.nodes.length !== stackNodesBeforeSetup ) { // !! no outputNode !! - //properties.outputNode = builder.stack; + //outputNode = builder.stack; - } + }*/ for ( const childNode of Object.values( properties ) ) { @@ -631,6 +634,14 @@ class Node extends EventDispatcher { } + if ( isNodeOutput ) { + + outputNode.build( builder ); + + } + + properties.outputNode = outputNode; + } } else if ( buildStage === 'analyze' ) { @@ -680,7 +691,7 @@ class Node extends EventDispatcher { /** * Returns the child nodes as a JSON object. * - * @return {Object} The serialized child objects as JSON. + * @return {Array} An iterable list of serialized child objects as JSON. */ getSerializeChildren() { diff --git a/src/nodes/core/NodeBuilder.js b/src/nodes/core/NodeBuilder.js index d371dded2620c7..52bd9766b805ab 100644 --- a/src/nodes/core/NodeBuilder.js +++ b/src/nodes/core/NodeBuilder.js @@ -497,6 +497,15 @@ class NodeBuilder { } + /** + * Returns the output struct name which is required by + * {@link module:OutputStructNode}. + * + * @abstract + * @return {String} The name of the output struct. + */ + getOutputStructName() {} + /** * Returns a bind group for the given group name and binding. * @@ -678,6 +687,7 @@ class NodeBuilder { /** * It is used to add Nodes that will be used as FRAME and RENDER events, * and need to follow a certain sequence in the calls to work correctly. + * This function should be called after 'setup()' in the 'build()' process to ensure that the child nodes are processed first. * * @param {Node} node - The node to add. */ @@ -1033,10 +1043,11 @@ class NodeBuilder { * @param {Texture} texture - The texture. * @param {String} textureProperty - The texture property name. * @param {String} uvSnippet - Snippet defining the texture coordinates. + * @param {String?} depthSnippet - Snippet defining the 0-based texture array index to sample. * @param {String} levelSnippet - Snippet defining the mip level. * @return {String} The generated shader string. */ - generateTextureLod( /* texture, textureProperty, uvSnippet, levelSnippet */ ) { + generateTextureLod( /* texture, textureProperty, uvSnippet, depthSnippet, levelSnippet */ ) { console.warn( 'Abstract function.' ); @@ -1210,11 +1221,11 @@ class NodeBuilder { } /** - * Whether the given texture needs a conversion to working color space. + * Checks if the given texture requires a manual conversion to the working color space. * * @abstract * @param {Texture} texture - The texture to check. - * @return {Boolean} Whether a color space conversion is required or not. + * @return {Boolean} Whether the given texture requires a conversion to working color space or not. */ needsToWorkingColorSpace( /*texture*/ ) { @@ -1593,9 +1604,11 @@ class NodeBuilder { * @param {String?} name - The variable's name. * @param {String} [type=node.getNodeType( this )] - The variable's type. * @param {('vertex'|'fragment'|'compute'|'any')} [shaderStage=this.shaderStage] - The shader stage. + * @param {Boolean} [readOnly=false] - Whether the variable is read-only or not. + * * @return {NodeVar} The node variable. */ - getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage ) { + getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage, readOnly = false ) { const nodeData = this.getDataFromNode( node, shaderStage ); @@ -1603,13 +1616,26 @@ class NodeBuilder { if ( nodeVar === undefined ) { + const idNS = readOnly ? '_const' : '_var'; + const vars = this.vars[ shaderStage ] || ( this.vars[ shaderStage ] = [] ); + const id = this.vars[ idNS ] || ( this.vars[ idNS ] = 0 ); - if ( name === null ) name = 'nodeVar' + vars.length; + if ( name === null ) { - nodeVar = new NodeVar( name, type ); + name = ( readOnly ? 'nodeConst' : 'nodeVar' ) + id; - vars.push( nodeVar ); + this.vars[ idNS ] ++; + + } + + nodeVar = new NodeVar( name, type, readOnly ); + + if ( ! readOnly ) { + + vars.push( nodeVar ); + + } nodeData.variable = nodeVar; @@ -1619,6 +1645,35 @@ class NodeBuilder { } + /** + * Returns whether a Node or its flow is deterministic, useful for use in `const`. + * + * @param {Node} node - The varying node. + * @return {Boolean} Returns true if deterministic. + */ + isDeterministic( node ) { + + if ( node.isMathNode ) { + + return this.isDeterministic( node.aNode ) && + ( node.bNode ? this.isDeterministic( node.bNode ) : true ) && + ( node.cNode ? this.isDeterministic( node.cNode ) : true ); + + } else if ( node.isOperatorNode ) { + + return this.isDeterministic( node.aNode ) && + ( node.bNode ? this.isDeterministic( node.bNode ) : true ); + + } else if ( node.isConstNode ) { + + return true; + + } + + return false; + + } + /** * Returns an instance of {@link NodeVarying} for the given varying node. * @@ -2414,6 +2469,13 @@ class NodeBuilder { // deprecated + /** + * @function + * @deprecated since r168. Use `new NodeMaterial()` instead, with targeted node material name. + * + * @param {String} [type='NodeMaterial'] - The node material type. + * @throws {Error} + */ createNodeMaterial( type = 'NodeMaterial' ) { // @deprecated, r168 throw new Error( `THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${ type }() instead.` ); diff --git a/src/nodes/core/NodeUtils.js b/src/nodes/core/NodeUtils.js index a4f0f813ac0cf7..cc055bbb2750ec 100644 --- a/src/nodes/core/NodeUtils.js +++ b/src/nodes/core/NodeUtils.js @@ -95,7 +95,7 @@ export function getCacheKey( object, force = false ) { for ( const { property, childNode } of getNodeChildren( object ) ) { - values.push( values, cyrb53( property.slice( 0, - 4 ) ), childNode.getCacheKey( force ) ); + values.push( cyrb53( property.slice( 0, - 4 ) ), childNode.getCacheKey( force ) ); } @@ -168,6 +168,8 @@ const typeFromLength = /*@__PURE__*/ new Map( [ [ 16, 'mat4' ] ] ); +const dataFromObject = /*@__PURE__*/ new WeakMap(); + /** * Returns the data type for the given the length. * @@ -181,6 +183,39 @@ export function getTypeFromLength( length ) { } +/** + * Returns the typed array for the given data type. + * + * @method + * @param {String} type - The data type. + * @return {TypedArray} The typed array. + */ +export function getTypedArrayFromType( type ) { + + // Handle component type for vectors and matrices + if ( /[iu]?vec\d/.test( type ) ) { + + // Handle int vectors + if ( type.startsWith( 'ivec' ) ) return Int32Array; + // Handle uint vectors + if ( type.startsWith( 'uvec' ) ) return Uint32Array; + // Default to float vectors + return Float32Array; + + } + + // Handle matrices (always float) + if ( /mat\d/.test( type ) ) return Float32Array; + + // Basic types + if ( /float/.test( type ) ) return Float32Array; + if ( /uint/.test( type ) ) return Uint32Array; + if ( /int/.test( type ) ) return Int32Array; + + throw new Error( `THREE.NodeUtils: Unsupported type: ${type}` ); + +} + /** * Returns the length for the given data type. * @@ -334,6 +369,27 @@ export function getValueFromType( type, ...params ) { } +/** + * Gets the object data that can be shared between different rendering steps. + * + * @param {Object} object - The object to get the data for. + * @return {Object} The object data. + */ +export function getDataFromObject( object ) { + + let data = dataFromObject.get( object ); + + if ( data === undefined ) { + + data = {}; + dataFromObject.set( object, data ); + + } + + return data; + +} + /** * Converts the given array buffer to a Base64 string. * diff --git a/src/nodes/core/NodeVar.js b/src/nodes/core/NodeVar.js index 7a180f8c3b649e..b95a18db7173d8 100644 --- a/src/nodes/core/NodeVar.js +++ b/src/nodes/core/NodeVar.js @@ -11,8 +11,9 @@ class NodeVar { * * @param {String} name - The name of the variable. * @param {String} type - The type of the variable. + * @param {Boolean} [readOnly=false] - The read-only flag. */ - constructor( name, type ) { + constructor( name, type, readOnly = false ) { /** * This flag can be used for type testing. @@ -37,6 +38,13 @@ class NodeVar { */ this.type = type; + /** + * The read-only flag. + * + * @type {boolean} + */ + this.readOnly = readOnly; + } } diff --git a/src/nodes/core/OutputStructNode.js b/src/nodes/core/OutputStructNode.js index 95f4a8f7b02a52..30c7495293d341 100644 --- a/src/nodes/core/OutputStructNode.js +++ b/src/nodes/core/OutputStructNode.js @@ -85,7 +85,7 @@ class OutputStructNode extends Node { export default OutputStructNode; /** - * TSL function for creating an output struct node with the given parameters. + * TSL function for creating an output struct node. * * @function * @param {...Node} members - A parameter list of nodes. diff --git a/src/nodes/core/ParameterNode.js b/src/nodes/core/ParameterNode.js index 338a0e3bba208c..9adf28a47117f8 100644 --- a/src/nodes/core/ParameterNode.js +++ b/src/nodes/core/ParameterNode.js @@ -54,7 +54,7 @@ class ParameterNode extends PropertyNode { export default ParameterNode; /** - * TSL function for creating a parameter node with the given paramters. + * TSL function for creating a parameter node. * * @function * @param {String} type - The type of the node. diff --git a/src/nodes/core/PropertyNode.js b/src/nodes/core/PropertyNode.js index 681173b1d3346e..df58c8f8bf959b 100644 --- a/src/nodes/core/PropertyNode.js +++ b/src/nodes/core/PropertyNode.js @@ -1,8 +1,10 @@ import Node from './Node.js'; import { nodeImmutable, nodeObject } from '../tsl/TSLCore.js'; +/** @module PropertyNode **/ + /** - * This class represents a shader property. It can be used on + * This class represents a shader property. It can be used * to explicitly define a property and assign a value to it. * * ```js @@ -101,34 +103,218 @@ class PropertyNode extends Node { export default PropertyNode; +/** + * TSL function for creating a property node. + * + * @function + * @param {String} type - The type of the node. + * @param {String?} [name=null] - The name of the property in the shader. + * @returns {PropertyNode} + */ export const property = ( type, name ) => nodeObject( new PropertyNode( type, name ) ); + +/** + * TSL function for creating a varying property node. + * + * @function + * @param {String} type - The type of the node. + * @param {String?} [name=null] - The name of the varying in the shader. + * @returns {PropertyNode} + */ export const varyingProperty = ( type, name ) => nodeObject( new PropertyNode( type, name, true ) ); +/** + * TSL object that represents the shader variable `DiffuseColor`. + * + * @type {PropertyNode} + */ export const diffuseColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'DiffuseColor' ); + +/** + * TSL object that represents the shader variable `EmissiveColor`. + * + * @type {PropertyNode} + */ export const emissive = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'EmissiveColor' ); + +/** + * TSL object that represents the shader variable `Roughness`. + * + * @type {PropertyNode} + */ export const roughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Roughness' ); + +/** + * TSL object that represents the shader variable `Metalness`. + * + * @type {PropertyNode} + */ export const metalness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Metalness' ); + +/** + * TSL object that represents the shader variable `Clearcoat`. + * + * @type {PropertyNode} + */ export const clearcoat = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Clearcoat' ); + +/** + * TSL object that represents the shader variable `ClearcoatRoughness`. + * + * @type {PropertyNode} + */ export const clearcoatRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'ClearcoatRoughness' ); + +/** + * TSL object that represents the shader variable `Sheen`. + * + * @type {PropertyNode} + */ export const sheen = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'Sheen' ); + +/** + * TSL object that represents the shader variable `SheenRoughness`. + * + * @type {PropertyNode} + */ export const sheenRoughness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SheenRoughness' ); + +/** + * TSL object that represents the shader variable `Iridescence`. + * + * @type {PropertyNode} + */ export const iridescence = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Iridescence' ); + +/** + * TSL object that represents the shader variable `IridescenceIOR`. + * + * @type {PropertyNode} + */ export const iridescenceIOR = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceIOR' ); + +/** + * TSL object that represents the shader variable `IridescenceThickness`. + * + * @type {PropertyNode} + */ export const iridescenceThickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IridescenceThickness' ); + +/** + * TSL object that represents the shader variable `AlphaT`. + * + * @type {PropertyNode} + */ export const alphaT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AlphaT' ); + +/** + * TSL object that represents the shader variable `Anisotropy`. + * + * @type {PropertyNode} + */ export const anisotropy = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Anisotropy' ); + +/** + * TSL object that represents the shader variable `AnisotropyT`. + * + * @type {PropertyNode} + */ export const anisotropyT = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyT' ); + +/** + * TSL object that represents the shader variable `AnisotropyB`. + * + * @type {PropertyNode} + */ export const anisotropyB = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec3', 'AnisotropyB' ); + +/** + * TSL object that represents the shader variable `SpecularColor`. + * + * @type {PropertyNode} + */ export const specularColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'SpecularColor' ); + +/** + * TSL object that represents the shader variable `SpecularF90`. + * + * @type {PropertyNode} + */ export const specularF90 = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'SpecularF90' ); + +/** + * TSL object that represents the shader variable `Shininess`. + * + * @type {PropertyNode} + */ export const shininess = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Shininess' ); + +/** + * TSL object that represents the shader variable `Output`. + * + * @type {PropertyNode} + */ export const output = /*@__PURE__*/ nodeImmutable( PropertyNode, 'vec4', 'Output' ); + +/** + * TSL object that represents the shader variable `dashSize`. + * + * @type {PropertyNode} + */ export const dashSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'dashSize' ); + +/** + * TSL object that represents the shader variable `gapSize`. + * + * @type {PropertyNode} + */ export const gapSize = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'gapSize' ); + +/** + * TSL object that represents the shader variable `pointWidth`. + * + * @type {PropertyNode} + */ export const pointWidth = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'pointWidth' ); + +/** + * TSL object that represents the shader variable `IOR`. + * + * @type {PropertyNode} + */ export const ior = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'IOR' ); + +/** + * TSL object that represents the shader variable `Transmission`. + * + * @type {PropertyNode} + */ export const transmission = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Transmission' ); + +/** + * TSL object that represents the shader variable `Thickness`. + * + * @type {PropertyNode} + */ export const thickness = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Thickness' ); + +/** + * TSL object that represents the shader variable `AttenuationDistance`. + * + * @type {PropertyNode} + */ export const attenuationDistance = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'AttenuationDistance' ); + +/** + * TSL object that represents the shader variable `AttenuationColor`. + * + * @type {PropertyNode} + */ export const attenuationColor = /*@__PURE__*/ nodeImmutable( PropertyNode, 'color', 'AttenuationColor' ); + +/** + * TSL object that represents the shader variable `Dispersion`. + * + * @type {PropertyNode} + */ export const dispersion = /*@__PURE__*/ nodeImmutable( PropertyNode, 'float', 'Dispersion' ); diff --git a/src/nodes/core/StackNode.js b/src/nodes/core/StackNode.js index 59ce71fa00e027..4d725bc4233521 100644 --- a/src/nodes/core/StackNode.js +++ b/src/nodes/core/StackNode.js @@ -157,8 +157,15 @@ class StackNode extends Node { } - // + // deprecated + /** + * @function + * @deprecated since r168. Use {@link StackNode#Else} instead. + * + * @param {...any} params + * @returns {StackNode} + */ else( ...params ) { // @deprecated, r168 console.warn( 'TSL.StackNode: .else() has been renamed to .Else().' ); @@ -166,6 +173,12 @@ class StackNode extends Node { } + /** + * @deprecated since r168. Use {@link StackNode#ElseIf} instead. + * + * @param {...any} params + * @returns {StackNode} + */ elseif( ...params ) { // @deprecated, r168 console.warn( 'TSL.StackNode: .elseif() has been renamed to .ElseIf().' ); @@ -178,7 +191,7 @@ class StackNode extends Node { export default StackNode; /** - * TSL function for creating a stack node with the given parameters. + * TSL function for creating a stack node. * * @function * @param {StackNode?} [parent=null] - The parent stack node. diff --git a/src/nodes/core/UniformNode.js b/src/nodes/core/UniformNode.js index 03491f170f0848..62c023d0827a67 100644 --- a/src/nodes/core/UniformNode.js +++ b/src/nodes/core/UniformNode.js @@ -159,7 +159,7 @@ class UniformNode extends InputNode { export default UniformNode; /** - * TSL function for creating a uniform node with the given paramters. + * TSL function for creating a uniform node. * * @function * @param {Any} arg1 - The value of this node. Usually a JS primitive or three.js object (vector, matrix, color, texture). diff --git a/src/nodes/core/VarNode.js b/src/nodes/core/VarNode.js index 9441703b27c343..bb0f1452e22c0e 100644 --- a/src/nodes/core/VarNode.js +++ b/src/nodes/core/VarNode.js @@ -26,8 +26,9 @@ class VarNode extends Node { * * @param {Node} node - The node for which a variable should be created. * @param {String?} name - The name of the variable in the shader. + * @param {Boolean?} readOnly - The read-only flag. */ - constructor( node, name = null ) { + constructor( node, name = null, readOnly = false ) { super(); @@ -64,6 +65,15 @@ class VarNode extends Node { */ this.isVarNode = true; + /** + * + * The read-only flag. + * + * @type {Boolean} + * @default false + */ + this.readOnly = readOnly; + } getHash( builder ) { @@ -80,15 +90,50 @@ class VarNode extends Node { generate( builder ) { - const { node, name } = this; + const { node, name, readOnly } = this; + const { renderer } = builder; + + const isWebGPUBackend = renderer.backend.isWebGPUBackend === true; + + let isDeterministic = false; + let shouldTreatAsReadOnly = false; + + if ( readOnly ) { + + isDeterministic = builder.isDeterministic( node ); + + shouldTreatAsReadOnly = isWebGPUBackend ? readOnly : isDeterministic; - const nodeVar = builder.getVarFromNode( this, name, builder.getVectorType( this.getNodeType( builder ) ) ); + } + + const vectorType = builder.getVectorType( this.getNodeType( builder ) ); + const snippet = node.build( builder, vectorType ); + + const nodeVar = builder.getVarFromNode( this, name, vectorType, undefined, shouldTreatAsReadOnly ); const propertyName = builder.getPropertyName( nodeVar ); - const snippet = node.build( builder, nodeVar.type ); + let declarationPrefix = propertyName; + + if ( shouldTreatAsReadOnly ) { + + const type = builder.getType( nodeVar.type ); + + if ( isWebGPUBackend ) { + + declarationPrefix = isDeterministic + ? `const ${ propertyName }` + : `let ${ propertyName }`; + + } else { + + declarationPrefix = `const ${ type } ${ propertyName }`; + + } + + } - builder.addLineFlowCode( `${propertyName} = ${snippet}`, this ); + builder.addLineFlowCode( `${ declarationPrefix } = ${ snippet }`, this ); return propertyName; @@ -99,7 +144,7 @@ class VarNode extends Node { export default VarNode; /** - * TSL function for creating a var node with the given paramters. + * TSL function for creating a var node. * * @function * @param {Node} node - The node for which a variable should be created. @@ -108,13 +153,43 @@ export default VarNode; */ const createVar = /*@__PURE__*/ nodeProxy( VarNode ); -addMethodChaining( 'toVar', ( ...params ) => createVar( ...params ).append() ); +/** + * TSL function for creating a var node. + * + * @function + * @param {Node} node - The node for which a variable should be created. + * @param {String?} name - The name of the variable in the shader. + * @returns {VarNode} + */ +export const Var = ( node, name = null ) => createVar( node, name ).append(); + +/** + * TSL function for creating a const node. + * + * @function + * @param {Node} node - The node for which a constant should be created. + * @param {String?} name - The name of the constant in the shader. + * @returns {VarNode} + */ +export const Const = ( node, name = null ) => createVar( node, name, true ).append(); + +// Method chaining + +addMethodChaining( 'toVar', Var ); +addMethodChaining( 'toConst', Const ); // Deprecated +/** + * @function + * @deprecated since r170. Use `Var( node )` or `node.toVar()` instead. + * + * @param {Any} node + * @returns {VarNode} + */ export const temp = ( node ) => { // @deprecated, r170 - console.warn( 'TSL: "temp" is deprecated. Use ".toVar()" instead.' ); + console.warn( 'TSL: "temp( node )" is deprecated. Use "Var( node )" or "node.toVar()" instead.' ); return createVar( node ); diff --git a/src/nodes/core/VaryingNode.js b/src/nodes/core/VaryingNode.js index 8c09a1009408ef..937fc973511416 100644 --- a/src/nodes/core/VaryingNode.js +++ b/src/nodes/core/VaryingNode.js @@ -167,7 +167,7 @@ class VaryingNode extends Node { export default VaryingNode; /** - * TSL function for creating a varying node with the given paramters. + * TSL function for creating a varying node. * * @function * @param {Node} node - The node for which a varying should be created. @@ -176,4 +176,14 @@ export default VaryingNode; */ export const varying = /*@__PURE__*/ nodeProxy( VaryingNode ); +/** + * Computes a node in the vertex stage. + * + * @function + * @param {Node} node - The node which should be executed in the vertex stage. + * @returns {VaryingNode} + */ +export const vertexStage = ( node ) => varying( node ); + addMethodChaining( 'varying', varying ); +addMethodChaining( 'vertexStage', vertexStage ); diff --git a/src/nodes/display/BlendModes.js b/src/nodes/display/BlendModes.js index 29760492e4a218..9ee7f7abfd97c8 100644 --- a/src/nodes/display/BlendModes.js +++ b/src/nodes/display/BlendModes.js @@ -1,6 +1,20 @@ import { Fn, vec4 } from '../tsl/TSLBase.js'; import { mix, min, step } from '../math/MathNode.js'; +/** @module BlendModes **/ + +/** + * Represents a "Color Burn" blend mode. + * + * It's designed to darken the base layer's colors based on the color of the blend layer. + * It significantly increases the contrast of the base layer, making the colors more vibrant and saturated. + * The darker the color in the blend layer, the stronger the darkening and contrast effect on the base layer. + * + * @method + * @param {Node} base - The base color. + * @param {Node} blend - The blend color. A white (#ffffff) blend color does not alter the base color. + * @return {Node} The result. + */ export const blendBurn = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { return min( 1.0, base.oneMinus().div( blend ) ).oneMinus(); @@ -14,6 +28,18 @@ export const blendBurn = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { ] } ); +/** + * Represents a "Color Dodge" blend mode. + * + * It's designed to lighten the base layer's colors based on the color of the blend layer. + * It significantly increases the brightness of the base layer, making the colors lighter and more vibrant. + * The brighter the color in the blend layer, the stronger the lightening and contrast effect on the base layer. + * + * @method + * @param {Node} base - The base color. + * @param {Node} blend - The blend color. A black (#000000) blend color does not alter the base color. + * @return {Node} The result. + */ export const blendDodge = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { return min( base.div( blend.oneMinus() ), 1.0 ); @@ -27,6 +53,18 @@ export const blendDodge = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { ] } ); +/** + * Represents a "Screen" blend mode. + * + * Similar to `blendDodge()`, this mode also lightens the base layer's colors based on the color of the blend layer. + * The "Screen" blend mode is better for general brightening whereas the "Dodge" results in more subtle and nuanced + * effects. + * + * @method + * @param {Node} base - The base color. + * @param {Node} blend - The blend color. A black (#000000) blend color does not alter the base color. + * @return {Node} The result. + */ export const blendScreen = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { return base.oneMinus().mul( blend.oneMinus() ).oneMinus(); @@ -40,6 +78,18 @@ export const blendScreen = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { ] } ); +/** + * Represents a "Overlay" blend mode. + * + * It's designed to increase the contrast of the base layer based on the color of the blend layer. + * It amplifies the existing colors and contrast in the base layer, making lighter areas lighter and darker areas darker. + * The color of the blend layer significantly influences the resulting contrast and color shift in the base layer. + * + * @method + * @param {Node} base - The base color. + * @param {Node} blend - The blend color + * @return {Node} The result. + */ export const blendOverlay = /*@__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 ) ); @@ -53,6 +103,15 @@ export const blendOverlay = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { ] } ); +/** + * This function blends two color based on their alpha values by replicating the behavior of `THREE.NormalBlending`. + * It assumes both input colors have non-preumiltiplied alpha. + * + * @method + * @param {Node} base - The base color. + * @param {Node} blend - The blend color + * @return {Node} The result. + */ export const blendColor = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { const outAlpha = blend.a.add( base.a.mul( blend.a.oneMinus() ) ); @@ -70,6 +129,13 @@ export const blendColor = /*@__PURE__*/ Fn( ( [ base, blend ] ) => { // deprecated +/** + * @function + * @deprecated since r171. Use {@link blendBurn} instead. + * + * @param {...any} params + * @returns {Function} + */ export const burn = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "burn" has been renamed. Use "blendBurn" instead.' ); @@ -77,6 +143,13 @@ export const burn = ( ...params ) => { // @deprecated, r171 }; +/** + * @function + * @deprecated since r171. Use {@link blendDodge} instead. + * + * @param {...any} params + * @returns {Function} + */ export const dodge = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "dodge" has been renamed. Use "blendDodge" instead.' ); @@ -84,6 +157,13 @@ export const dodge = ( ...params ) => { // @deprecated, r171 }; +/** + * @method + * @deprecated since r171. Use {@link blendScreen} instead. + * + * @param {...any} params + * @returns {Function} + */ export const screen = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "screen" has been renamed. Use "blendScreen" instead.' ); @@ -91,6 +171,13 @@ export const screen = ( ...params ) => { // @deprecated, r171 }; +/** + * @method + * @deprecated since r171. Use {@link blendOverlay} instead. + * + * @param {...any} params + * @returns {Function} + */ export const overlay = ( ...params ) => { // @deprecated, r171 console.warn( 'THREE.TSL: "overlay" has been renamed. Use "blendOverlay" instead.' ); diff --git a/src/nodes/display/BumpMapNode.js b/src/nodes/display/BumpMapNode.js index f8ea0511194003..a591463b0aaf95 100644 --- a/src/nodes/display/BumpMapNode.js +++ b/src/nodes/display/BumpMapNode.js @@ -5,6 +5,8 @@ import { positionView } from '../accessors/Position.js'; import { faceDirection } from './FrontFacingNode.js'; import { Fn, nodeProxy, float, vec2 } from '../tsl/TSLBase.js'; +/** @module BumpMapNode **/ + // Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen // https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf @@ -64,8 +66,8 @@ class BumpMapNode extends TempNode { /** * Constructs a new bump map node. * - * @param {Node} textureNode - Represents the bump map data. - * @param {Node?} [scaleNode=null] - Controls the intensity of the bump effect. + * @param {Node} textureNode - Represents the bump map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the bump effect. */ constructor( textureNode, scaleNode = null ) { @@ -74,14 +76,14 @@ class BumpMapNode extends TempNode { /** * Represents the bump map data. * - * @type {Node} + * @type {Node} */ this.textureNode = textureNode; /** * Controls the intensity of the bump effect. * - * @type {Node?} + * @type {Node?} * @default null */ this.scaleNode = scaleNode; @@ -105,4 +107,12 @@ class BumpMapNode extends TempNode { export default BumpMapNode; +/** + * TSL function for creating a bump map node. + * + * @function + * @param {Node} textureNode - Represents the bump map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the bump effect. + * @returns {BumpMapNode} + */ export const bumpMap = /*@__PURE__*/ nodeProxy( BumpMapNode ); diff --git a/src/nodes/display/ColorSpaceNode.js b/src/nodes/display/ColorSpaceNode.js index e087593c652a4b..405ca8a5904001 100644 --- a/src/nodes/display/ColorSpaceNode.js +++ b/src/nodes/display/ColorSpaceNode.js @@ -46,14 +46,14 @@ class ColorSpaceNode extends TempNode { /** * The source color space. * - * @type {Node} + * @type {String} */ this.source = source; /** * The target color space. * - * @type {Node} + * @type {String} */ this.target = target; diff --git a/src/nodes/display/NormalMapNode.js b/src/nodes/display/NormalMapNode.js index 97e17e2d42d2ac..5d5b9c70a7d4a6 100644 --- a/src/nodes/display/NormalMapNode.js +++ b/src/nodes/display/NormalMapNode.js @@ -59,8 +59,8 @@ class NormalMapNode extends TempNode { /** * Constructs a new normal map node. * - * @param {Node} node - Represents the normal map data. - * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. + * @param {Node} node - Represents the normal map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. */ constructor( node, scaleNode = null ) { @@ -69,14 +69,14 @@ class NormalMapNode extends TempNode { /** * Represents the normal map data. * - * @type {Node} + * @type {Node} */ this.node = node; /** * Controls the intensity of the effect. * - * @type {Node?} + * @type {Node?} * @default null */ this.scaleNode = scaleNode; @@ -139,11 +139,11 @@ class NormalMapNode extends TempNode { export default NormalMapNode; /** - * TSL function for creating a normal map node with the given paramters. + * TSL function for creating a normal map node. * * @function - * @param {Node} node - Represents the normal map data. - * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. + * @param {Node} node - Represents the normal map data. + * @param {Node?} [scaleNode=null] - Controls the intensity of the effect. * @returns {NormalMapNode} */ export const normalMap = /*@__PURE__*/ nodeProxy( NormalMapNode ); diff --git a/src/nodes/display/PassNode.js b/src/nodes/display/PassNode.js index db8b05377ed3fb..45ddea6e6db243 100644 --- a/src/nodes/display/PassNode.js +++ b/src/nodes/display/PassNode.js @@ -17,7 +17,7 @@ const _size = /*@__PURE__*/ new Vector2(); /** * Represents the texture of a pass node. * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class PassTextureNode extends TextureNode { @@ -68,7 +68,7 @@ class PassTextureNode extends TextureNode { * An extension of `PassTextureNode` which allows to manage more than one * internal texture. Relevant for the `getPreviousTexture()` related API. * - * @augments PassTextureNode + * @augments module:PassTextureNode~PassTextureNode */ class PassMultipleTextureNode extends PassTextureNode { @@ -186,7 +186,7 @@ class PassNode extends TempNode { /** * A reference to the camera. * - * @type {camera} + * @type {Camera} */ this.camera = camera; @@ -242,7 +242,7 @@ class PassNode extends TempNode { * A dictionary holding the internal result textures. * * @private - * @type {Object} + * @type {Object} */ this._textures = { output: renderTarget.texture, @@ -253,7 +253,7 @@ class PassNode extends TempNode { * A dictionary holding the internal texture nodes. * * @private - * @type {Object} + * @type {Object} */ this._textureNodes = {}; @@ -278,7 +278,7 @@ class PassNode extends TempNode { * Used for computing velocity/motion vectors. * * @private - * @type {Object} + * @type {Object} */ this._previousTextures = {}; @@ -287,7 +287,7 @@ class PassNode extends TempNode { * Used for computing velocity/motion vectors. * * @private - * @type {Object} + * @type {Object} */ this._previousTextureNodes = {}; @@ -639,7 +639,7 @@ PassNode.DEPTH = 'depth'; export default PassNode; /** - * TSL function for creating a pass node with the given paramters. + * TSL function for creating a pass node. * * @function * @param {Scene} scene - A reference to the scene. @@ -650,7 +650,7 @@ export default PassNode; export const pass = ( scene, camera, options ) => nodeObject( new PassNode( PassNode.COLOR, scene, camera, options ) ); /** - * TSL function for creating a pass texture node with the given paramters. + * TSL function for creating a pass texture node. * * @function * @param {PassNode} pass - The pass node. @@ -660,7 +660,7 @@ export const pass = ( scene, camera, options ) => nodeObject( new PassNode( Pass export const passTexture = ( pass, texture ) => nodeObject( new PassTextureNode( pass, texture ) ); /** - * TSL function for creating a depth pass node with the given paramters. + * TSL function for creating a depth pass node. * * @function * @param {Scene} scene - A reference to the scene. diff --git a/src/nodes/display/PosterizeNode.js b/src/nodes/display/PosterizeNode.js index 930f07a928b4e6..f7b27efba983c7 100644 --- a/src/nodes/display/PosterizeNode.js +++ b/src/nodes/display/PosterizeNode.js @@ -56,7 +56,7 @@ class PosterizeNode extends TempNode { export default PosterizeNode; /** - * TSL function for creating a posterize node with the given paramters. + * TSL function for creating a posterize node. * * @function * @param {Node} sourceNode - The input color. diff --git a/src/nodes/display/RenderOutputNode.js b/src/nodes/display/RenderOutputNode.js index bd22935409f1ec..8bafcad48c8193 100644 --- a/src/nodes/display/RenderOutputNode.js +++ b/src/nodes/display/RenderOutputNode.js @@ -41,7 +41,7 @@ class RenderOutputNode extends TempNode { * Constructs a new render output node. * * @param {Node} colorNode - The color node to process. - * @param {String} toneMapping - The tone mapping type. + * @param {Number} toneMapping - The tone mapping type. * @param {String} outputColorSpace - The output color space. */ constructor( colorNode, toneMapping, outputColorSpace ) { @@ -112,11 +112,11 @@ class RenderOutputNode extends TempNode { export default RenderOutputNode; /** - * TSL function for creating a posterize node with the given paramters. + * TSL function for creating a posterize node. * * @function * @param {Node} color - The color node to process. - * @param {String?} [toneMapping=null] - The tone mapping type. + * @param {Number?} [toneMapping=null] - The tone mapping type. * @param {String?} [outputColorSpace=null] - The output color space. * @returns {RenderOutputNode} */ diff --git a/src/nodes/display/ScreenNode.js b/src/nodes/display/ScreenNode.js index e86b5f7cd8783b..7e6950b0114055 100644 --- a/src/nodes/display/ScreenNode.js +++ b/src/nodes/display/ScreenNode.js @@ -6,11 +6,13 @@ import { Fn, nodeImmutable, vec2 } from '../tsl/TSLBase.js'; import { Vector2 } from '../../math/Vector2.js'; import { Vector4 } from '../../math/Vector4.js'; +/** @module ScreenNode **/ + let screenSizeVec, viewportVec; /** * This node provides a collection of screen related metrics. - * Depending on {@link ScreenNode#scope}, the nodes can represent + * Depending on {@link module:ScreenNode~ScreenNode#scope}, the nodes can represent * resolution or viewport data as well as fragment or uv coordinates. * * @augments Node @@ -38,7 +40,7 @@ class ScreenNode extends Node { * - `ScreenNode.COORDINATE`: Window-relative coordinates of the current fragment according to WebGPU standards. * - `ScreenNode.VIEWPORT`: The current viewport defined as a four-dimensional vector. * - `ScreenNode.SIZE`: The dimensions of the current bound framebuffer. - * - `ScreenNode.UV`: Normalized screen coordinates. + * - `ScreenNode.UV`: Normalized coordinates. * * @type {('coordinate'|'viewport'|'size'|'uv')} */ @@ -188,19 +190,62 @@ export default ScreenNode; // Screen +/** + * TSL object that represents normalized screen coordinates, unitless in `[0, 1]`. + * + * @type {ScreenNode} + */ export const screenUV = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.UV ); + +/** + * TSL object that represents the screen resolution in physical pixel units. + * + * @type {ScreenNode} + */ export const screenSize = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.SIZE ); + +/** + * TSL object that represents the current `x`/`y` pixel position on the screen in physical pixel units. + * + * @type {ScreenNode} + */ export const screenCoordinate = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.COORDINATE ); // Viewport +/** + * TSL object that represents the viewport rectangle as `x`, `y`, `width` and `height` in physical pixel units. + * + * @type {ScreenNode} + */ export const viewport = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.VIEWPORT ); + +/** + * TSL object that represents the viewport resolution in physical pixel units. + * + * @type {ScreenNode} + */ export const viewportSize = viewport.zw; + +/** + * TSL object that represents the current `x`/`y` pixel position on the viewport in physical pixel units. + * + * @type {ScreenNode} + */ export const viewportCoordinate = /*@__PURE__*/ screenCoordinate.sub( viewport.xy ); + +/** + * TSL object that represents normalized viewport coordinates, unitless in `[0, 1]`. + * + * @type {ScreenNode} + */ export const viewportUV = /*@__PURE__*/ viewportCoordinate.div( viewportSize ); // Deprecated +/** + * @deprecated since r169. Use {@link screenSize} instead. + */ export const viewportResolution = /*@__PURE__*/ ( Fn( () => { // @deprecated, r169 console.warn( 'TSL.ViewportNode: "viewportResolution" is deprecated. Use "screenSize" instead.' ); @@ -209,6 +254,9 @@ export const viewportResolution = /*@__PURE__*/ ( Fn( () => { // @deprecated, r1 }, 'vec2' ).once() )(); +/** + * @deprecated since r168. Use {@link screenUV} instead. + */ export const viewportTopLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 console.warn( 'TSL.ViewportNode: "viewportTopLeft" is deprecated. Use "screenUV" instead.' ); @@ -217,6 +265,9 @@ export const viewportTopLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 }, 'vec2' ).once() )(); +/** + * @deprecated since r168. Use `screenUV.flipY()` instead. + */ export const viewportBottomLeft = /*@__PURE__*/ ( Fn( () => { // @deprecated, r168 console.warn( 'TSL.ViewportNode: "viewportBottomLeft" is deprecated. Use "screenUV.flipY()" instead.' ); diff --git a/src/nodes/display/ToneMappingNode.js b/src/nodes/display/ToneMappingNode.js index f0298cb36a0efd..90866fb4805455 100644 --- a/src/nodes/display/ToneMappingNode.js +++ b/src/nodes/display/ToneMappingNode.js @@ -5,6 +5,8 @@ import { rendererReference } from '../accessors/RendererReferenceNode.js'; import { NoToneMapping } from '../../constants.js'; import { hash } from '../core/NodeUtils.js'; +/** @module ToneMappingNode **/ + /** * This node represents a tone mapping operation. * @@ -47,7 +49,7 @@ class ToneMappingNode extends TempNode { /** * Represents the color to process. * - * @type {Node} + * @type {Node?} * @default null */ this.colorNode = colorNode; @@ -97,7 +99,22 @@ class ToneMappingNode extends TempNode { export default ToneMappingNode; +/** + * TSL function for creating a tone mapping node. + * + * @function + * @param {Number} mapping - The tone mapping type. + * @param {Node | Number} exposure - The tone mapping exposure. + * @param {Node | Color} color - The color node to process. + * @returns {ToneMappingNode} + */ export const toneMapping = ( mapping, exposure, color ) => nodeObject( new ToneMappingNode( mapping, nodeObject( exposure ), nodeObject( color ) ) ); + +/** + * TSL object that represents the global tone mapping exposure of the renderer. + * + * @type {RendererReferenceNode} + */ export const toneMappingExposure = /*@__PURE__*/ rendererReference( 'toneMappingExposure', 'float' ); addMethodChaining( 'toneMapping', ( color, mapping, exposure ) => toneMapping( mapping, exposure, color ) ); diff --git a/src/nodes/display/ToonOutlinePassNode.js b/src/nodes/display/ToonOutlinePassNode.js index 243208d36f7383..15b98020d6406e 100644 --- a/src/nodes/display/ToonOutlinePassNode.js +++ b/src/nodes/display/ToonOutlinePassNode.js @@ -8,6 +8,8 @@ import { normalLocal } from '../../nodes/accessors/Normal.js'; import { BackSide } from '../../constants.js'; import PassNode from './PassNode.js'; +/** @module ToonOutlinePassNode **/ + /** * Represents a render pass for producing a toon outline effect on compatible objects. * Only 3D objects with materials of type `MeshToonMaterial` and `MeshToonNodeMaterial` @@ -168,4 +170,15 @@ class ToonOutlinePassNode extends PassNode { export default ToonOutlinePassNode; +/** + * TSL function for creating a toon outline pass node. + * + * @function + * @param {Scene} scene - A reference to the scene. + * @param {Camera} camera - A reference to the camera. + * @param {Color} color - Defines the outline's color. + * @param {Number} [thickness=0.003] - Defines the outline's thickness. + * @param {Number} [alpha=1] - Defines the outline's alpha. + * @returns {ToonOutlinePassNode} + */ export 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 ) ) ); diff --git a/src/nodes/display/ViewportDepthNode.js b/src/nodes/display/ViewportDepthNode.js index b9256656299856..0c340867f1b5da 100644 --- a/src/nodes/display/ViewportDepthNode.js +++ b/src/nodes/display/ViewportDepthNode.js @@ -4,6 +4,8 @@ import { cameraNear, cameraFar } from '../accessors/Camera.js'; import { positionView } from '../accessors/Position.js'; import { viewportDepthTexture } from './ViewportDepthTextureNode.js'; +/** @module ViewportDepthNode **/ + /** * This node offers a collection of features in context of the depth logic in the fragment shader. * Depending on {@link ViewportDepthNode#scope}, it can be used to define a depth value for the current @@ -45,7 +47,7 @@ class ViewportDepthNode extends Node { * Can be used to define a custom depth value. * The property is ignored in the `ViewportDepthNode.DEPTH` scope. * - * @type {Node} + * @type {Node?} * @default null */ this.valueNode = valueNode; @@ -140,21 +142,61 @@ export default ViewportDepthNode; // 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 +/** + * TSL function for converting a viewZ value to an orthographic depth value. + * + * @function + * @param {Node} viewZ - The viewZ node. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ export const viewZToOrthographicDepth = ( viewZ, near, far ) => viewZ.add( near ).div( near.sub( far ) ); -// maps orthographic depth in [ 0, 1 ] to viewZ +/** + * TSL function for converting an orthographic depth value to a viewZ value. + * + * @function + * @param {Node} depth - The orthographic depth. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ export 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 +/** + * TSL function for converting a viewZ value to a perspective depth value. + * + * Note: {link https://twitter.com/gonnavis/status/1377183786949959682}. + * + * @function + * @param {Node} viewZ - The viewZ node. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ export const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( far.sub( near ).mul( viewZ ) ); -// maps perspective depth in [ 0, 1 ] to viewZ +/** + * TSL function for converting a perspective depth value to a viewZ value. + * + * @function + * @param {Node} depth - The perspective depth. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ export const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) ); -// -near maps to 0; -far maps to 1 +/** + * TSL function for converting a viewZ value to a logarithmic depth value. + * + * @function + * @param {Node} viewZ - The viewZ node. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ export const viewZToLogarithmicDepth = ( viewZ, near, far ) => { // NOTE: viewZ must be negative--see explanation at the end of this comment block. @@ -190,7 +232,15 @@ export const viewZToLogarithmicDepth = ( viewZ, near, far ) => { }; -// maps logarithmic depth in [ 0, 1 ] to viewZ +/** + * TSL function for converting a logarithmic depth value to a viewZ value. + * + * @function + * @param {Node} depth - The logarithmic depth. + * @param {Node} near - The camera's near value. + * @param {Node} far - The camera's far value. + * @returns {Node} + */ export const logarithmicDepthToViewZ = ( depth, near, far ) => { // NOTE: we add a 'negate()' call to the return value here to maintain consistency with @@ -201,10 +251,36 @@ export const logarithmicDepthToViewZ = ( depth, near, far ) => { }; +/** + * TSL function for defining a value for the current fragment's depth. + * + * @function + * @param {Node} value - The depth value to set. + * @returns {ViewportDepthNode} + */ const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE ); +/** + * TSL object that represents the depth value for the current fragment. + * + * @type {ViewportDepthNode} + */ export const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH ); + +/** + * TSL function for converting a perspective depth value to linear depth. + * + * @function + * @param {Node} value - The perspective depth. + * @returns {ViewportDepthNode} + */ export const linearDepth = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.LINEAR_DEPTH ); + +/** + * TSL object that represents the linear (orthographic) depth value of the current fragment + * + * @type {ViewportDepthNode} + */ export const viewportLinearDepth = /*@__PURE__*/ linearDepth( viewportDepthTexture() ); depth.assign = ( value ) => depthBase( value ); diff --git a/src/nodes/display/ViewportDepthTextureNode.js b/src/nodes/display/ViewportDepthTextureNode.js index ca3b0d0a596c70..f04b49d26765ff 100644 --- a/src/nodes/display/ViewportDepthTextureNode.js +++ b/src/nodes/display/ViewportDepthTextureNode.js @@ -4,6 +4,8 @@ import { screenUV } from './ScreenNode.js'; import { DepthTexture } from '../../textures/DepthTexture.js'; +/** @module ViewportDepthTextureNode **/ + let sharedDepthbuffer = null; /** @@ -11,7 +13,7 @@ let sharedDepthbuffer = null; * can be used in combination with viewport texture to achieve effects * that require depth evaluation. * - * @augments ViewportTextureNode + * @augments module:ViewportTextureNode~ViewportTextureNode */ class ViewportDepthTextureNode extends ViewportTextureNode { @@ -22,7 +24,7 @@ class ViewportDepthTextureNode extends ViewportTextureNode { } /** - * Constructs a new viewport shared texture node. + * Constructs a new viewport depth texture node. * * @param {Node} [uvNode=screenUV] - The uv node. * @param {Node?} [levelNode=null] - The level node. @@ -43,4 +45,12 @@ class ViewportDepthTextureNode extends ViewportTextureNode { export default ViewportDepthTextureNode; +/** + * TSL function for a viewport depth texture node. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @returns {ViewportDepthTextureNode} + */ export const viewportDepthTexture = /*@__PURE__*/ nodeProxy( ViewportDepthTextureNode ); diff --git a/src/nodes/display/ViewportSharedTextureNode.js b/src/nodes/display/ViewportSharedTextureNode.js index 880e6f30567663..9a176f489d60ef 100644 --- a/src/nodes/display/ViewportSharedTextureNode.js +++ b/src/nodes/display/ViewportSharedTextureNode.js @@ -4,6 +4,8 @@ import { screenUV } from './ScreenNode.js'; import { FramebufferTexture } from '../../textures/FramebufferTexture.js'; +/** @module ViewportSharedTextureNode **/ + let _sharedFramebuffer = null; /** @@ -11,7 +13,7 @@ let _sharedFramebuffer = null; * shares a texture across all instances of `ViewportSharedTextureNode`. It should * be the first choice when using data of the default/screen framebuffer for performance reasons. * - * @augments ViewportTextureNode + * @augments module:ViewportTextureNode~ViewportTextureNode */ class ViewportSharedTextureNode extends ViewportTextureNode { @@ -49,4 +51,12 @@ class ViewportSharedTextureNode extends ViewportTextureNode { export default ViewportSharedTextureNode; +/** + * TSL function for creating a shared viewport texture node. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @returns {ViewportSharedTextureNode} + */ export const viewportSharedTexture = /*@__PURE__*/ nodeProxy( ViewportSharedTextureNode ); diff --git a/src/nodes/display/ViewportTextureNode.js b/src/nodes/display/ViewportTextureNode.js index 26fbd6bb99e391..b9d2edc12ae487 100644 --- a/src/nodes/display/ViewportTextureNode.js +++ b/src/nodes/display/ViewportTextureNode.js @@ -7,6 +7,8 @@ import { Vector2 } from '../../math/Vector2.js'; import { FramebufferTexture } from '../../textures/FramebufferTexture.js'; import { LinearMipmapLinearFilter } from '../../constants.js'; +/** @module ViewportTextureNode **/ + const _size = /*@__PURE__*/ new Vector2(); /** @@ -16,7 +18,7 @@ const _size = /*@__PURE__*/ new Vector2(); * (which is good for performance). `ViewportTextureNode` can be used as an input for a * variety of effects like refractive or transmissive materials. * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class ViewportTextureNode extends TextureNode { @@ -113,5 +115,24 @@ class ViewportTextureNode extends TextureNode { export default ViewportTextureNode; +/** + * TSL function for creating a viewport texture node. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Texture?} [framebufferTexture=null] - A framebuffer texture holding the viewport data. If not provided, a framebuffer texture is created automatically. + * @returns {ViewportTextureNode} + */ export const viewportTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode ); + +/** + * TSL function for creating a viewport texture node with enabled mipmap generation. + * + * @function + * @param {Node} [uvNode=screenUV] - The uv node. + * @param {Node?} [levelNode=null] - The level node. + * @param {Texture?} [framebufferTexture=null] - A framebuffer texture holding the viewport data. If not provided, a framebuffer texture is created automatically. + * @returns {ViewportTextureNode} + */ export const viewportMipTexture = /*@__PURE__*/ nodeProxy( ViewportTextureNode, null, null, { generateMipmaps: true } ); diff --git a/src/nodes/fog/Fog.js b/src/nodes/fog/Fog.js index 3cd015cdbce9d2..c729d5b561f3b6 100644 --- a/src/nodes/fog/Fog.js +++ b/src/nodes/fog/Fog.js @@ -1,6 +1,6 @@ import { positionView } from '../accessors/Position.js'; import { smoothstep } from '../math/MathNode.js'; -import { Fn, vec4 } from '../tsl/TSLBase.js'; +import { Fn, output, vec4 } from '../tsl/TSLBase.js'; /** @module Fog **/ @@ -34,6 +34,7 @@ function getViewZNode( builder ) { /** * Constructs a new range factor node. * + * @function * @param {Node} near - Defines the near value. * @param {Node} far - Defines the far value. */ @@ -50,6 +51,7 @@ export const rangeFogFactor = Fn( ( [ near, far ], builder ) => { * a clear view near the camera and a faster than exponentially * densening fog farther from the camera. * + * @function * @param {Node} density - Defines the fog density. */ export const densityFogFactor = Fn( ( [ density ], builder ) => { @@ -64,17 +66,27 @@ export const densityFogFactor = Fn( ( [ density ], builder ) => { * This class can be used to configure a fog for the scene. * Nodes of this type are assigned to `Scene.fogNode`. * + * @function * @param {Node} color - Defines the color of the fog. * @param {Node} factor - Defines how the fog is factored in the scene. */ export const fog = Fn( ( [ color, factor ] ) => { - return vec4( color.toVec3(), factor.toFloat() ); + return vec4( factor.toFloat().mix( output.rgb, color.toVec3() ), output.a ); } ); // Deprecated +/** + * @function + * @deprecated since r171. Use `fog( color, rangeFogFactor( near, far ) )` instead. + * + * @param {Node} color + * @param {Node} near + * @param {Node} far + * @returns {Function} + */ export function rangeFog( color, near, far ) { // @deprecated, r171 console.warn( 'THREE.TSL: "rangeFog( color, near, far )" is deprecated. Use "fog( color, rangeFogFactor( near, far ) )" instead.' ); @@ -82,6 +94,14 @@ export function rangeFog( color, near, far ) { // @deprecated, r171 } +/** + * @function + * @deprecated since r171. Use `fog( color, densityFogFactor( density ) )` instead. + * + * @param {Node} color + * @param {Node} density + * @returns {Function} + */ export function densityFog( color, density ) { // @deprecated, r171 console.warn( 'THREE.TSL: "densityFog( color, density )" is deprecated. Use "fog( color, densityFogFactor( density ) )" instead.' ); diff --git a/src/nodes/functions/PhongLightingModel.js b/src/nodes/functions/PhongLightingModel.js index 09dcf65d517cf9..b2f978a5f88601 100644 --- a/src/nodes/functions/PhongLightingModel.js +++ b/src/nodes/functions/PhongLightingModel.js @@ -33,7 +33,7 @@ const BRDF_BlinnPhong = /*@__PURE__*/ Fn( ( { lightDirection } ) => { /** * Represents the lighting model for a phong material. Used in {@link MeshPhongNodeMaterial}. * - * @augments LightingModel + * @augments BasicLightingModel */ class PhongLightingModel extends BasicLightingModel { diff --git a/src/nodes/functions/material/getParallaxCorrectNormal.js b/src/nodes/functions/material/getParallaxCorrectNormal.js index e525b00200dc0a..174ebef666404e 100644 --- a/src/nodes/functions/material/getParallaxCorrectNormal.js +++ b/src/nodes/functions/material/getParallaxCorrectNormal.js @@ -1,8 +1,23 @@ import { positionWorld } from '../../accessors/Position.js'; import { float, Fn, min, normalize, sub, vec3 } from '../../tsl/TSLBase.js'; -// https://devlog-martinsh.blogspot.com/2011/09/box-projected-cube-environment-mapping.html +/** @module getParallaxCorrectNormal **/ +/** + * This computes a parallax corrected normal which is used for box-projected cube mapping (BPCEM). + * + * Reference: {@link https://devlog-martinsh.blogspot.com/2011/09/box-projected-cube-environment-mapping.html} + * + * ```js + * const uvNode = getParallaxCorrectNormal( reflectVector, vec3( 200, 100, 100 ), vec3( 0, - 50, 0 ) ); + * material.envNode = pmremTexture( renderTarget.texture, uvNode ); + * ``` + * @function + * @param {Node} normal - The normal to correct. + * @param {Node} cubeSize - The cube size should reflect the size of the environment (BPCEM is usually applied in closed environments like rooms). + * @param {Node} cubePos - The cube position. + * @return {Node} The parallax corrected normal. + */ const getParallaxCorrectNormal = /*@__PURE__*/ Fn( ( [ normal, cubeSize, cubePos ] ) => { const nDir = normalize( normal ).toVar( 'nDir' ); diff --git a/src/nodes/geometry/RangeNode.js b/src/nodes/geometry/RangeNode.js index 61b7e18720f95a..811149d1b06122 100644 --- a/src/nodes/geometry/RangeNode.js +++ b/src/nodes/geometry/RangeNode.js @@ -163,7 +163,7 @@ class RangeNode extends Node { export default RangeNode; /** - * TSL function for creating a range node with the given paramters. + * TSL function for creating a range node. * * @function * @param {Node} [minNode=float()] - A node defining the lower bound of the range. diff --git a/src/nodes/gpgpu/AtomicFunctionNode.js b/src/nodes/gpgpu/AtomicFunctionNode.js index 682b4367d98ed5..ae821021956e1e 100644 --- a/src/nodes/gpgpu/AtomicFunctionNode.js +++ b/src/nodes/gpgpu/AtomicFunctionNode.js @@ -1,6 +1,19 @@ import TempNode from '../core/TempNode.js'; import { nodeProxy } from '../tsl/TSLCore.js'; +/** @module AtomicFunctionNode **/ + +/** + * `AtomicFunctionNode` represents any function that can operate on atomic variable types + * within a shader. In an atomic function, any modification to an atomic variable will + * occur as an indivisible step with a defined order relative to other modifications. + * Accordingly, even if multiple atomic functions are modifying an atomic variable at once + * atomic operations will not interfere with each other. + * + * This node can only be used with a WebGPU backend. + * + * @augments TempNode + */ class AtomicFunctionNode extends TempNode { static get type() { @@ -9,24 +22,68 @@ class AtomicFunctionNode extends TempNode { } + /** + * Constructs a new atomic function node. + * + * @param {String} method - The signature of the atomic function to construct. + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + */ constructor( method, pointerNode, valueNode, storeNode = null ) { super( 'uint' ); + /** + * The signature of the atomic function to construct. + * + * @type {String} + */ this.method = method; + /** + * An atomic variable or element of an atomic buffer. + * + * @type {Node} + */ this.pointerNode = pointerNode; + + /** + * A value that modifies the atomic variable. + * + * @type {Node} + */ this.valueNode = valueNode; + + /** + * A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * + * @type {Node?} + * @default null + */ this.storeNode = storeNode; } + /** + * Overwrites the default implementation to return the type of + * the pointer node. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( builder ) { return this.pointerNode.getNodeType( builder ); } + /** + * Overwritten since the node type is inferred from the input type. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( builder ) { return this.getInputType( builder ); @@ -78,9 +135,29 @@ AtomicFunctionNode.ATOMIC_XOR = 'atomicXor'; export default AtomicFunctionNode; +/** + * TSL function for creating an atomic function node. + * + * @function + * @param {String} method - The signature of the atomic function to construct. + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ const atomicNode = nodeProxy( AtomicFunctionNode ); -export const atomicFunc = ( method, pointerNode, valueNode, storeNode ) => { +/** + * TSL function for appending an atomic function call into the programmatic flow of a compute shader. + * + * @function + * @param {String} method - The signature of the atomic function to construct. + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ +export const atomicFunc = ( method, pointerNode, valueNode, storeNode = null ) => { const node = atomicNode( method, pointerNode, valueNode, storeNode ); node.append(); @@ -89,11 +166,90 @@ export const atomicFunc = ( method, pointerNode, valueNode, storeNode ) => { }; +/** + * Stores a value in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ export const atomicStore = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_STORE, pointerNode, valueNode, storeNode ); + +/** + * Increments the value stored in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ export const atomicAdd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_ADD, pointerNode, valueNode, storeNode ); + +/** + * Decrements the value stored in the atomic variable. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ export const atomicSub = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_SUB, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the maximum between its current value and a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ export const atomicMax = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MAX, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the minimum between its current value and a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ export const atomicMin = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_MIN, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the bitwise AND of its value with a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ export const atomicAnd = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_AND, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the bitwise OR of its value with a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ export const atomicOr = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_OR, pointerNode, valueNode, storeNode ); + +/** + * Stores in an atomic variable the bitwise XOR of its value with a parameter. + * + * @function + * @param {Node} pointerNode - An atomic variable or element of an atomic buffer. + * @param {Node} valueNode - The value that mutates the atomic variable. + * @param {Node?} [storeNode=null] - A variable storing the return value of an atomic operation, typically the value of the atomic variable before the operation. + * @returns {AtomicFunctionNode} + */ export const atomicXor = ( pointerNode, valueNode, storeNode = null ) => atomicFunc( AtomicFunctionNode.ATOMIC_XOR, pointerNode, valueNode, storeNode ); diff --git a/src/nodes/gpgpu/BarrierNode.js b/src/nodes/gpgpu/BarrierNode.js index f613c2656a4b52..639264a508bb4f 100644 --- a/src/nodes/gpgpu/BarrierNode.js +++ b/src/nodes/gpgpu/BarrierNode.js @@ -1,8 +1,22 @@ import Node from '../core/Node.js'; import { nodeProxy } from '../tsl/TSLCore.js'; +/** @module BarrierNode **/ + +/** + * Represents a GPU control barrier that synchronizes compute operations within a given scope. + * + * This node can only be used with a WebGPU backend. + * + * @augments Node + */ class BarrierNode extends Node { + /** + * Constructs a new barrier node. + * + * @param {String} scope - The scope defines the behavior of the node. + */ constructor( scope ) { super(); @@ -32,9 +46,42 @@ class BarrierNode extends Node { export default BarrierNode; +/** + * TSL function for creating a barrier node. + * + * @function + * @param {String} scope - The scope defines the behavior of the node.. + * @returns {BarrierNode} + */ const barrier = nodeProxy( BarrierNode ); +/** + * TSL function for creating a workgroup barrier. All compute shader + * invocations must wait for each invocation within a workgroup to + * complete before the barrier can be surpassed. + * + * @function + * @returns {BarrierNode} + */ export const workgroupBarrier = () => barrier( 'workgroup' ).append(); + +/** + * TSL function for creating a storage barrier. All invocations must + * wait for each access to variables within the 'storage' address space + * to complete before the barrier can be passed. + * + * @function + * @returns {BarrierNode} + */ export const storageBarrier = () => barrier( 'storage' ).append(); + +/** + * TSL function for creating a texture barrier. All invocations must + * wait for each access to variables within the 'texture' address space + * to complete before the barrier can be passed. + * + * @function + * @returns {BarrierNode} + */ export const textureBarrier = () => barrier( 'texture' ).append(); diff --git a/src/nodes/gpgpu/ComputeBuiltinNode.js b/src/nodes/gpgpu/ComputeBuiltinNode.js index bf3213a9d21f47..a52a66879d71a6 100644 --- a/src/nodes/gpgpu/ComputeBuiltinNode.js +++ b/src/nodes/gpgpu/ComputeBuiltinNode.js @@ -1,6 +1,16 @@ import Node from '../core/Node.js'; import { nodeObject } from '../tsl/TSLBase.js'; +/** @module ComputeBuiltinNode **/ + +/** + * `ComputeBuiltinNode` represents a compute-scope builtin value that expose information + * about the currently running dispatch and/or the device it is running on. + * + * This node can only be used with a WebGPU backend. + * + * @augments Node + */ class ComputeBuiltinNode extends Node { static get type() { @@ -9,26 +19,56 @@ class ComputeBuiltinNode extends Node { } + /** + * Constructs a new compute builtin node. + * + * @param {String} builtinName - The built-in name. + * @param {String} nodeType - The node type. + */ constructor( builtinName, nodeType ) { super( nodeType ); + /** + * The built-in name. + * + * @private + * @type {String} + */ this._builtinName = builtinName; } + /** + * This method is overwritten since hash is derived from the built-in name. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The hash. + */ getHash( builder ) { return this.getBuiltinName( builder ); } + /** + * This method is overwritten since the node type is simply derived from `nodeType`.. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The node type. + */ getNodeType( /*builder*/ ) { return this.nodeType; } + /** + * Sets the builtin name. + * + * @param {String} builtinName - The built-in name. + * @return {ComputeBuiltinNode} A reference to this node. + */ setBuiltinName( builtinName ) { this._builtinName = builtinName; @@ -37,12 +77,23 @@ class ComputeBuiltinNode extends Node { } + /** + * Returns the builtin name. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The builtin name. + */ getBuiltinName( /*builder*/ ) { return this._builtinName; } + /** + * Whether the current node builder has the builtin or not. + * + * @param {NodeBuilder} builder - The current node builder. + */ hasBuiltin( builder ) { builder.hasBuiltin( this._builtinName ); @@ -89,10 +140,93 @@ class ComputeBuiltinNode extends Node { export default ComputeBuiltinNode; +/** + * TSL function for creating a compute builtin node. + * + * @function + * @param {String} name - The built-in name. + * @param {String} nodeType - The node type. + * @returns {ComputeBuiltinNode} + */ const computeBuiltin = ( name, nodeType ) => nodeObject( new ComputeBuiltinNode( name, nodeType ) ); +/** + * TSL function for creating a `numWorkgroups` builtin node. + * Represents the number of workgroups dispatched by the compute shader. + * ```js + * // Run 512 invocations/threads with a workgroup size of 128. + * const computeFn = Fn(() => { + * + * // numWorkgroups.x = 4 + * storageBuffer.element(0).assign(numWorkgroups.x) + * + * })().compute(512, [128]); + * + * // Run 512 invocations/threads with the default workgroup size of 64. + * const computeFn = Fn(() => { + * + * // numWorkgroups.x = 8 + * storageBuffer.element(0).assign(numWorkgroups.x) + * + * })().compute(512); + * ``` + * + * @function + * @returns {ComputeBuiltinNode} + */ export const numWorkgroups = /*@__PURE__*/ computeBuiltin( 'numWorkgroups', 'uvec3' ); + +/** + * TSL function for creating a `workgroupId` builtin node. + * Represents the 3-dimensional index of the workgroup the current compute invocation belongs to. + * ```js + * // Execute 12 compute threads with a workgroup size of 3. + * const computeFn = Fn( () => { + * + * If( workgroupId.x.modInt( 2 ).equal( 0 ), () => { + * + * storageBuffer.element( instanceIndex ).assign( instanceIndex ); + * + * } ).Else( () => { + * + * storageBuffer.element( instanceIndex ).assign( 0 ); + * + * } ); + * + * } )().compute( 12, [ 3 ] ); + * + * // workgroupId.x = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]; + * // Buffer Output = [0, 1, 2, 0, 0, 0, 6, 7, 8, 0, 0, 0]; + * ``` + * + * @function + * @returns {ComputeBuiltinNode} + */ export const workgroupId = /*@__PURE__*/ computeBuiltin( 'workgroupId', 'uvec3' ); + +/** + * TSL function for creating a `globalId` builtin node. A non-linearized 3-dimensional + * representation of the current invocation's position within a 3D global grid. + * + * @function + * @returns {ComputeBuiltinNode} + */ +export const globalId = /*@__PURE__*/ computeBuiltin( 'globalId', 'uvec3' ); +/** + * TSL function for creating a `localId` builtin node. A non-linearized 3-dimensional + * representation of the current invocation's position within a 3D workgroup grid. + * + * @function + * @returns {ComputeBuiltinNode} + */ export const localId = /*@__PURE__*/ computeBuiltin( 'localId', 'uvec3' ); + +/** + * TSL function for creating a `subgroupSize` builtin node. A device dependent variable + * that exposes the size of the current invocation's subgroup. + * + * @function + * @returns {ComputeBuiltinNode} + */ export const subgroupSize = /*@__PURE__*/ computeBuiltin( 'subgroupSize', 'uint' ); diff --git a/src/nodes/gpgpu/ComputeNode.js b/src/nodes/gpgpu/ComputeNode.js index 2c1da8ee98ecb6..7ca263a227982a 100644 --- a/src/nodes/gpgpu/ComputeNode.js +++ b/src/nodes/gpgpu/ComputeNode.js @@ -2,6 +2,13 @@ import Node from '../core/Node.js'; import { NodeUpdateType } from '../core/constants.js'; import { addMethodChaining, nodeObject } from '../tsl/TSLCore.js'; +/** @module ComputeNode **/ + +/** + * TODO + * + * @augments Node + */ class ComputeNode extends Node { static get type() { @@ -10,39 +17,116 @@ class ComputeNode extends Node { } + /** + * Constructs a new compute node. + * + * @param {Node} computeNode - TODO + * @param {Number} count - TODO. + * @param {Array} [workgroupSize=[64]] - TODO. + */ constructor( computeNode, count, workgroupSize = [ 64 ] ) { super( 'void' ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isComputeNode = true; + /** + * TODO + * + * @type {Node} + */ this.computeNode = computeNode; + /** + * TODO + * + * @type {Number} + */ this.count = count; + + /** + * TODO + * + * @type {Array} + * @default [64] + */ this.workgroupSize = workgroupSize; + + /** + * TODO + * + * @type {Number} + */ this.dispatchCount = 0; + /** + * TODO + * + * @type {Number} + */ this.version = 1; + + /** + * The name or label of the uniform. + * + * @type {String} + * @default '' + */ + this.name = ''; + + /** + * The `updateBeforeType` is set to `NodeUpdateType.OBJECT` since {@link ComputeNode#updateBefore} + * is executed once per object by default. + * + * @type {String} + * @default 'object' + */ this.updateBeforeType = NodeUpdateType.OBJECT; + /** + * TODO + * + * @type {Function} + */ this.onInitFunction = null; this.updateDispatchCount(); } + /** + * Executes the `dispose` event for this node. + */ dispose() { this.dispatchEvent( { type: 'dispose' } ); } - set needsUpdate( value ) { + /** + * Sets the {@link ComputeNode#name} property. + * + * @param {String} name - The name of the uniform. + * @return {ComputeNode} A reference to this node. + */ + label( name ) { + + this.name = name; - if ( value === true ) this.version ++; + return this; } + /** + * TODO + */ updateDispatchCount() { const { count, workgroupSize } = this; @@ -56,6 +140,12 @@ class ComputeNode extends Node { } + /** + * TODO + * + * @param {Function} callback - TODO. + * @return {ComputeNode} A reference to this node. + */ onInit( callback ) { this.onInitFunction = callback; @@ -64,6 +154,11 @@ class ComputeNode extends Node { } + /** + * The method execute the compute for this node. + * + * @param {NodeFrame} frame - A reference to the current node frame. + */ updateBefore( { renderer } ) { renderer.compute( this ); @@ -92,6 +187,15 @@ class ComputeNode extends Node { export default ComputeNode; +/** + * TSL function for creating a compute node. + * + * @function + * @param {Node} node - TODO + * @param {Number} count - TODO. + * @param {Array} [workgroupSize=[64]] - TODO. + * @returns {AtomicFunctionNode} + */ export const compute = ( node, count, workgroupSize ) => nodeObject( new ComputeNode( nodeObject( node ), count, workgroupSize ) ); addMethodChaining( 'compute', compute ); diff --git a/src/nodes/gpgpu/WorkgroupInfoNode.js b/src/nodes/gpgpu/WorkgroupInfoNode.js index 2bbe3e8eafdb9a..8d1bc9c0191d11 100644 --- a/src/nodes/gpgpu/WorkgroupInfoNode.js +++ b/src/nodes/gpgpu/WorkgroupInfoNode.js @@ -2,12 +2,32 @@ import ArrayElementNode from '../utils/ArrayElementNode.js'; import { nodeObject } from '../tsl/TSLCore.js'; import Node from '../core/Node.js'; +/** @module WorkgroupInfoNode **/ + +/** + * Represents an element of a 'workgroup' scoped buffer. + * + * @augments ArrayElementNode + */ class WorkgroupInfoElementNode extends ArrayElementNode { + /** + * Constructs a new workgroup info element node. + * + * @param {Node} workgroupInfoNode - The workgroup info node. + * @param {Node} indexNode - The index node that defines the element access. + */ constructor( workgroupInfoNode, indexNode ) { super( workgroupInfoNode, indexNode ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWorkgroupInfoElementNode = true; } @@ -35,22 +55,77 @@ class WorkgroupInfoElementNode extends ArrayElementNode { } - +/** + * A node allowing the user to create a 'workgroup' scoped buffer within the + * context of a compute shader. Typically, workgroup scoped buffers are + * created to hold data that is transferred from a global storage scope into + * a local workgroup scope. For invocations within a workgroup, data + * access speeds on 'workgroup' scoped buffers can be significantly faster + * than similar access operations on globally accessible storage buffers. + * + * This node can only be used with a WebGPU backend. + * + * @augments Node + */ class WorkgroupInfoNode extends Node { + /** + * Constructs a new buffer scoped to type scope. + * + * @param {String} scope - TODO. + * @param {String} bufferType - The data type of a 'workgroup' scoped buffer element. + * @param {Number} [bufferCount=0] - The number of elements in the buffer. + */ constructor( scope, bufferType, bufferCount = 0 ) { super( bufferType ); + /** + * The buffer type. + * + * @type {String} + */ this.bufferType = bufferType; + + /** + * The buffer count. + * + * @type {Number} + * @default 0 + */ this.bufferCount = bufferCount; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWorkgroupInfoNode = true; + /** + * The data type of the array buffer. + * + * @type {String} + */ + this.elementType = bufferType; + + /** + * TODO. + * + * @type {String} + */ this.scope = scope; } + /** + * Sets the name/label of this node. + * + * @param {String} name - The name to set. + * @return {WorkgroupInfoNode} A reference to this node. + */ label( name ) { this.name = name; @@ -59,26 +134,51 @@ class WorkgroupInfoNode extends Node { } - getHash() { + /** + * Sets the scope of this node. + * + * @param {String} scope - The scope to set. + * @return {WorkgroupInfoNode} A reference to this node. + */ + setScope( scope ) { + + this.scope = scope; - return this.uuid; + return this; } - setScope( scope ) { - this.scope = scope; + /** + * The data type of the array buffer. + * + * @return {String} The element type. + */ + getElementType() { - return this; + return this.elementType; } + /** + * Overwrites the default implementation since the input type + * is inferred from the scope. + * + * @param {NodeBuilder} builder - The current node builder. + * @return {String} The input type. + */ getInputType( /*builder*/ ) { return `${this.scope}Array`; } + /** + * This method can be used to access elements via an index node. + * + * @param {IndexNode} indexNode - indexNode. + * @return {WorkgroupInfoElementNode} A reference to an element. + */ element( indexNode ) { return nodeObject( new WorkgroupInfoElementNode( this, indexNode ) ); @@ -95,6 +195,15 @@ class WorkgroupInfoNode extends Node { export default WorkgroupInfoNode; +/** + * TSL function for creating a workgroup info node. + * Creates a new 'workgroup' scoped array buffer. + * + * @function + * @param {String} type - The data type of a 'workgroup' scoped buffer element. + * @param {Number} [count=0] - The number of elements in the buffer. + * @returns {WorkgroupInfoNode} + */ export const workgroupArray = ( type, count ) => nodeObject( new WorkgroupInfoNode( 'Workgroup', type, count ) ); diff --git a/src/nodes/lighting/AONode.js b/src/nodes/lighting/AONode.js index 66257ff6f48275..59ddfb4ae08749 100644 --- a/src/nodes/lighting/AONode.js +++ b/src/nodes/lighting/AONode.js @@ -18,7 +18,7 @@ class AONode extends LightingNode { /** * Constructs a new AO node. * - * @param {Node} aoNode - The ambient occlusion node. + * @param {Node?} [aoNode=null] - The ambient occlusion node. */ constructor( aoNode = null ) { @@ -27,7 +27,8 @@ class AONode extends LightingNode { /** * The ambient occlusion node. * - * @type {Node} + * @type {Node?} + * @default null */ this.aoNode = aoNode; diff --git a/src/nodes/lighting/AnalyticLightNode.js b/src/nodes/lighting/AnalyticLightNode.js index 5ae7f9381e0f13..4888ffa3680770 100644 --- a/src/nodes/lighting/AnalyticLightNode.js +++ b/src/nodes/lighting/AnalyticLightNode.js @@ -32,7 +32,7 @@ class AnalyticLightNode extends LightingNode { /** * The light source. * - * @type {Light} + * @type {Light?} * @default null */ this.light = light; @@ -56,21 +56,24 @@ class AnalyticLightNode extends LightingNode { * This property is used to retain a reference to the original value of {@link AnalyticLightNode#colorNode}. * The final color node is represented by a different node when using shadows. * - * @type {Node} + * @type {Node?} + * @default null */ this.baseColorNode = null; /** * Represents the light's shadow. * - * @type {ShadowNode} + * @type {ShadowNode?} + * @default null */ this.shadowNode = null; /** * Represents the light's shadow color. * - * @type {Node} + * @type {Node?} + * @default null */ this.shadowColorNode = null; diff --git a/src/nodes/lighting/BasicEnvironmentNode.js b/src/nodes/lighting/BasicEnvironmentNode.js index 3f4c73b6008b25..4afee453339999 100644 --- a/src/nodes/lighting/BasicEnvironmentNode.js +++ b/src/nodes/lighting/BasicEnvironmentNode.js @@ -3,7 +3,7 @@ import { cubeMapNode } from '../utils/CubeMapNode.js'; /** * Represents a basic model for Image-based lighting (IBL). The environment - * is defined via environment maps in the equirectanular or cube map format. + * is defined via environment maps in the equirectangular or cube map format. * `BasicEnvironmentNode` is intended for non-PBR materials like {@link MeshBasicNodeMaterial} * or {@link MeshPhongNodeMaterial}. * diff --git a/src/nodes/lighting/BasicLightMapNode.js b/src/nodes/lighting/BasicLightMapNode.js index 0d1ac92e8933e8..bfe68dea8ba1f3 100644 --- a/src/nodes/lighting/BasicLightMapNode.js +++ b/src/nodes/lighting/BasicLightMapNode.js @@ -19,7 +19,7 @@ class BasicLightMapNode extends LightingNode { /** * Constructs a new basic light map node. * - * @param {Node} lightMapNode - The light map node. + * @param {Node?} [lightMapNode=null] - The light map node. */ constructor( lightMapNode = null ) { @@ -28,7 +28,7 @@ class BasicLightMapNode extends LightingNode { /** * The light map node. * - * @type {Node} + * @type {Node?} */ this.lightMapNode = lightMapNode; diff --git a/src/nodes/lighting/EnvironmentNode.js b/src/nodes/lighting/EnvironmentNode.js index 1525ebb1709e9f..1e12822edcf9ef 100644 --- a/src/nodes/lighting/EnvironmentNode.js +++ b/src/nodes/lighting/EnvironmentNode.js @@ -13,7 +13,7 @@ const _envNodeCache = new WeakMap(); /** * Represents a physical model for Image-based lighting (IBL). The environment - * is defined via environment maps in the equirectanular, cube map or cubeUV (PMREM) format. + * is defined via environment maps in the equirectangular, cube map or cubeUV (PMREM) format. * `EnvironmentNode` is intended for PBR materials like {@link MeshStandardNodeMaterial}. * * @augments LightingNode @@ -38,7 +38,7 @@ class EnvironmentNode extends LightingNode { /** * A node representing the environment. * - * @type {Node} + * @type {Node?} * @default null */ this.envNode = envNode; diff --git a/src/nodes/lighting/LightingContextNode.js b/src/nodes/lighting/LightingContextNode.js index cc28a5da1ed845..131928d3358a2a 100644 --- a/src/nodes/lighting/LightingContextNode.js +++ b/src/nodes/lighting/LightingContextNode.js @@ -2,7 +2,7 @@ import ContextNode from '../core/ContextNode.js'; import { nodeProxy, float, vec3 } from '../tsl/TSLBase.js'; /** - * `LightingContextNode` represents an extension of the {@link ContextNode} module + * `LightingContextNode` represents an extension of the {@link module:ContextNode~ContextNode} module * by adding lighting specific context data. It represents the runtime context of * {@link LightsNode}. * @@ -20,9 +20,9 @@ class LightingContextNode extends ContextNode { * Constructs a new lighting context node. * * @param {LightsNode} node - The lights node. - * @param {LightingModel} [lightingModel=null] - The current lighting model. - * @param {Node} [backdropNode=null] - A backdrop node. - * @param {Node} [backdropAlphaNode=null] - A backdrop alpha node. + * @param {LightingModel?} [lightingModel=null] - The current lighting model. + * @param {Node?} [backdropNode=null] - A backdrop node. + * @param {Node?} [backdropAlphaNode=null] - A backdrop alpha node. */ constructor( node, lightingModel = null, backdropNode = null, backdropAlphaNode = null ) { @@ -31,7 +31,7 @@ class LightingContextNode extends ContextNode { /** * The current lighting model. * - * @type {LightingModel} + * @type {LightingModel?} * @default null */ this.lightingModel = lightingModel; @@ -39,7 +39,7 @@ class LightingContextNode extends ContextNode { /** * A backdrop node. * - * @type {Node} + * @type {Node?} * @default null */ this.backdropNode = backdropNode; @@ -47,7 +47,7 @@ class LightingContextNode extends ContextNode { /** * A backdrop alpha node. * - * @type {Node} + * @type {Node?} * @default null */ this.backdropAlphaNode = backdropAlphaNode; diff --git a/src/nodes/lighting/LightsNode.js b/src/nodes/lighting/LightsNode.js index 55299ad1ff35a8..cf378cc55cd0dc 100644 --- a/src/nodes/lighting/LightsNode.js +++ b/src/nodes/lighting/LightsNode.js @@ -117,6 +117,7 @@ class LightsNode extends Node { customCacheKey() { const lightIDs = []; + const lights = this._lights; for ( let i = 0; i < lights.length; i ++ ) { diff --git a/src/nodes/lighting/PointShadowNode.js b/src/nodes/lighting/PointShadowNode.js index f15b55489686d2..c3d3523ebffbab 100644 --- a/src/nodes/lighting/PointShadowNode.js +++ b/src/nodes/lighting/PointShadowNode.js @@ -163,7 +163,7 @@ const _shadowMapSize = /*@__PURE__*/ new Vector2(); /** * Represents the shadow implementation for point light nodes. * - * @augments ShadowNode + * @augments module:ShadowNode~ShadowNode */ class PointShadowNode extends ShadowNode { @@ -218,6 +218,7 @@ class PointShadowNode extends ShadowNode { * @param {NodeBuilder} builder - A reference to the current node builder. * @param {Object} inputs - A configuration object that defines the shadow filtering. * @param {Function} inputs.filterFn - This function defines the filtering type of the shadow map e.g. PCF. + * @param {Texture} inputs.shadowTexture - A reference to the shadow map's texture. * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. * @param {Node} inputs.shadowCoord - Shadow coordinates which are used to sample from the shadow map. * @param {LightShadow} inputs.shadow - The light shadow. @@ -233,7 +234,7 @@ class PointShadowNode extends ShadowNode { * Overwrites the default implementation with point light specific * rendering code. * - * @param {NodeFrme} frame - A reference to the current node frame. + * @param {NodeFrame} frame - A reference to the current node frame. */ renderShadow( frame ) { diff --git a/src/nodes/lighting/ShadowBaseNode.js b/src/nodes/lighting/ShadowBaseNode.js index b8e7dc0a191ac0..4b3a5b894ab75f 100644 --- a/src/nodes/lighting/ShadowBaseNode.js +++ b/src/nodes/lighting/ShadowBaseNode.js @@ -58,15 +58,15 @@ class ShadowBaseNode extends Node { } /** - * Setups the shadow position node which is by default the predefined TSL node object `shadowWorldPosition`. + * Setups the shadow position node which is by default the predefined TSL node object `shadowPositionWorld`. * - * @param {(NodeBuilder|{material})} object - A configuration object that must at least hold a material reference. + * @param {(NodeBuilder|{Material})} object - A configuration object that must at least hold a material reference. */ setupShadowPosition( { material } ) { // Use assign inside an Fn() - shadowWorldPosition.assign( material.shadowPositionNode || positionWorld ); + shadowPositionWorld.assign( material.shadowPositionNode || positionWorld ); } @@ -88,6 +88,6 @@ class ShadowBaseNode extends Node { * * @type {Node} */ -export const shadowWorldPosition = /*@__PURE__*/ vec3().toVar( 'shadowWorldPosition' ); +export const shadowPositionWorld = /*@__PURE__*/ vec3().toVar( 'shadowPositionWorld' ); export default ShadowBaseNode; diff --git a/src/nodes/lighting/ShadowNode.js b/src/nodes/lighting/ShadowNode.js index 09f4f88ffb38c6..97886f305e6e73 100644 --- a/src/nodes/lighting/ShadowNode.js +++ b/src/nodes/lighting/ShadowNode.js @@ -1,4 +1,4 @@ -import ShadowBaseNode, { shadowWorldPosition } from './ShadowBaseNode.js'; +import ShadowBaseNode, { shadowPositionWorld } from './ShadowBaseNode.js'; import { float, vec2, vec3, vec4, If, int, Fn, nodeObject } from '../tsl/TSLBase.js'; import { reference } from '../accessors/ReferenceNode.js'; import { texture } from '../accessors/TextureNode.js'; @@ -16,6 +16,8 @@ import { renderGroup } from '../core/UniformGroupNode.js'; import { viewZToLogarithmicDepth } from '../display/ViewportDepthNode.js'; import { objectPosition } from '../accessors/Object3DNode.js'; import { lightShadowMatrix } from '../accessors/Lights.js'; +import { resetRendererAndSceneState, restoreRendererAndSceneState } from '../../renderers/common/RendererUtils.js'; +import { getDataFromObject } from '../core/NodeUtils.js'; /** @module ShadowNode **/ @@ -54,8 +56,9 @@ const getShadowMaterial = ( light ) => { material = new NodeMaterial(); material.colorNode = vec4( 0, 0, 0, 1 ); material.depthNode = depthNode; - material.isShadowNodeMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode + material.isShadowPassMaterial = true; // Use to avoid other overrideMaterial override material.colorNode unintentionally when using material.shadowNode material.name = 'ShadowMaterial'; + material.fog = false; shadowMaterialLib.set( light, material ); @@ -305,12 +308,13 @@ const _shadowFilterLib = [ BasicShadowFilter, PCFShadowFilter, PCFSoftShadowFilt // +let _rendererState; const _quadMesh = /*@__PURE__*/ new QuadMesh(); /** * Represents the default shadow implementation for lighting nodes. * - * @augments ShadowBaseNode + * @augments module:ShadowBaseNode~ShadowBaseNode */ class ShadowNode extends ShadowBaseNode { @@ -548,7 +552,7 @@ class ShadowNode extends ShadowBaseNode { const shadowIntensity = reference( 'intensity', 'float', shadow ).setGroup( renderGroup ); const normalBias = reference( 'normalBias', 'float', shadow ).setGroup( renderGroup ); - const shadowPosition = lightShadowMatrix( light ).mul( shadowWorldPosition.add( transformedNormalWorld.mul( normalBias ) ) ); + const shadowPosition = lightShadowMatrix( light ).mul( shadowPositionWorld.add( transformedNormalWorld.mul( normalBias ) ) ); const shadowCoord = this.setupShadowCoord( builder, shadowPosition ); // @@ -640,7 +644,7 @@ class ShadowNode extends ShadowBaseNode { /** * Updates the shadow. * - * @param {NodeFrme} frame - A reference to the current node frame. + * @param {NodeFrame} frame - A reference to the current node frame. */ updateShadow( frame ) { @@ -652,22 +656,27 @@ class ShadowNode extends ShadowBaseNode { const depthVersion = shadowMap.depthTexture.version; this._depthVersionCached = depthVersion; - const currentOverrideMaterial = scene.overrideMaterial; - - scene.overrideMaterial = getShadowMaterial( light ); - shadow.camera.layers.mask = camera.layers.mask; - const currentRenderTarget = renderer.getRenderTarget(); const currentRenderObjectFunction = renderer.getRenderObjectFunction(); + const currentMRT = renderer.getMRT(); + const useVelocity = currentMRT ? currentMRT.has( 'velocity' ) : false; + + _rendererState = resetRendererAndSceneState( renderer, scene, _rendererState ); - renderer.setMRT( null ); + scene.overrideMaterial = getShadowMaterial( light ); renderer.setRenderObjectFunction( ( object, scene, _camera, geometry, material, group, ...params ) => { if ( object.castShadow === true || ( object.receiveShadow && shadowType === VSMShadowMap ) ) { + if ( useVelocity ) { + + getDataFromObject( object ).useVelocity = true; + + } + object.onBeforeShadow( renderer, object, camera, shadow.camera, geometry, scene.overrideMaterial, group ); renderer.renderObject( object, scene, _camera, geometry, material, group, ...params ); @@ -692,11 +701,7 @@ class ShadowNode extends ShadowBaseNode { } - renderer.setRenderTarget( currentRenderTarget ); - - renderer.setMRT( currentMRT ); - - scene.overrideMaterial = currentOverrideMaterial; + restoreRendererAndSceneState( renderer, scene, _rendererState ); } diff --git a/src/nodes/lighting/SpotLightNode.js b/src/nodes/lighting/SpotLightNode.js index 042480e3aa45b2..21795ef762a486 100644 --- a/src/nodes/lighting/SpotLightNode.js +++ b/src/nodes/lighting/SpotLightNode.js @@ -30,14 +30,14 @@ class SpotLightNode extends AnalyticLightNode { super( light ); /** - * Uniform node representing the cone cosinus. + * Uniform node representing the cone cosine. * * @type {UniformNode} */ this.coneCosNode = uniform( 0 ).setGroup( renderGroup ); /** - * Uniform node representing the penumbra cosinus. + * Uniform node representing the penumbra cosine. * * @type {UniformNode} */ diff --git a/src/nodes/math/ConditionalNode.js b/src/nodes/math/ConditionalNode.js index 9566308a2af3c9..dba9b29f45e47c 100644 --- a/src/nodes/math/ConditionalNode.js +++ b/src/nodes/math/ConditionalNode.js @@ -2,6 +2,8 @@ import Node from '../core/Node.js'; import { property } from '../core/PropertyNode.js'; import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js'; +/** @module ConditionalNode **/ + /** * Represents a logical `if/else` statement. Can be used as an alternative * to the `If()`/`Else()` syntax. @@ -10,7 +12,7 @@ import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js'; * ```js * velocity = position.greaterThanEqual( limit ).select( velocity.negate(), velocity ); * ``` - * The `select()` method is called in a chaining fashion on a codition. The parameter nodes of `select()` + * The `select()` method is called in a chaining fashion on a condition. The parameter nodes of `select()` * determine the outcome of the entire statement. * * @augments Node @@ -51,7 +53,8 @@ class ConditionalNode extends Node { /** * The node that is evaluate when the condition ends up `false`. * - * @type {Node} + * @type {Node?} + * @default null */ this.elseNode = elseNode; @@ -66,11 +69,23 @@ class ConditionalNode extends Node { */ getNodeType( builder ) { - const ifType = this.ifNode.getNodeType( builder ); + const { ifNode, elseNode } = builder.getNodeProperties( this ); + + if ( ifNode === undefined ) { + + // fallback setup + + this.setup( builder ); + + return this.getNodeType( builder ); + + } + + const ifType = ifNode.getNodeType( builder ); - if ( this.elseNode !== null ) { + if ( elseNode !== null ) { - const elseType = this.elseNode.getNodeType( builder ); + const elseType = elseNode.getNodeType( builder ); if ( builder.getTypeLength( elseType ) > builder.getTypeLength( ifType ) ) { @@ -183,12 +198,28 @@ class ConditionalNode extends Node { export default ConditionalNode; +/** + * TSL function for creating a conditional node. + * + * @function + * @param {Node} condNode - The node that defines the condition. + * @param {Node} ifNode - The node that is evaluate when the condition ends up `true`. + * @param {Node?} [elseNode=null] - The node that is evaluate when the condition ends up `false`. + * @returns {ConditionalNode} + */ export const select = /*@__PURE__*/ nodeProxy( ConditionalNode ); addMethodChaining( 'select', select ); -// +// deprecated +/** + * @function + * @deprecated since r168. Use {@link select} instead. + * + * @param {...any} params + * @returns {ConditionalNode} + */ export const cond = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.ConditionalNode: cond() has been renamed to select().' ); diff --git a/src/nodes/math/MathNode.js b/src/nodes/math/MathNode.js index 51c6a72c73d4f1..786aa41e3215ab 100644 --- a/src/nodes/math/MathNode.js +++ b/src/nodes/math/MathNode.js @@ -1,6 +1,9 @@ import TempNode from '../core/TempNode.js'; import { sub, mul, div } from './OperatorNode.js'; import { addMethodChaining, nodeObject, nodeProxy, float, vec2, vec3, vec4, Fn } from '../tsl/TSLCore.js'; +import { WebGLCoordinateSystem, WebGPUCoordinateSystem } from '../../constants.js'; + +/** @module MathNode **/ /** * This node represents a variety of mathematical methods available in shaders. @@ -33,11 +36,9 @@ class MathNode extends TempNode { super(); /** - * This flag can be used for type testing. + * The method name. * - * @type {Boolean} - * @readonly - * @default true + * @type {String} */ this.method = method; @@ -64,6 +65,15 @@ class MathNode extends TempNode { */ this.cNode = cNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isMathNode = true; + } /** @@ -140,7 +150,7 @@ class MathNode extends TempNode { generate( builder, output ) { - const method = this.method; + let method = this.method; const type = this.getNodeType( builder ); const inputType = this.getInputType( builder ); @@ -149,7 +159,7 @@ class MathNode extends TempNode { const b = this.bNode; const c = this.cNode; - const isWebGL = builder.renderer.isWebGLRenderer === true; + const coordinateSystem = builder.renderer.coordinateSystem; if ( method === MathNode.TRANSFORM_DIRECTION ) { @@ -200,14 +210,14 @@ class MathNode extends TempNode { b.build( builder, type ) ); - } else if ( isWebGL && method === MathNode.STEP ) { + } else if ( coordinateSystem === WebGLCoordinateSystem && 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 ) { + } else if ( ( coordinateSystem === WebGLCoordinateSystem && ( method === MathNode.MIN || method === MathNode.MAX ) ) || method === MathNode.MOD ) { params.push( a.build( builder, inputType ), @@ -232,6 +242,12 @@ class MathNode extends TempNode { } else { + if ( coordinateSystem === WebGPUCoordinateSystem && method === MathNode.ATAN && b !== null ) { + + method = 'atan2'; + + } + params.push( a.build( builder, inputType ) ); if ( b !== null ) params.push( b.build( builder, inputType ) ); if ( c !== null ) params.push( c.build( builder, inputType ) ); @@ -266,7 +282,6 @@ class MathNode extends TempNode { MathNode.ALL = 'all'; MathNode.ANY = 'any'; -MathNode.EQUALS = 'equals'; MathNode.RADIANS = 'radians'; MathNode.DEGREES = 'degrees'; @@ -297,12 +312,12 @@ MathNode.ROUND = 'round'; MathNode.RECIPROCAL = 'reciprocal'; MathNode.TRUNC = 'trunc'; MathNode.FWIDTH = 'fwidth'; -MathNode.BITCAST = 'bitcast'; MathNode.TRANSPOSE = 'transpose'; // 2 inputs -MathNode.ATAN2 = 'atan2'; +MathNode.BITCAST = 'bitcast'; +MathNode.EQUALS = 'equals'; MathNode.MIN = 'min'; MathNode.MAX = 'max'; MathNode.MOD = 'mod'; @@ -325,72 +340,574 @@ MathNode.FACEFORWARD = 'faceforward'; export default MathNode; +// 1 inputs + +/** + * A small value used to handle floating-point precision errors. + * + * @type {Node} + */ export const EPSILON = /*@__PURE__*/ float( 1e-6 ); + +/** + * Represents infinity. + * + * @type {Node} + */ export const INFINITY = /*@__PURE__*/ float( 1e6 ); + +/** + * Represents PI. + * + * @type {Node} + */ export const PI = /*@__PURE__*/ float( Math.PI ); + +/** + * Represents PI * 2. + * + * @type {Node} + */ export const PI2 = /*@__PURE__*/ float( Math.PI * 2 ); +/** + * Returns `true` if all components of `x` are `true`. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const all = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ALL ); + +/** + * Returns `true` if any components of `x` are `true`. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const any = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ANY ); -export const equals = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EQUALS ); +/** + * Converts a quantity in degrees to radians. + * + * @function + * @param {Node | Number} x - The input in degrees. + * @returns {Node} + */ export const radians = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RADIANS ); + +/** + * Convert a quantity in radians to degrees. + * + * @function + * @param {Node | Number} x - The input in radians. + * @returns {Node} + */ export const degrees = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DEGREES ); + +/** + * Returns the natural exponentiation of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const exp = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP ); + +/** + * Returns 2 raised to the power of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const exp2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EXP2 ); + +/** + * Returns the natural logarithm of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const log = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG ); + +/** + * Returns the base 2 logarithm of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const log2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LOG2 ); + +/** + * Returns the square root of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const sqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SQRT ); + +/** + * Returns the inverse of the square root of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const inverseSqrt = /*@__PURE__*/ nodeProxy( MathNode, MathNode.INVERSE_SQRT ); + +/** + * Finds the nearest integer less than or equal to the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const floor = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FLOOR ); + +/** + * Finds the nearest integer that is greater than or equal to the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const ceil = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CEIL ); + +/** + * Calculates the unit vector in the same direction as the original vector. + * + * @function + * @param {Node} x - The input vector. + * @returns {Node} + */ export const normalize = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NORMALIZE ); + +/** + * Computes the fractional part of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const fract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FRACT ); + +/** + * Returns the sine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const sin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIN ); + +/** + * Returns the cosine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const cos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.COS ); + +/** + * Returns the tangent of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const tan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TAN ); + +/** + * Returns the arcsine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const asin = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ASIN ); + +/** + * Returns the arccosine of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const acos = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ACOS ); + +/** + * Returns the arc-tangent of the parameter. + * If two parameters are provided, the result is `atan2(y/x)`. + * + * @function + * @param {Node | Number} y - The y parameter. + * @param {(Node | Number)?} x - The x parameter. + * @returns {Node} + */ export const atan = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN ); + +/** + * Returns the absolute value of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const abs = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ABS ); + +/** + * Extracts the sign of the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const sign = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SIGN ); + +/** + * Calculates the length of a vector. + * + * @function + * @param {Node} x - The parameter. + * @returns {Node} + */ export const length = /*@__PURE__*/ nodeProxy( MathNode, MathNode.LENGTH ); + +/** + * Negates the value of the parameter (-x). + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const negate = /*@__PURE__*/ nodeProxy( MathNode, MathNode.NEGATE ); + +/** + * Return `1` minus the parameter. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const oneMinus = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ONE_MINUS ); + +/** + * Returns the partial derivative of the parameter with respect to x. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const dFdx = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDX ); + +/** + * Returns the partial derivative of the parameter with respect to y. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const dFdy = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DFDY ); + +/** + * Rounds the parameter to the nearest integer. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const round = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ROUND ); + +/** + * Returns the reciprocal of the parameter `(1/x)`. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const reciprocal = /*@__PURE__*/ nodeProxy( MathNode, MathNode.RECIPROCAL ); + +/** + * Truncates the parameter, removing the fractional part. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const trunc = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRUNC ); + +/** + * Returns the sum of the absolute derivatives in x and y. + * + * @function + * @param {Node | Number} x - The parameter. + * @returns {Node} + */ export const fwidth = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FWIDTH ); -export const bitcast = /*@__PURE__*/ nodeProxy( MathNode, MathNode.BITCAST ); + +/** + * Returns the transpose of a matrix. + * + * @function + * @param {Node} x - The parameter. + * @returns {Node} + */ export const transpose = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSPOSE ); -export const atan2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.ATAN2 ); +// 2 inputs + +/** + * Reinterpret the bit representation of a value in one type as a value in another type. + * + * @function + * @param {Node | Number} x - The parameter. + * @param {String} y - The new type. + * @returns {Node} + */ +export const bitcast = /*@__PURE__*/ nodeProxy( MathNode, MathNode.BITCAST ); + +/** + * Returns `true` if `x` equals `y`. + * + * @function + * @param {Node | Number} x - The first parameter. + * @param {Node | Number} y - The second parameter. + * @returns {Node} + */ +export const equals = /*@__PURE__*/ nodeProxy( MathNode, MathNode.EQUALS ); + +/** + * Returns the lesser of two values. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ export const min = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIN ); + +/** + * Returns the greater of two values. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ export const max = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MAX ); + +/** + * Computes the remainder of dividing the first node by the second one. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ export const mod = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MOD ); + +/** + * Generate a step function by comparing two values. + * + * @function + * @param {Node | Number} x - The y parameter. + * @param {Node | Number} y - The x parameter. + * @returns {Node} + */ export const step = /*@__PURE__*/ nodeProxy( MathNode, MathNode.STEP ); + +/** + * Calculates the reflection direction for an incident vector. + * + * @function + * @param {Node} I - The incident vector. + * @param {Node} N - The normal vector. + * @returns {Node} + */ export const reflect = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFLECT ); + +/** + * Calculates the distance between two points. + * + * @function + * @param {Node} x - The first point. + * @param {Node} y - The second point. + * @returns {Node} + */ export const distance = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DISTANCE ); + +/** + * Calculates the absolute difference between two values. + * + * @function + * @param {Node | Number} x - The first parameter. + * @param {Node | Number} y - The second parameter. + * @returns {Node} + */ export const difference = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DIFFERENCE ); + +/** + * Calculates the dot product of two vectors. + * + * @function + * @param {Node} x - The first vector. + * @param {Node} y - The second vector. + * @returns {Node} + */ export const dot = /*@__PURE__*/ nodeProxy( MathNode, MathNode.DOT ); + +/** + * Calculates the cross product of two vectors. + * + * @function + * @param {Node} x - The first vector. + * @param {Node} y - The second vector. + * @returns {Node} + */ export const cross = /*@__PURE__*/ nodeProxy( MathNode, MathNode.CROSS ); + +/** + * Return the value of the first parameter raised to the power of the second one. + * + * @function + * @param {Node | Number} x - The first parameter. + * @param {Node | Number} y - The second parameter. + * @returns {Node} + */ export const pow = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW ); + +/** + * Returns the square of the parameter. + * + * @function + * @param {Node | Number} x - The first parameter. + * @returns {Node} + */ export const pow2 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 2 ); + +/** + * Returns the cube of the parameter. + * + * @function + * @param {Node | Number} x - The first parameter. + * @returns {Node} + */ export const pow3 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 3 ); + +/** + * Returns the fourth power of the parameter. + * + * @function + * @param {Node | Number} x - The first parameter. + * @returns {Node} + */ export const pow4 = /*@__PURE__*/ nodeProxy( MathNode, MathNode.POW, 4 ); + +/** + * Transforms the direction of a vector by a matrix and then normalizes the result. + * + * @function + * @param {Node} direction - The direction vector. + * @param {Node} matrix - The transformation matrix. + * @returns {Node} + */ export const transformDirection = /*@__PURE__*/ nodeProxy( MathNode, MathNode.TRANSFORM_DIRECTION ); +/** + * Returns the cube root of a number. + * + * @function + * @param {Node | Number} a - The first parameter. + * @returns {Node} + */ export const cbrt = ( a ) => mul( sign( a ), pow( abs( a ), 1.0 / 3.0 ) ); + +/** + * Calculate the squared length of a vector. + * + * @function + * @param {Node} a - The vector. + * @returns {Node} + */ export const lengthSq = ( a ) => dot( a, a ); + +/** + * Linearly interpolates between two values. + * + * @function + * @param {Node | Number} a - The first parameter. + * @param {Node | Number} b - The second parameter. + * @param {Node | Number} t - The interpolation value. + * @returns {Node} + */ export const mix = /*@__PURE__*/ nodeProxy( MathNode, MathNode.MIX ); + +/** + * Constrains a value to lie between two further values. + * + * @function + * @param {Node | Number} value - The value to constrain. + * @param {Node | Number} [low=0] - The lower bound. + * @param {Node | Number} [high=1] - The upper bound. + * @returns {Node} + */ export const clamp = ( value, low = 0, high = 1 ) => nodeObject( new MathNode( MathNode.CLAMP, nodeObject( value ), nodeObject( low ), nodeObject( high ) ) ); + +/** + * Constrains a value between `0` and `1`. + * + * @function + * @param {Node | Number} value - The value to constrain. + * @returns {Node} + */ export const saturate = ( value ) => clamp( value ); + +/** + * Calculates the refraction direction for an incident vector. + * + * @function + * @param {Node} I - The incident vector. + * @param {Node} N - The normal vector. + * @param {Node} eta - The the ratio of indices of refraction. + * @returns {Node} + */ export const refract = /*@__PURE__*/ nodeProxy( MathNode, MathNode.REFRACT ); + +/** + * Performs a Hermite interpolation between two values. + * + * @function + * @param {Node | Number} low - The value of the lower edge of the Hermite function. + * @param {Node | Number} high - The value of the upper edge of the Hermite function. + * @param {Node | Number} x - The source value for interpolation. + * @returns {Node} + */ export const smoothstep = /*@__PURE__*/ nodeProxy( MathNode, MathNode.SMOOTHSTEP ); + +/** + * Returns a vector pointing in the same direction as another. + * + * @function + * @param {Node} N - The vector to orient. + * @param {Node} I - The incident vector. + * @param {Node} Nref - The reference vector. + * @returns {Node} + */ export const faceForward = /*@__PURE__*/ nodeProxy( MathNode, MathNode.FACEFORWARD ); +/** + * Returns a random value for the given uv. + * + * @function + * @param {Node} uv - The uv node. + * @returns {Node} + */ export const rand = /*@__PURE__*/ Fn( ( [ uv ] ) => { const a = 12.9898, b = 78.233, c = 43758.5453; @@ -400,9 +917,52 @@ export const rand = /*@__PURE__*/ Fn( ( [ uv ] ) => { } ); +/** + * Alias for `mix()` with a different parameter order. + * + * @function + * @param {Node | Number} t - The interpolation value. + * @param {Node | Number} e1 - The first parameter. + * @param {Node | Number} e2 - The second parameter. + * @returns {Node} + */ export const mixElement = ( t, e1, e2 ) => mix( e1, e2, t ); + +/** + * Alias for `smoothstep()` with a different parameter order. + * + * @function + * @param {Node | Number} x - The source value for interpolation. + * @param {Node | Number} low - The value of the lower edge of the Hermite function. + * @param {Node | Number} high - The value of the upper edge of the Hermite function. + * @returns {Node} + */ export const smoothstepElement = ( x, low, high ) => smoothstep( low, high, x ); +/** + * Returns the arc-tangent of the quotient of its parameters. + * + * @function + * @deprecated since r172. Use {@link atan} instead. + * + * @param {Node | Number} y - The y parameter. + * @param {Node | Number} x - The x parameter. + * @returns {Node} + */ +export const atan2 = ( y, x ) => { // @deprecated, r172 + + console.warn( 'THREE.TSL: "atan2" is overloaded. Use "atan" instead.' ); + return atan( y, x ); + +}; + +// GLSL alias function + +export const faceforward = faceForward; +export const inversesqrt = inverseSqrt; + +// Method chaining + addMethodChaining( 'all', all ); addMethodChaining( 'any', any ); addMethodChaining( 'equals', equals ); diff --git a/src/nodes/math/MathUtils.js b/src/nodes/math/MathUtils.js index 7f904d69f76025..347d076e793d15 100644 --- a/src/nodes/math/MathUtils.js +++ b/src/nodes/math/MathUtils.js @@ -22,7 +22,7 @@ export const parabola = ( x, k ) => pow( mul( 4.0, x.mul( sub( 1.0, x ) ) ), k ) * * @method * @param {Node} x - The value to remap. - * @param {Node} k - `k=1` is the identity curve,`k<1` produces the classic `gain()` shape, and `k>1` produces "s" shaped curces. + * @param {Node} k - `k=1` is the identity curve,`k<1` produces the classic `gain()` shape, and `k>1` produces "s" shaped curves. * @return {Node} The remapped value. */ export 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 ) ); diff --git a/src/nodes/math/OperatorNode.js b/src/nodes/math/OperatorNode.js index 50600d7d459bec..c009eed09761a6 100644 --- a/src/nodes/math/OperatorNode.js +++ b/src/nodes/math/OperatorNode.js @@ -1,6 +1,8 @@ import TempNode from '../core/TempNode.js'; import { addMethodChaining, nodeProxy } from '../tsl/TSLCore.js'; +/** @module OperatorNode **/ + /** * This node represents basic mathematical and logical operations like addition, * subtraction or comparisons (e.g. `equal()`). @@ -63,6 +65,15 @@ class OperatorNode extends TempNode { */ this.bNode = bNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ + this.isOperatorNode = true; + } /** @@ -303,26 +314,218 @@ class OperatorNode extends TempNode { export default OperatorNode; +/** + * Returns the addition of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ export const add = /*@__PURE__*/ nodeProxy( OperatorNode, '+' ); + +/** + * Returns the subtraction of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ export const sub = /*@__PURE__*/ nodeProxy( OperatorNode, '-' ); + +/** + * Returns the multiplication of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ export const mul = /*@__PURE__*/ nodeProxy( OperatorNode, '*' ); + +/** + * Returns the division of two or more value. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @param {...Node} params - Additional input parameters. + * @returns {OperatorNode} + */ export const div = /*@__PURE__*/ nodeProxy( OperatorNode, '/' ); + +/** + * Computes the remainder of dividing the first node by the second, for integer values. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const modInt = /*@__PURE__*/ nodeProxy( OperatorNode, '%' ); + +/** + * Checks if two nodes are equal. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const equal = /*@__PURE__*/ nodeProxy( OperatorNode, '==' ); + +/** + * Checks if two nodes are not equal. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const notEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '!=' ); + +/** + * Checks if the first node is less than the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const lessThan = /*@__PURE__*/ nodeProxy( OperatorNode, '<' ); + +/** + * Checks if the first node is greater than the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const greaterThan = /*@__PURE__*/ nodeProxy( OperatorNode, '>' ); + +/** + * Checks if the first node is less than or equal to the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const lessThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '<=' ); + +/** + * Checks if the first node is greater than or equal to the second. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const greaterThanEqual = /*@__PURE__*/ nodeProxy( OperatorNode, '>=' ); + +/** + * Performs logical AND on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const and = /*@__PURE__*/ nodeProxy( OperatorNode, '&&' ); + +/** + * Performs logical OR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const or = /*@__PURE__*/ nodeProxy( OperatorNode, '||' ); + +/** + * Performs logical NOT on a node. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const not = /*@__PURE__*/ nodeProxy( OperatorNode, '!' ); + +/** + * Performs logical XOR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const xor = /*@__PURE__*/ nodeProxy( OperatorNode, '^^' ); + +/** + * Performs bitwise AND on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const bitAnd = /*@__PURE__*/ nodeProxy( OperatorNode, '&' ); + +/** + * Performs bitwise NOT on a node. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const bitNot = /*@__PURE__*/ nodeProxy( OperatorNode, '~' ); + +/** + * Performs bitwise OR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const bitOr = /*@__PURE__*/ nodeProxy( OperatorNode, '|' ); + +/** + * Performs bitwise XOR on two nodes. + * + * @function + * @param {Node} aNode - The first input. + * @param {Node} bNode - The second input. + * @returns {OperatorNode} + */ export const bitXor = /*@__PURE__*/ nodeProxy( OperatorNode, '^' ); + +/** + * Shifts a node to the left. + * + * @function + * @param {Node} aNode - The node to shift. + * @param {Node} bNode - The value to shift. + * @returns {OperatorNode} + */ export const shiftLeft = /*@__PURE__*/ nodeProxy( OperatorNode, '<<' ); + +/** + * Shifts a node to the right. + * + * @function + * @param {Node} aNode - The node to shift. + * @param {Node} bNode - The value to shift. + * @returns {OperatorNode} + */ export const shiftRight = /*@__PURE__*/ nodeProxy( OperatorNode, '>>' ); addMethodChaining( 'add', add ); @@ -347,7 +550,13 @@ addMethodChaining( 'bitXor', bitXor ); addMethodChaining( 'shiftLeft', shiftLeft ); addMethodChaining( 'shiftRight', shiftRight ); - +/** + * @function + * @deprecated since r168. Use {@link modInt} instead. + * + * @param {...any} params + * @returns {Function} + */ export const remainder = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.OperatorNode: .remainder() has been renamed to .modInt().' ); diff --git a/src/nodes/pmrem/PMREMNode.js b/src/nodes/pmrem/PMREMNode.js index a11b6805a9e910..8120c986dcd28d 100644 --- a/src/nodes/pmrem/PMREMNode.js +++ b/src/nodes/pmrem/PMREMNode.js @@ -362,7 +362,7 @@ function isEquirectangularMapReady( image ) { } /** - * TSL function for creating a PMREM node with the given paramters. + * TSL function for creating a PMREM node. * * @function * @param {Texture} value - The input texture. diff --git a/src/nodes/procedural/Checker.js b/src/nodes/procedural/Checker.js index b897c6760b33d0..503bb2094e4298 100644 --- a/src/nodes/procedural/Checker.js +++ b/src/nodes/procedural/Checker.js @@ -7,7 +7,7 @@ import { Fn } from '../tsl/TSLBase.js'; * Creates a 2x2 checkerboard pattern that can be used as procedural texture data. * * @method - * @param {Node} uv - The uv coordinates. + * @param {Node} coord - The uv coordinates. * @return {Node} The result data. */ export const checker = /*@__PURE__*/ Fn( ( [ coord = uv() ] ) => { diff --git a/src/nodes/shapes/Shapes.js b/src/nodes/shapes/Shapes.js new file mode 100644 index 00000000000000..07dc74e46c46d7 --- /dev/null +++ b/src/nodes/shapes/Shapes.js @@ -0,0 +1,33 @@ +import { Fn, float } from '../tsl/TSLBase.js'; +import { lengthSq, smoothstep } from '../math/MathNode.js'; +import { uv } from '../accessors/UV.js'; + +/** @module Shapes **/ + +/** + * Generates a circle based on the uv coordinates. + * + * @method + * @param {Node} coord - The uv to generate the circle. + * @return {Node} The circle shape. + */ +export const shapeCircle = Fn( ( [ coord = uv() ], { renderer, material } ) => { + + const alpha = float( 1 ).toVar(); + const len2 = lengthSq( coord.mul( 2 ).sub( 1 ) ); + + if ( material.alphaToCoverage && 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(); + + } + + return alpha; + +} ); diff --git a/src/nodes/tsl/TSLBase.js b/src/nodes/tsl/TSLBase.js index 4985ab6426e393..8fb44ae7df9bc0 100644 --- a/src/nodes/tsl/TSLBase.js +++ b/src/nodes/tsl/TSLBase.js @@ -11,7 +11,7 @@ export * from '../math/MathNode.js'; // abs(), floor(), ... export * from '../math/ConditionalNode.js'; // select(), ... export * from '../core/ContextNode.js'; // .context() export * from '../core/VarNode.js'; // .var() -> TODO: Maybe rename .toVar() -> .var() -export * from '../core/VaryingNode.js'; // varying() -> TODO: Add vertexStage() +export * from '../core/VaryingNode.js'; // varying(), vertexStage() export * from '../display/ColorSpaceNode.js'; // .toColorSpace() export * from '../display/ToneMappingNode.js'; // .toToneMapping() export * from '../accessors/BufferAttributeNode.js'; // .toAttribute() diff --git a/src/nodes/tsl/TSLCore.js b/src/nodes/tsl/TSLCore.js index 612362d8eaca00..ac0961c123744e 100644 --- a/src/nodes/tsl/TSLCore.js +++ b/src/nodes/tsl/TSLCore.js @@ -8,7 +8,7 @@ import FlipNode from '../utils/FlipNode.js'; import ConstNode from '../core/ConstNode.js'; import { getValueFromType, getValueType } from '../core/NodeUtils.js'; -// +/** @module TSLCore **/ let currentStack = null; @@ -305,7 +305,7 @@ class ShaderCallNodeInternal extends Node { } else { const jsFunc = shaderNode.jsFunc; - const outputNode = inputNodes !== null ? jsFunc( inputNodes, builder ) : jsFunc( builder ); + const outputNode = inputNodes !== null || jsFunc.length > 1 ? jsFunc( inputNodes || [], builder ) : jsFunc( builder ); result = nodeObject( outputNode ); @@ -553,6 +553,13 @@ export const Fn = ( jsFunc, nodeType ) => { }; +/** + * @function + * @deprecated since r168. Use {@link Fn} instead. + * + * @param {...any} params + * @returns {Function} + */ export const tslFn = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.ShaderNode: tslFn() has been renamed to Fn().' ); diff --git a/src/nodes/utils/ArrayElementNode.js b/src/nodes/utils/ArrayElementNode.js index 4e2d0c9de162ff..7f0d8d0569d24c 100644 --- a/src/nodes/utils/ArrayElementNode.js +++ b/src/nodes/utils/ArrayElementNode.js @@ -15,7 +15,7 @@ class ArrayElementNode extends Node { // @TODO: If extending from TempNode it br } /** - * Constructs array element node. + * Constructs an array element node. * * @param {Node} node - The array-like node. * @param {Node} indexNode - The index node that defines the element access. diff --git a/src/nodes/utils/CubeMapNode.js b/src/nodes/utils/CubeMapNode.js index 4c9517cde1dbb5..71e9cbb4de0506 100644 --- a/src/nodes/utils/CubeMapNode.js +++ b/src/nodes/utils/CubeMapNode.js @@ -6,6 +6,8 @@ import { cubeTexture } from '../accessors/CubeTextureNode.js'; import CubeRenderTarget from '../../renderers/common/CubeRenderTarget.js'; import { CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping } from '../../constants.js'; +/** @module CubeMapNode **/ + const _cache = new WeakMap(); /** @@ -226,4 +228,11 @@ function mapTextureMapping( texture, mapping ) { } +/** + * TSL function for creating a cube map node. + * + * @function + * @param {Node} envNode - The node representing the environment map. + * @returns {CubeMapNode} + */ export const cubeMapNode = /*@__PURE__*/ nodeProxy( CubeMapNode ); diff --git a/src/nodes/utils/EquirectUVNode.js b/src/nodes/utils/EquirectUVNode.js index 5ab3e37f447cb6..61eda0fc405935 100644 --- a/src/nodes/utils/EquirectUVNode.js +++ b/src/nodes/utils/EquirectUVNode.js @@ -2,6 +2,8 @@ import TempNode from '../core/TempNode.js'; import { positionWorldDirection } from '../accessors/Position.js'; import { nodeProxy, vec2 } from '../tsl/TSLBase.js'; +/** @module EquirectUVNode **/ + /** * Can be used to compute texture coordinates for projecting an * equirectangular texture onto a mesh for using it as the scene's @@ -24,7 +26,7 @@ class EquirectUVNode extends TempNode { /** * Constructs a new equirect uv node. * - * @param {Node} [dirNode=positionWorldDirection] - A direction vector for sampling why is by default `positionWorldDirection`. + * @param {Node} [dirNode=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`. */ constructor( dirNode = positionWorldDirection ) { @@ -43,7 +45,7 @@ class EquirectUVNode extends TempNode { const dir = this.dirNode; - const u = dir.z.atan2( dir.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 ); + const u = dir.z.atan( 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 ); @@ -54,4 +56,11 @@ class EquirectUVNode extends TempNode { export default EquirectUVNode; +/** + * TSL function for creating an equirect uv node. + * + * @function + * @param {Node} [dirNode=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`. + * @returns {EquirectUVNode} + */ export const equirectUV = /*@__PURE__*/ nodeProxy( EquirectUVNode ); diff --git a/src/nodes/utils/FunctionOverloadingNode.js b/src/nodes/utils/FunctionOverloadingNode.js index 83cef83deeb168..aec1235cb1995d 100644 --- a/src/nodes/utils/FunctionOverloadingNode.js +++ b/src/nodes/utils/FunctionOverloadingNode.js @@ -1,5 +1,7 @@ import Node from '../core/Node.js'; -import { nodeProxy } from '../tsl/TSLBase.js'; +import { nodeProxy } from '../tsl/TSLCore.js'; + +/** @module FunctionOverloadingNode **/ /** * This class allows to define multiple overloaded versions @@ -141,4 +143,11 @@ export default FunctionOverloadingNode; const overloadingBaseFn = /*@__PURE__*/ nodeProxy( FunctionOverloadingNode ); +/** + * TSL function for creating a function overloading node. + * + * @function + * @param {Array} functionNodes - Array of `Fn` function definitions. + * @returns {FunctionOverloadingNode} + */ export const overloadingFn = ( functionNodes ) => ( ...params ) => overloadingBaseFn( functionNodes, ...params ); diff --git a/src/nodes/utils/LoopNode.js b/src/nodes/utils/LoopNode.js index c6c0e1da05a7d7..cf51717eb6f44d 100644 --- a/src/nodes/utils/LoopNode.js +++ b/src/nodes/utils/LoopNode.js @@ -2,6 +2,8 @@ import Node from '../core/Node.js'; import { expression } from '../code/ExpressionNode.js'; import { nodeObject, nodeArray } from '../tsl/TSLBase.js'; +/** @module LoopNode **/ + /** * This module offers a variety of ways to implement loops in TSL. In it's basic form it's: * ```js @@ -15,7 +17,7 @@ import { nodeObject, nodeArray } from '../tsl/TSLBase.js'; * * } ); *``` - * Nested loops can be definde in a compacted form: + * Nested loops can be defined in a compacted form: * ```js * Loop( 10, 5, ( { i, j } ) => { * @@ -247,12 +249,40 @@ class LoopNode extends Node { export default LoopNode; +/** + * TSL function for creating a loop node. + * + * @function + * @param {...Any} params - A list of parameters. + * @returns {LoopNode} + */ export const Loop = ( ...params ) => nodeObject( new LoopNode( nodeArray( params, 'int' ) ) ).append(); + +/** + * TSL function for creating a `Continue()` expression. + * + * @function + * @returns {ExpressionNode} + */ export const Continue = () => expression( 'continue' ).append(); + +/** + * TSL function for creating a `Break()` expression. + * + * @function + * @returns {ExpressionNode} + */ export const Break = () => expression( 'break' ).append(); -// +// deprecated +/** + * @function + * @deprecated since r168. Use {@link Loop} instead. + * + * @param {...any} params + * @returns {LoopNode} + */ export const loop = ( ...params ) => { // @deprecated, r168 console.warn( 'TSL.LoopNode: loop() has been renamed to Loop().' ); diff --git a/src/nodes/utils/MatcapUVNode.js b/src/nodes/utils/MatcapUVNode.js index ea912bea7f118d..68654e9ac3f63f 100644 --- a/src/nodes/utils/MatcapUVNode.js +++ b/src/nodes/utils/MatcapUVNode.js @@ -3,6 +3,8 @@ import { transformedNormalView } from '../accessors/Normal.js'; import { positionViewDirection } from '../accessors/Position.js'; import { nodeImmutable, vec2, vec3 } from '../tsl/TSLBase.js'; +/** @module MatcapUVNode **/ + /** * Can be used to compute texture coordinates for projecting a * matcap onto a mesh. Used by {@link MeshMatcapNodeMaterial}. @@ -39,4 +41,10 @@ class MatcapUVNode extends TempNode { export default MatcapUVNode; +/** + * TSL function for creating a matcap uv node. + * + * @function + * @returns {MatcapUVNode} + */ export const matcapUV = /*@__PURE__*/ nodeImmutable( MatcapUVNode ); diff --git a/src/nodes/utils/MaxMipLevelNode.js b/src/nodes/utils/MaxMipLevelNode.js index 310321b9c3a213..9404008eee6446 100644 --- a/src/nodes/utils/MaxMipLevelNode.js +++ b/src/nodes/utils/MaxMipLevelNode.js @@ -2,6 +2,8 @@ import UniformNode from '../core/UniformNode.js'; import { NodeUpdateType } from '../core/constants.js'; import { nodeProxy } from '../tsl/TSLBase.js'; +/** @module MatcapUVNode **/ + /** * A special type of uniform node that computes the * maximum mipmap level for a given texture node. @@ -10,7 +12,7 @@ import { nodeProxy } from '../tsl/TSLBase.js'; * const level = maxMipLevel( textureNode ); * ``` * - * @augments UniformNode + * @augments module:UniformNode~UniformNode */ class MaxMipLevelNode extends UniformNode { @@ -92,4 +94,11 @@ class MaxMipLevelNode extends UniformNode { export default MaxMipLevelNode; +/** + * TSL function for creating a max mip level node. + * + * @function + * @param {TextureNode} textureNode - The texture node to compute the max mip level for. + * @returns {MaxMipLevelNode} + */ export const maxMipLevel = /*@__PURE__*/ nodeProxy( MaxMipLevelNode ); diff --git a/src/nodes/utils/RTTNode.js b/src/nodes/utils/RTTNode.js index ca81720d82b408..b5f2e7f442c88d 100644 --- a/src/nodes/utils/RTTNode.js +++ b/src/nodes/utils/RTTNode.js @@ -9,6 +9,8 @@ import { RenderTarget } from '../../core/RenderTarget.js'; import { Vector2 } from '../../math/Vector2.js'; import { HalfFloatType } from '../../constants.js'; +/** @module RTTNode **/ + const _size = /*@__PURE__*/ new Vector2(); /** @@ -17,7 +19,7 @@ const _size = /*@__PURE__*/ new Vector2(); * texture input for their effects. With the helper function `convertToTexture()` which is based * on this module, the node system can automatically ensure texture input if required. * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class RTTNode extends TextureNode { @@ -228,8 +230,28 @@ class RTTNode extends TextureNode { export default RTTNode; +/** + * TSL function for creating a RTT node. + * + * @function + * @param {Node} node - The node to render a texture with. + * @param {Number?} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. + * @param {Number?} [height=null] - The height of the internal render target. + * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @returns {RTTNode} + */ export const rtt = ( node, ...params ) => nodeObject( new RTTNode( nodeObject( node ), ...params ) ); +/** + * TSL function for converting nodes to textures nodes. + * + * @function + * @param {Node} node - The node to render a texture with. + * @param {Number?} [width=null] - The width of the internal render target. If not width is applied, the render target is automatically resized. + * @param {Number?} [height=null] - The height of the internal render target. + * @param {Object} [options={type:HalfFloatType}] - The options for the internal render target. + * @returns {RTTNode} + */ export const convertToTexture = ( node, ...params ) => { if ( node.isTextureNode ) return node; diff --git a/src/nodes/utils/ReflectorNode.js b/src/nodes/utils/ReflectorNode.js index c6bd6e1b5d35f5..a55a22d3133fea 100644 --- a/src/nodes/utils/ReflectorNode.js +++ b/src/nodes/utils/ReflectorNode.js @@ -14,6 +14,8 @@ import { Matrix4 } from '../../math/Matrix4.js'; import { RenderTarget } from '../../core/RenderTarget.js'; import { DepthTexture } from '../../textures/DepthTexture.js'; +/** @module ReflectorNode **/ + const _reflectorPlane = new Plane(); const _normal = new Vector3(); const _reflectorWorldPosition = new Vector3(); @@ -46,7 +48,7 @@ let _inReflector = false; * plane.add( groundReflector.target ); * ``` * - * @augments TextureNode + * @augments module:TextureNode~TextureNode */ class ReflectorNode extends TextureNode { @@ -65,6 +67,8 @@ class ReflectorNode extends TextureNode { * @param {Boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not. * @param {Boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not. * @param {Boolean} [parameters.depth=false] - Whether depth data should be generated or not. + * @param {TextureNode} [parameters.defaultTexture] - The default texture node. + * @param {ReflectorBaseNode} [parameters.reflector] - The reflector base node. */ constructor( parameters = {} ) { @@ -74,7 +78,7 @@ class ReflectorNode extends TextureNode { * A reference to the internal reflector base node which holds the actual implementation. * * @private - * @type {Node?} + * @type {ReflectorBaseNode?} * @default null */ this._reflectorBaseNode = parameters.reflector || new ReflectorBaseNode( this, parameters ); @@ -95,7 +99,7 @@ class ReflectorNode extends TextureNode { /** * A reference to the internal reflector node. * - * @type {Node} + * @type {ReflectorBaseNode} */ get reflector() { @@ -164,7 +168,7 @@ class ReflectorNode extends TextureNode { /** * Holds the actual implementation of the reflector. * - * TOOD: Explain why `ReflectorBaseNode`. Originally the entire logic was implemented + * TODO: Explain why `ReflectorBaseNode`. Originally the entire logic was implemented * in `ReflectorNode`, see #29619. * * @private @@ -260,7 +264,7 @@ class ReflectorBaseNode extends Node { /** * Weak map for managing virtual cameras. * - * @type {WeakMap} + * @type {WeakMap} */ this.virtualCameras = new WeakMap(); @@ -359,7 +363,7 @@ class ReflectorBaseNode extends Node { updateBefore( frame ) { - if ( this.bounces === false && _inReflector ) return; + if ( this.bounces === false && _inReflector ) return false; _inReflector = true; @@ -456,14 +460,17 @@ class ReflectorBaseNode extends Node { const currentRenderTarget = renderer.getRenderTarget(); const currentMRT = renderer.getMRT(); + const currentAutoClear = renderer.autoClear; renderer.setMRT( null ); renderer.setRenderTarget( renderTarget ); + renderer.autoClear = true; renderer.render( scene, virtualCamera ); renderer.setMRT( currentMRT ); renderer.setRenderTarget( currentRenderTarget ); + renderer.autoClear = currentAutoClear; material.visible = true; @@ -473,6 +480,20 @@ class ReflectorBaseNode extends Node { } +/** + * TSL function for creating a reflector node. + * + * @function + * @param {Object} [parameters={}] - An object holding configuration parameters. + * @param {Object3D} [parameters.target=new Object3D()] - The 3D object the reflector is linked to. + * @param {Number} [parameters.resolution=1] - The resolution scale. + * @param {Boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not. + * @param {Boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not. + * @param {Boolean} [parameters.depth=false] - Whether depth data should be generated or not. + * @param {TextureNode} [parameters.defaultTexture] - The default texture node. + * @param {ReflectorBaseNode} [parameters.reflector] - The reflector base node. + * @returns {ReflectorNode} + */ export const reflector = ( parameters ) => nodeObject( new ReflectorNode( parameters ) ); export default ReflectorNode; diff --git a/src/nodes/utils/RemapNode.js b/src/nodes/utils/RemapNode.js index 4e87c7ef82bfe0..ba4f83a43e9a7c 100644 --- a/src/nodes/utils/RemapNode.js +++ b/src/nodes/utils/RemapNode.js @@ -1,6 +1,8 @@ import Node from '../core/Node.js'; import { float, addMethodChaining, nodeProxy } from '../tsl/TSLCore.js'; +/** @module RemapNode **/ + /** * This node allows to remap a node value from one range into another. E.g a value of * `0.4` in the range `[ 0.3, 0.5 ]` should be remapped into the normalized range `[ 0, 1 ]`. @@ -93,7 +95,30 @@ class RemapNode extends Node { export default RemapNode; +/** + * TSL function for creating a remap node. + * + * @function + * @param {Node} node - The node that should be remapped. + * @param {Node} inLowNode - The source or current lower bound of the range. + * @param {Node} inHighNode - The source or current upper bound of the range. + * @param {Node} [outLowNode=float(0)] - The target lower bound of the range. + * @param {Node} [outHighNode=float(1)] - The target upper bound of the range. + * @returns {RemapNode} + */ export const remap = /*@__PURE__*/ nodeProxy( RemapNode, null, null, { doClamp: false } ); + +/** + * TSL function for creating a remap node, but with enabled clamping. + * + * @function + * @param {Node} node - The node that should be remapped. + * @param {Node} inLowNode - The source or current lower bound of the range. + * @param {Node} inHighNode - The source or current upper bound of the range. + * @param {Node} [outLowNode=float(0)] - The target lower bound of the range. + * @param {Node} [outHighNode=float(1)] - The target upper bound of the range. + * @returns {RemapNode} + */ export const remapClamp = /*@__PURE__*/ nodeProxy( RemapNode ); addMethodChaining( 'remap', remap ); diff --git a/src/nodes/utils/RotateNode.js b/src/nodes/utils/RotateNode.js index a8eae3ee2be0a4..33fcadab1005bd 100644 --- a/src/nodes/utils/RotateNode.js +++ b/src/nodes/utils/RotateNode.js @@ -2,6 +2,8 @@ import TempNode from '../core/TempNode.js'; import { nodeProxy, vec4, mat2, mat4 } from '../tsl/TSLBase.js'; import { cos, sin } from '../math/MathNode.js'; +/** @module RotateNode **/ + /** * Applies a rotation to the given position node. * @@ -90,4 +92,13 @@ class RotateNode extends TempNode { export default RotateNode; +/** + * TSL function for creating a rotate node. + * + * @function + * @param {Node} positionNode - The position node. + * @param {Node} rotationNode - Represents the rotation that is applied to the position node. Depending + * on whether the position data are 2D or 3D, the rotation is expressed a single float value or an Euler value. + * @returns {RotateNode} + */ export const rotate = /*@__PURE__*/ nodeProxy( RotateNode ); diff --git a/src/nodes/utils/SpriteSheetUVNode.js b/src/nodes/utils/SpriteSheetUVNode.js index e2a84109dc99f1..a85ef8e88cec42 100644 --- a/src/nodes/utils/SpriteSheetUVNode.js +++ b/src/nodes/utils/SpriteSheetUVNode.js @@ -2,6 +2,8 @@ import Node from '../core/Node.js'; import { uv } from '../accessors/UV.js'; import { nodeProxy, float, vec2 } from '../tsl/TSLBase.js'; +/** @module SpriteSheetUVNode **/ + /** * Can be used to compute texture coordinates for animated sprite sheets. * @@ -77,4 +79,13 @@ class SpriteSheetUVNode extends Node { export default SpriteSheetUVNode; +/** + * TSL function for creating a sprite sheet uv node. + * + * @function + * @param {Node} countNode - The node that defines the number of sprites in the x and y direction (e.g 6x6). + * @param {Node} [uvNode=uv()] - The uv node. + * @param {Node} [frameNode=float()] - The node that defines the current frame/sprite. + * @returns {SpriteSheetUVNode} + */ export const spritesheetUV = /*@__PURE__*/ nodeProxy( SpriteSheetUVNode ); diff --git a/src/nodes/utils/StorageArrayElementNode.js b/src/nodes/utils/StorageArrayElementNode.js index 26748692be5bea..ae2892549869cb 100644 --- a/src/nodes/utils/StorageArrayElementNode.js +++ b/src/nodes/utils/StorageArrayElementNode.js @@ -1,6 +1,8 @@ import { nodeProxy } from '../tsl/TSLBase.js'; import ArrayElementNode from './ArrayElementNode.js'; +/** @module StorageArrayElementNode **/ + /** * This class enables element access on instances of {@link StorageBufferNode}. * In most cases, it is indirectly used when accessing elements with the @@ -117,4 +119,12 @@ class StorageArrayElementNode extends ArrayElementNode { export default StorageArrayElementNode; +/** + * TSL function for creating a storage element node. + * + * @function + * @param {StorageBufferNode} storageBufferNode - The storage buffer node. + * @param {Node} indexNode - The index node that defines the element access. + * @returns {StorageArrayElementNode} + */ export const storageElement = /*@__PURE__*/ nodeProxy( StorageArrayElementNode ); diff --git a/src/nodes/utils/Timer.js b/src/nodes/utils/Timer.js index 38a6118d1d3012..10012c70c3a297 100644 --- a/src/nodes/utils/Timer.js +++ b/src/nodes/utils/Timer.js @@ -26,6 +26,13 @@ export const frameId = /*@__PURE__*/ uniform( 0, 'uint' ).setGroup( renderGroup // Deprecated +/** + * @function + * @deprecated since r170. Use {@link time} instead. + * + * @param {Number} [timeScale=1] - The time scale. + * @returns {UniformNode} + */ export const timerLocal = ( timeScale = 1 ) => { // @deprecated, r170 console.warn( 'TSL: timerLocal() is deprecated. Use "time" instead.' ); @@ -33,6 +40,13 @@ export const timerLocal = ( timeScale = 1 ) => { // @deprecated, r170 }; +/** + * @function + * @deprecated since r170. Use {@link time} instead. + * + * @param {Number} [timeScale=1] - The time scale. + * @returns {UniformNode} + */ export const timerGlobal = ( timeScale = 1 ) => { // @deprecated, r170 console.warn( 'TSL: timerGlobal() is deprecated. Use "time" instead.' ); @@ -40,6 +54,13 @@ export const timerGlobal = ( timeScale = 1 ) => { // @deprecated, r170 }; +/** + * @function + * @deprecated since r170. Use {@link deltaTime} instead. + * + * @param {Number} [timeScale=1] - The time scale. + * @returns {UniformNode} + */ export const timerDelta = ( timeScale = 1 ) => { // @deprecated, r170 console.warn( 'TSL: timerDelta() is deprecated. Use "deltaTime" instead.' ); diff --git a/src/nodes/utils/TriplanarTexturesNode.js b/src/nodes/utils/TriplanarTexturesNode.js index 2d60b3874f82bd..ad80b85059b590 100644 --- a/src/nodes/utils/TriplanarTexturesNode.js +++ b/src/nodes/utils/TriplanarTexturesNode.js @@ -5,6 +5,8 @@ import { positionLocal } from '../accessors/Position.js'; import { texture } from '../accessors/TextureNode.js'; import { nodeProxy, float, vec3 } from '../tsl/TSLBase.js'; +/** @module TriplanarTexturesNode **/ + /** * Can be used for triplanar texture mapping. * @@ -117,5 +119,30 @@ class TriplanarTexturesNode extends Node { export default TriplanarTexturesNode; +/** + * TSL function for creating a triplanar textures node. + * + * @function + * @param {Node} textureXNode - First texture node. + * @param {Node?} [textureYNode=null] - Second texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [textureZNode=null] - Third texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [scaleNode=float(1)] - The scale node. + * @param {Node?} [positionNode=positionLocal] - Vertex positions in local space. + * @param {Node?} [normalNode=normalLocal] - Normals in local space. + * @returns {TriplanarTexturesNode} + */ export const triplanarTextures = /*@__PURE__*/ nodeProxy( TriplanarTexturesNode ); + +/** + * TSL function for creating a triplanar textures node. + * + * @function + * @param {Node} textureXNode - First texture node. + * @param {Node?} [textureYNode=null] - Second texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [textureZNode=null] - Third texture node. When not set, the shader will sample from `textureXNode` instead. + * @param {Node?} [scaleNode=float(1)] - The scale node. + * @param {Node?} [positionNode=positionLocal] - Vertex positions in local space. + * @param {Node?} [normalNode=normalLocal] - Normals in local space. + * @returns {TriplanarTexturesNode} + */ export const triplanarTexture = ( ...params ) => triplanarTextures( ...params ); diff --git a/src/objects/BatchedMesh.js b/src/objects/BatchedMesh.js index 3e0237e82c4b9f..42b4ef27a83a60 100644 --- a/src/objects/BatchedMesh.js +++ b/src/objects/BatchedMesh.js @@ -656,7 +656,7 @@ class BatchedMesh extends Mesh { const instanceInfo = this._instanceInfo; for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) { - if ( instanceInfo[ i ].geometryIndex === geometryId ) { + if ( instanceInfo[ i ].active && instanceInfo[ i ].geometryIndex === geometryId ) { this.deleteInstance( i ); diff --git a/src/objects/ClippingGroup.js b/src/objects/ClippingGroup.js index c5db020386eb60..2ff8cb598a1cee 100644 --- a/src/objects/ClippingGroup.js +++ b/src/objects/ClippingGroup.js @@ -1,15 +1,64 @@ import { Group } from './Group.js'; +/** + * In earlier three.js versions, clipping was defined globally + * on the renderer or on material level. This special version of + * `THREE.Group` allows to encode the clipping state into the scene + * graph. Meaning if you create an instance of this group, all + * descendant 3D objects will be affected by the respective clipping + * planes. + * + * Note: `ClippingGroup` can only be used with `WebGPURenderer`. + * + * @augments Group + */ class ClippingGroup extends Group { + /** + * Constructs a new clipping group. + */ constructor() { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isClippingGroup = true; + + /** + * An array with clipping planes. + * + * @type {Array} + */ this.clippingPlanes = []; + + /** + * Whether clipping should be enabled or not. + * + * @type {Boolean} + * @default true + */ this.enabled = true; + + /** + * Whether the intersection of the clipping planes is used to clip objects, rather than their union. + * + * @type {Boolean} + * @default false + */ this.clipIntersection = false; + + /** + * Whether shadows should be clipped or not. + * + * @type {Boolean} + * @default false + */ this.clipShadows = false; } diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 05fdd5e9a249ad..99f00248376f53 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -1272,7 +1272,7 @@ class WebGLRenderer { // - if ( _currentRenderTarget !== null ) { + if ( _currentRenderTarget !== null && _currentActiveMipmapLevel === 0 ) { // resolve multisample renderbuffers to a single-sample texture if necessary @@ -2267,6 +2267,7 @@ class WebGLRenderer { }; + const _scratchFrameBuffer = _gl.createFramebuffer(); this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { _currentRenderTarget = renderTarget; @@ -2375,6 +2376,14 @@ class WebGLRenderer { } + // Use a scratch frame buffer if rendering to a mip level to avoid depth buffers + // being bound that are different sizes. + if ( activeMipmapLevel !== 0 ) { + + framebuffer = _scratchFrameBuffer; + + } + const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); if ( framebufferBound && useDefaultFramebuffer ) { @@ -2395,8 +2404,15 @@ class WebGLRenderer { } else if ( isRenderTarget3D ) { const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); + const layer = activeCubeFace; + _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel, layer ); + + } else if ( renderTarget !== null && activeMipmapLevel !== 0 ) { + + // Only bind the frame buffer if we are using a scratch frame buffer to render to a mipmap. + // If we rebind the texture when using a multi sample buffer then an error about inconsistent samples will be thrown. + const textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, textureProperties.__webglTexture, activeMipmapLevel ); } diff --git a/src/renderers/common/Animation.js b/src/renderers/common/Animation.js index ae626f97e21382..195bc2bdcd4012 100644 --- a/src/renderers/common/Animation.js +++ b/src/renderers/common/Animation.js @@ -1,16 +1,63 @@ + +/** + * This module manages the internal animation loop of the renderer. + * + * @private + */ class Animation { + /** + * Constructs a new animation loop management component. + * + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( nodes, info ) { + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; + /** + * A reference to the context from `requestAnimationFrame()` can + * be called (usually `window`). + * + * @type {Window|XRSession} + */ this._context = self; + + /** + * The user-defined animation loop. + * + * @type {Function?} + * @default null + */ this._animationLoop = null; + + /** + * The requestId which is returned from the `requestAnimationFrame()` call. + * Can be used to cancel the stop the animation loop. + * + * @type {Number?} + * @default null + */ this._requestId = null; } + /** + * Starts the internal animation loop. + */ start() { const update = ( time, frame ) => { @@ -31,6 +78,9 @@ class Animation { } + /** + * Stops the internal animation loop. + */ stop() { this._context.cancelAnimationFrame( this._requestId ); @@ -39,18 +89,31 @@ class Animation { } + /** + * Defines the user-level animation loop. + * + * @param {Function} callback - The animation loop. + */ setAnimationLoop( callback ) { this._animationLoop = callback; } + /** + * Defines the context in which `requestAnimationFrame()` is executed. + * + * @param {Window|XRSession} context - The context to set. + */ setContext( context ) { this._context = context; } + /** + * Frees all internal resources and stops the animation loop. + */ dispose() { this.stop(); diff --git a/src/renderers/common/Attributes.js b/src/renderers/common/Attributes.js index 0f80a46fe72619..d0cd8fcb21ab0c 100644 --- a/src/renderers/common/Attributes.js +++ b/src/renderers/common/Attributes.js @@ -3,16 +3,38 @@ import { AttributeType } from './Constants.js'; import { DynamicDrawUsage } from '../../constants.js'; +/** + * This renderer module manages geometry attributes. + * + * @private + * @augments DataMap + */ class Attributes extends DataMap { + /** + * Constructs a new attribute management component. + * + * @param {Backend} backend - The renderer's backend. + */ constructor( backend ) { super(); + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; } + /** + * Deletes the data for the given attribute. + * + * @param {BufferAttribute} attribute - The attribute. + * @return {Object} The deleted attribute data. + */ delete( attribute ) { const attributeData = super.delete( attribute ); @@ -27,6 +49,13 @@ class Attributes extends DataMap { } + /** + * Updates the given attribute. This method creates attribute buffers + * for new attributes and updates data for existing ones. + * + * @param {BufferAttribute} attribute - The attribute to update. + * @param {Number} type - The attribute type. + */ update( attribute, type ) { const data = this.get( attribute ); @@ -69,6 +98,13 @@ class Attributes extends DataMap { } + /** + * Utility method for handling interleaved buffer attributes correctly. + * To process them, their `InterleavedBuffer` is returned. + * + * @param {BufferAttribute} attribute - The attribute. + * @return {BufferAttribute|InterleavedBuffer} + */ _getBufferAttribute( attribute ) { if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; diff --git a/src/renderers/common/Backend.js b/src/renderers/common/Backend.js index da67772f88a27c..415545fdb8ad0a 100644 --- a/src/renderers/common/Backend.js +++ b/src/renderers/common/Backend.js @@ -1,144 +1,542 @@ -let vector2 = null; -let vector4 = null; -let color4 = null; +let _vector2 = null; +let _color4 = null; import Color4 from './Color4.js'; import { Vector2 } from '../../math/Vector2.js'; -import { Vector4 } from '../../math/Vector4.js'; import { createCanvasElement } from '../../utils.js'; import { REVISION } from '../../constants.js'; +/** + * Most of the rendering related logic is implemented in the + * {@link module:Renderer} module and related management components. + * Sometimes it is required though to execute commands which are + * specific to the current 3D backend (which is WebGPU or WebGL 2). + * This abstract base class defines an interface that encapsulates + * all backend-related logic. Derived classes for each backend must + * implement the interface. + * + * @abstract + * @private + */ class Backend { + /** + * Constructs a new backend. + * + * @param {Object} parameters - An object holding parameters for the backend. + */ constructor( parameters = {} ) { + /** + * The parameters of the backend. + * + * @type {Object} + */ this.parameters = Object.assign( {}, parameters ); + + /** + * This weak map holds backend-specific data of objects + * like textures, attributes or render targets. + * + * @type {WeakMap} + */ this.data = new WeakMap(); + + /** + * A reference to the renderer. + * + * @type {Renderer?} + * @default null + */ this.renderer = null; + + /** + * A reference to the canvas element the renderer is drawing to. + * + * @type {(HTMLCanvasElement|OffscreenCanvas)?} + * @default null + */ this.domElement = null; } + /** + * Initializes the backend so it is ready for usage. Concrete backends + * are supposed to implement their rendering context creation and related + * operations in this method. + * + * @async + * @param {Renderer} renderer - The renderer. + * @return {Promise} A Promise that resolves when the backend has been initialized. + */ async init( renderer ) { this.renderer = renderer; } - // render context + /** + * The coordinate system of the backend. + * + * @abstract + * @type {Number} + * @readonly + */ + get coordinateSystem() {} - begin( /*renderContext*/ ) { } + // render context - finish( /*renderContext*/ ) { } + /** + * This method is executed at the beginning of a render call and + * can be used by the backend to prepare the state for upcoming + * draw calls. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + */ + beginRender( /*renderContext*/ ) {} + + /** + * This method is executed at the end of a render call and + * can be used by the backend to finalize work after draw + * calls. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + */ + finishRender( /*renderContext*/ ) {} + + /** + * This method is executed at the beginning of a compute call and + * can be used by the backend to prepare the state for upcoming + * compute tasks. + * + * @abstract + * @param {Node|Array} computeGroup - The compute node(s). + */ + beginCompute( /*computeGroup*/ ) {} + + /** + * This method is executed at the end of a compute call and + * can be used by the backend to finalize work after compute + * tasks. + * + * @abstract + * @param {Node|Array} computeGroup - The compute node(s). + */ + finishCompute( /*computeGroup*/ ) {} // render object + /** + * Executes a draw command for the given render object. + * + * @abstract + * @param {RenderObject} renderObject - The render object to draw. + * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. + */ draw( /*renderObject, info*/ ) { } + // compute node + + /** + * Executes a compute command for the given compute node. + * + * @abstract + * @param {Node|Array} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @param {ComputePipeline} computePipeline - The compute pipeline. + */ + compute( /*computeGroup, computeNode, computeBindings, computePipeline*/ ) { } + // program + /** + * Creates a shader program from the given programmable stage. + * + * @abstract + * @param {ProgrammableStage} program - The programmable stage. + */ createProgram( /*program*/ ) { } + /** + * Destroys the shader program of the given programmable stage. + * + * @abstract + * @param {ProgrammableStage} program - The programmable stage. + */ destroyProgram( /*program*/ ) { } // bindings - createBindings( /*bingGroup, bindings*/ ) { } - - updateBindings( /*bingGroup, bindings*/ ) { } + /** + * Creates bindings from the given bind group definition. + * + * @abstract + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + createBindings( /*bindGroup, bindings, cacheIndex, version*/ ) { } + + /** + * Updates the given bind group definition. + * + * @abstract + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + updateBindings( /*bindGroup, bindings, cacheIndex, version*/ ) { } + + /** + * Updates a buffer binding. + * + * @abstract + * @param {Buffer} binding - The buffer binding to update. + */ + updateBinding( /*binding*/ ) { } // pipeline - createRenderPipeline( /*renderObject*/ ) { } - - createComputePipeline( /*computeNode, pipeline*/ ) { } - - destroyPipeline( /*pipeline*/ ) { } + /** + * Creates a render pipeline for the given render object. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ + createRenderPipeline( /*renderObject, promises*/ ) { } + + /** + * Creates a compute pipeline for the given compute node. + * + * @abstract + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ + createComputePipeline( /*computePipeline, bindings*/ ) { } // cache key - needsRenderUpdate( /*renderObject*/ ) { } // return Boolean ( fast test ) - - getRenderCacheKey( /*renderObject*/ ) { } // return String + /** + * Returns `true` if the render pipeline requires an update. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render pipeline requires an update or not. + */ + needsRenderUpdate( /*renderObject*/ ) { } + + /** + * Returns a cache key that is used to identify render pipelines. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @return {String} The cache key. + */ + getRenderCacheKey( /*renderObject*/ ) { } // node builder - createNodeBuilder( /*renderObject*/ ) { } // return NodeBuilder (ADD IT) + /** + * Returns a node builder for the given render object. + * + * @abstract + * @param {RenderObject} renderObject - The render object. + * @param {Renderer} renderer - The renderer. + * @return {NodeBuilder} The node builder. + */ + createNodeBuilder( /*renderObject, renderer*/ ) { } // textures + /** + * Creates a GPU sampler for the given texture. + * + * @abstract + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( /*texture*/ ) { } + /** + * Destroys the GPU sampler for the given texture. + * + * @abstract + * @param {Texture} texture - The texture to destroy the sampler for. + */ + destroySampler( /*texture*/ ) {} + + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @abstract + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( /*texture*/ ) { } - createTexture( /*texture*/ ) { } - - copyTextureToBuffer( /*texture, x, y, width, height*/ ) {} + /** + * Defines a texture on the GPU for the given texture object. + * + * @abstract + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ + createTexture( /*texture, options={}*/ ) { } + + /** + * Uploads the updated texture data to the GPU. + * + * @abstract + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ + updateTexture( /*texture, options = {}*/ ) { } + + /** + * Generates mipmaps for the given texture. + * + * @abstract + * @param {Texture} texture - The texture. + */ + generateMipmaps( /*texture*/ ) { } + + /** + * Destroys the GPU data for the given texture object. + * + * @abstract + * @param {Texture} texture - The texture. + */ + destroyTexture( /*texture*/ ) { } + + /** + * Returns texture data as a typed array. + * + * @abstract + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ + async copyTextureToBuffer( /*texture, x, y, width, height, faceIndex*/ ) {} + + /** + * Copies data of the given source texture to the given destination texture. + * + * @abstract + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ + copyTextureToTexture( /*srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0*/ ) {} + + /** + * Copies the current bound framebuffer to the given texture. + * + * @abstract + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ + copyFramebufferToTexture( /*texture, renderContext, rectangle*/ ) {} // attributes + /** + * Creates the GPU buffer of a shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute. + */ createAttribute( /*attribute*/ ) { } + /** + * Creates the GPU buffer of an indexed shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The indexed buffer attribute. + */ createIndexAttribute( /*attribute*/ ) { } + /** + * Creates the GPU buffer of a storage attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute. + */ + createStorageAttribute( /*attribute*/ ) { } + + /** + * Updates the GPU buffer of a shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute to update. + */ updateAttribute( /*attribute*/ ) { } + /** + * Destroys the GPU buffer of a shader attribute. + * + * @abstract + * @param {BufferAttribute} attribute - The buffer attribute to destroy. + */ destroyAttribute( /*attribute*/ ) { } // canvas + /** + * Returns the backend's rendering context. + * + * @abstract + * @return {Object} The rendering context. + */ getContext() { } + /** + * Backends can use this method if they have to run + * logic when the renderer gets resized. + * + * @abstract + */ updateSize() { } - // utils - - resolveTimestampAsync( /*renderContext, type*/ ) { } + /** + * Updates the viewport with the values from the given render context. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + */ + updateViewport( /*renderContext*/ ) {} - 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 ); - - } + // utils + /** + * Returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. Backends must implement this method by using + * a Occlusion Query API. + * + * @abstract + * @param {RenderContext} renderContext - The render context. + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ + isOccluded( /*renderContext, object*/ ) {} + + /** + * Resolves the time stamp for the given render context and type. + * + * @async + * @abstract + * @param {RenderContext} renderContext - The render context. + * @param {String} type - The render context. + * @return {Promise} A Promise that resolves when the time stamp has been computed. + */ + async resolveTimestampAsync( /*renderContext, type*/ ) { } + + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @abstract + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ + async waitForGPU() {} + + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ + async getArrayBufferAsync( /* attribute */ ) {} + + /** + * Checks if the given feature is supported by the backend. + * + * @async + * @abstract + * @param {String} name - The feature's name. + * @return {Promise} A Promise that resolves with a bool that indicates whether the feature is supported or not. + */ + async hasFeatureAsync( /*name*/ ) { } + + /** + * Checks if the given feature is supported by the backend. + * + * @abstract + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ + hasFeature( /*name*/ ) {} + + /** + * Returns the maximum anisotropy texture filtering value. + * + * @abstract + * @return {Number} The maximum anisotropy texture filtering value. + */ + getMaxAnisotropy() {} + + /** + * Returns the drawing buffer size. + * + * @return {Vector2} The drawing buffer size. + */ getDrawingBufferSize() { - vector2 = vector2 || new Vector2(); + _vector2 = _vector2 || new Vector2(); - return this.renderer.getDrawingBufferSize( vector2 ); - - } - - getScissor() { - - vector4 = vector4 || new Vector4(); - - return this.renderer.getScissor( vector4 ); + return this.renderer.getDrawingBufferSize( _vector2 ); } + /** + * Defines the scissor test. + * + * @abstract + * @param {Boolean} boolean - Whether the scissor test should be enabled or not. + */ setScissorTest( /*boolean*/ ) { } + /** + * Returns the clear color and alpha into a single + * color object. + * + * @return {Color4} The clear color. + */ getClearColor() { const renderer = this.renderer; - color4 = color4 || new Color4(); + _color4 = _color4 || new Color4(); - renderer.getClearColor( color4 ); + renderer.getClearColor( _color4 ); - color4.getRGB( color4, this.renderer.currentColorSpace ); + _color4.getRGB( _color4, this.renderer.currentColorSpace ); - return color4; + return _color4; } + /** + * Returns the DOM element. If no DOM element exists, the backend + * creates a new one. + * + * @return {HTMLCanvasElement} The DOM element. + */ getDomElement() { let domElement = this.domElement; @@ -158,14 +556,25 @@ class Backend { } - // resource properties - + /** + * Sets a dictionary for the given object into the + * internal data structure. + * + * @param {Object} object - The object. + * @param {Object} value - The dictionary to set. + */ set( object, value ) { this.data.set( object, value ); } + /** + * Returns the dictionary for the given object. + * + * @param {Object} object - The object. + * @return {Object} The object's dictionary. + */ get( object ) { let map = this.data.get( object ); @@ -181,18 +590,35 @@ class Backend { } + /** + * Checks if the given object has a dictionary + * with data defined. + * + * @param {Object} object - The object. + * @return {Boolean} Whether a dictionary for the given object as been defined or not. + */ has( object ) { return this.data.has( object ); } + /** + * Deletes an object from the internal data structure. + * + * @param {Object} object - The object to delete. + */ delete( object ) { this.data.delete( object ); } + /** + * Frees internal resources. + * + * @abstract + */ dispose() { } } diff --git a/src/renderers/common/Background.js b/src/renderers/common/Background.js index 1a1ed200538f31..97092b3b5a4608 100644 --- a/src/renderers/common/Background.js +++ b/src/renderers/common/Background.js @@ -9,17 +9,50 @@ import { BackSide, LinearSRGBColorSpace } from '../../constants.js'; const _clearColor = /*@__PURE__*/ new Color4(); +/** + * This renderer module manages the background. + * + * @private + * @augments DataMap + */ class Background extends DataMap { + /** + * Constructs a new background management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + */ constructor( renderer, nodes ) { super(); + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; } + /** + * Updates the background for the given scene. Depending on how `Scene.background` + * or `Scene.backgroundNode` are configured, this method might configure a simple clear + * or add a mesh to the render list for rendering the background as a textured plane + * or skybox. + * + * @param {Scene} scene - The scene. + * @param {RenderList} renderList - The current render list. + * @param {RenderContext} renderContext - The current render context. + */ update( scene, renderList, renderContext ) { const renderer = this.renderer; @@ -60,7 +93,7 @@ class Background extends DataMap { getTextureLevel: () => backgroundBlurriness } ); - let viewProj = modelViewProjection(); + let viewProj = modelViewProjection; viewProj = viewProj.setZ( viewProj.w ); const nodeMaterial = new NodeMaterial(); diff --git a/src/renderers/common/BindGroup.js b/src/renderers/common/BindGroup.js index fd350b2328dc92..8255fe9cc73bd8 100644 --- a/src/renderers/common/BindGroup.js +++ b/src/renderers/common/BindGroup.js @@ -1,14 +1,57 @@ let _id = 0; +/** + * A bind group represents a collection of bindings and thus a collection + * or resources. Bind groups are assigned to pipelines to provide them + * with the required resources (like uniform buffers or textures). + * + * @private + */ class BindGroup { + /** + * Constructs a new bind group. + * + * @param {String} name - The bind group's name. + * @param {Array} bindings - An array of bindings. + * @param {Number} index - The group index. + * @param {Array} bindingsReference - An array of reference bindings. + */ constructor( name = '', bindings = [], index = 0, bindingsReference = [] ) { + /** + * The bind group's name. + * + * @type {String} + */ this.name = name; + + /** + * An array of bindings. + * + * @type {Array} + */ this.bindings = bindings; + + /** + * The group index. + * + * @type {Number} + */ this.index = index; + + /** + * An array of reference bindings. + * + * @type {Array} + */ this.bindingsReference = bindingsReference; + /** + * The group's ID. + * + * @type {Number} + */ this.id = _id ++; } diff --git a/src/renderers/common/Binding.js b/src/renderers/common/Binding.js index 9f60f4e41c2ecc..1bb65735b2ec0d 100644 --- a/src/renderers/common/Binding.js +++ b/src/renderers/common/Binding.js @@ -1,19 +1,54 @@ +/** + * A binding represents the connection between a resource (like a texture, sampler + * or uniform buffer) and the resource definition in a shader stage. + * + * This module is an abstract base class for all concrete bindings types. + * + * @abstract + * @private + */ class Binding { + /** + * Constructs a new binding. + * + * @param {String} [name=''] - The binding's name. + */ constructor( name = '' ) { + /** + * The binding's name. + * + * @type {String} + */ this.name = name; + /** + * A bitmask that defines in what shader stages the + * binding's resource is accessible. + * + * @type {Number} + */ this.visibility = 0; } + /** + * Makes sure binding's resource is visible for the given shader stage. + * + * @param {Number} visibility - The shader stage. + */ setVisibility( visibility ) { this.visibility |= visibility; } + /** + * Clones the binding. + * + * @return {Binding} The cloned binding. + */ clone() { return Object.assign( new this.constructor(), this ); diff --git a/src/renderers/common/Bindings.js b/src/renderers/common/Bindings.js index ca942d20714907..31800450305ed3 100644 --- a/src/renderers/common/Bindings.js +++ b/src/renderers/common/Bindings.js @@ -1,23 +1,80 @@ import DataMap from './DataMap.js'; import { AttributeType } from './Constants.js'; +/** + * This renderer module manages the bindings of the renderer. + * + * @private + * @augments DataMap + */ class Bindings extends DataMap { + /** + * Constructs a new bindings management component. + * + * @param {Backend} backend - The renderer's backend. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Textures} textures - Renderer component for managing textures. + * @param {Attributes} attributes - Renderer component for managing attributes. + * @param {Pipelines} pipelines - Renderer component for managing pipelines. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( backend, nodes, textures, attributes, pipelines, info ) { super(); + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * Renderer component for managing textures. + * + * @type {Textures} + */ this.textures = textures; + + /** + * Renderer component for managing pipelines. + * + * @type {Pipelines} + */ this.pipelines = pipelines; + + /** + * Renderer component for managing attributes. + * + * @type {Attributes} + */ this.attributes = attributes; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; this.pipelines.bindings = this; // assign bindings to pipelines } + /** + * Returns the bind groups for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Array} The bind groups. + */ getForRender( renderObject ) { const bindings = renderObject.getBindings(); @@ -44,6 +101,12 @@ class Bindings extends DataMap { } + /** + * Returns the bind groups for the given compute node. + * + * @param {Node} computeNode - The compute node. + * @return {Array} The bind groups. + */ getForCompute( computeNode ) { const bindings = this.nodes.getForCompute( computeNode ).bindings; @@ -68,18 +131,33 @@ class Bindings extends DataMap { } + /** + * Updates the bindings for the given compute node. + * + * @param {Node} computeNode - The compute node. + */ updateForCompute( computeNode ) { this._updateBindings( this.getForCompute( computeNode ) ); } + /** + * Updates the bindings for the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { this._updateBindings( this.getForRender( renderObject ) ); } + /** + * Updates the given array of bindings. + * + * @param {Array} bindings - The bind groups. + */ _updateBindings( bindings ) { for ( const bindGroup of bindings ) { @@ -90,6 +168,11 @@ class Bindings extends DataMap { } + /** + * Initializes the given bind group. + * + * @param {BindGroup} bindGroup - The bind group to initialize. + */ _init( bindGroup ) { for ( const binding of bindGroup.bindings ) { @@ -111,6 +194,12 @@ class Bindings extends DataMap { } + /** + * Updates the given bind group. + * + * @param {BindGroup} bindGroup - The bind group to update. + * @param {Array} bindings - The bind groups. + */ _update( bindGroup, bindings ) { const { backend } = this; @@ -128,7 +217,10 @@ class Bindings extends DataMap { const updated = this.nodes.updateGroup( binding ); - if ( ! updated ) continue; + // every uniforms group is a uniform buffer. So if no update is required, + // we move one with the next binding. Otherwise the next if block will update the group. + + if ( updated === false ) continue; } diff --git a/src/renderers/common/Buffer.js b/src/renderers/common/Buffer.js index a9a664396f0db9..adbe2cefc5c07d 100644 --- a/src/renderers/common/Buffer.js +++ b/src/renderers/common/Buffer.js @@ -1,32 +1,81 @@ import Binding from './Binding.js'; import { getFloatLength } from './BufferUtils.js'; +/** + * Represents a buffer binding type. + * + * @private + * @abstract + * @augments Binding + */ class Buffer extends Binding { + /** + * Constructs a new buffer. + * + * @param {String} name - The buffer's name. + * @param {TypedArray} [buffer=null] - The buffer. + */ constructor( name, buffer = null ) { super( name ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBuffer = true; + /** + * The bytes per element. + * + * @type {Number} + */ this.bytesPerElement = Float32Array.BYTES_PER_ELEMENT; + /** + * A reference to the internal buffer. + * + * @private + * @type {TypedArray} + */ this._buffer = buffer; } + /** + * The buffer's byte length. + * + * @type {Number} + * @readonly + */ get byteLength() { return getFloatLength( this._buffer.byteLength ); } + /** + * A reference to the internal buffer. + * + * @type {Float32Array} + * @readonly + */ get buffer() { return this._buffer; } + /** + * Updates the binding. + * + * @return {Boolean} Whether the buffer has been updated and must be + * uploaded to the GPU. + */ update() { return true; diff --git a/src/renderers/common/BufferUtils.js b/src/renderers/common/BufferUtils.js index 0cbdd4c773d3cc..d3df612ed3032a 100644 --- a/src/renderers/common/BufferUtils.js +++ b/src/renderers/common/BufferUtils.js @@ -1,5 +1,15 @@ import { GPU_CHUNK_BYTES } from './Constants.js'; +/** @module BufferUtils **/ + +/** + * This function is usually called with the length in bytes of an array buffer. + * It returns an padded value which ensure chunk size alignment according to STD140 layout. + * + * @function + * @param {Number} floatLength - The buffer length. + * @return {Number} The padded length. + */ function getFloatLength( floatLength ) { // ensure chunk size alignment (STD140 layout) @@ -8,6 +18,15 @@ function getFloatLength( floatLength ) { } +/** + * Given the count of vectors and their vector length, this function computes + * a total length in bytes with buffer alignment according to STD140 layout. + * + * @function + * @param {Number} count - The number of vectors. + * @param {Number} [vectorLength=4] - The vector length. + * @return {Number} The padded length. + */ function getVectorLength( count, vectorLength = 4 ) { const strideLength = getStrideLength( vectorLength ); @@ -18,6 +37,14 @@ function getVectorLength( count, vectorLength = 4 ) { } +/** + * This function is called with a vector length and ensure the computed length + * matches a predefined stride (in this case `4`). + * + * @function + * @param {Number} vectorLength - The vector length. + * @return {Number} The padded length. + */ function getStrideLength( vectorLength ) { const strideLength = 4; diff --git a/src/renderers/common/BundleGroup.js b/src/renderers/common/BundleGroup.js index 9b2dff9f2888ad..5da552ef9dc277 100644 --- a/src/renderers/common/BundleGroup.js +++ b/src/renderers/common/BundleGroup.js @@ -1,20 +1,77 @@ import { Group } from '../../objects/Group.js'; +/** + * A specialized group which enables applications access to the + * Render Bundle API of WebGPU. The group with all its descendant nodes + * are considered as one render bundle and processed as such by + * the renderer. + * + * This module is only fully supported by `WebGPURenderer` with a WebGPU backend. + * With a WebGL backend, the group can technically be rendered but without + * any performance improvements. + * + * @augments Group + */ class BundleGroup extends Group { + /** + * Constructs a new bundle group. + */ constructor() { super(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isBundleGroup = true; + /** + * This property is only relevant for detecting types + * during serialization/deserialization. It should always + * match the class name. + * + * @type {String} + * @readonly + * @default 'BundleGroup' + */ this.type = 'BundleGroup'; + /** + * Whether the bundle is static or not. When set to `true`, the structure + * is assumed to be static and does not change. E.g. no new objects are + * added to the group + * + * If a change is required, an update can still be forced by setting the + * `needsUpdate` flag to `true`. + * + * @type {Boolean} + * @default true + */ this.static = true; + + /** + * The bundle group's version. + * + * @type {Number} + * @readonly + * @default 0 + */ this.version = 0; } + /** + * Set this property to `true` when the bundle group has changed. + * + * @type {Boolean} + * @default false + * @param {Boolean} value + */ set needsUpdate( value ) { if ( value === true ) this.version ++; diff --git a/src/renderers/common/ChainMap.js b/src/renderers/common/ChainMap.js index 5a3bbface0e481..02203123518275 100644 --- a/src/renderers/common/ChainMap.js +++ b/src/renderers/common/ChainMap.js @@ -1,16 +1,38 @@ -export default class ChainMap { - +/** + * Data structure for the renderer. It allows defining values + * with chained, hierarchical keys. Keys are meant to be + * objects since the module internally works with Weak Maps + * for performance reasons. + * + * @private + */ +class ChainMap { + + /** + * Constructs a new Chain Map. + */ constructor() { + /** + * The root Weak Map. + * + * @type {WeakMap} + */ this.weakMap = new WeakMap(); } + /** + * Returns the value for the given array of keys. + * + * @param {Array} keys - List of keys. + * @return {Any} The value. Returns `undefined` if no value was found. + */ get( keys ) { let map = this.weakMap; - for ( let i = 0; i < keys.length; i ++ ) { + for ( let i = 0; i < keys.length - 1; i ++ ) { map = map.get( keys[ i ] ); @@ -22,11 +44,18 @@ export default class ChainMap { } + /** + * Sets the value for the given keys. + * + * @param {Array} keys - List of keys. + * @param {Any} value - The value to set. + * @return {ChainMap} A reference to this Chain Map. + */ set( keys, value ) { let map = this.weakMap; - for ( let i = 0; i < keys.length; i ++ ) { + for ( let i = 0; i < keys.length - 1; i ++ ) { const key = keys[ i ]; @@ -36,15 +65,23 @@ export default class ChainMap { } - return map.set( keys[ keys.length - 1 ], value ); + map.set( keys[ keys.length - 1 ], value ); + + return this; } + /** + * Deletes a value for the given keys. + * + * @param {Array} keys - The keys. + * @return {Boolean} Returns `true` if the value has been removed successfully and `false` if the value has not be found. + */ delete( keys ) { let map = this.weakMap; - for ( let i = 0; i < keys.length; i ++ ) { + for ( let i = 0; i < keys.length - 1; i ++ ) { map = map.get( keys[ i ] ); @@ -57,3 +94,5 @@ export default class ChainMap { } } + +export default ChainMap; diff --git a/src/renderers/common/ClippingContext.js b/src/renderers/common/ClippingContext.js index 220a02976f079c..f19c1444d05277 100644 --- a/src/renderers/common/ClippingContext.js +++ b/src/renderers/common/ClippingContext.js @@ -4,41 +4,110 @@ import { Vector4 } from '../../math/Vector4.js'; const _plane = /*@__PURE__*/ new Plane(); +/** + * Represents the state that is used to perform clipping via clipping planes. + * There is a default clipping context for each render context. When the + * scene holds instances of `ClippingGroup`, there will be a context for each + * group. + * + * @private + */ class ClippingContext { + /** + * Constructs a new clipping context. + * + * @param {ClippingContext?} [parentContext=null] - A reference to the parent clipping context. + */ constructor( parentContext = null ) { + /** + * The clipping context's version. + * + * @type {Number} + * @readonly + */ this.version = 0; + /** + * Whether the intersection of the clipping planes is used to clip objects, rather than their union. + * + * @type {Boolean?} + * @default null + */ this.clipIntersection = null; - this.cacheKey = ''; - - - if ( parentContext === null ) { - this.intersectionPlanes = []; - this.unionPlanes = []; - - this.viewNormalMatrix = new Matrix3(); - this.clippingGroupContexts = new WeakMap(); + /** + * The clipping context's cache key. + * + * @type {String} + */ + this.cacheKey = ''; - this.shadowPass = false; + /** + * Whether the shadow pass is active or not. + * + * @type {Boolean} + * @default false + */ + this.shadowPass = false; + + /** + * The view normal matrix. + * + * @type {Matrix3} + */ + this.viewNormalMatrix = new Matrix3(); + + /** + * Internal cache for maintaining clipping contexts. + * + * @type {WeakMap} + */ + this.clippingGroupContexts = new WeakMap(); + + /** + * The intersection planes. + * + * @type {Array} + */ + this.intersectionPlanes = []; + + /** + * The intersection planes. + * + * @type {Array} + */ + this.unionPlanes = []; + + /** + * The version of the clipping context's parent context. + * + * @type {Number?} + * @readonly + */ + this.parentVersion = null; - } else { + if ( parentContext !== null ) { this.viewNormalMatrix = parentContext.viewNormalMatrix; this.clippingGroupContexts = parentContext.clippingGroupContexts; this.shadowPass = parentContext.shadowPass; - this.viewMatrix = parentContext.viewMatrix; } - this.parentVersion = null; - } + /** + * Projects the given source clipping planes and writes the result into the + * destination array. + * + * @param {Array} source - The source clipping planes. + * @param {Array} destination - The destination. + * @param {Number} offset - The offset. + */ projectPlanes( source, destination, offset ) { const l = source.length; @@ -59,15 +128,27 @@ class ClippingContext { } + /** + * Updates the root clipping context of a scene. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera that is used to render the scene. + */ updateGlobal( scene, camera ) { - this.shadowPass = ( scene.overrideMaterial !== null && scene.overrideMaterial.isShadowNodeMaterial ); + this.shadowPass = ( scene.overrideMaterial !== null && scene.overrideMaterial.isShadowPassMaterial ); this.viewMatrix = camera.matrixWorldInverse; this.viewNormalMatrix.getNormalMatrix( this.viewMatrix ); } + /** + * Updates the clipping context. + * + * @param {ClippingContext} parentContext - The parent context. + * @param {ClippingGroup} clippingGroup - The clipping group this context belongs to. + */ update( parentContext, clippingGroup ) { let update = false; @@ -139,6 +220,12 @@ class ClippingContext { } + /** + * Returns a clipping context for the given clipping group. + * + * @param {ClippingGroup} clippingGroup - The clipping group. + * @return {ClippingContext} The clipping context. + */ getGroupContext( clippingGroup ) { if ( this.shadowPass && ! clippingGroup.clipShadows ) return this; @@ -158,6 +245,12 @@ class ClippingContext { } + /** + * The count of union clipping planes. + * + * @type {Number} + * @readonly + */ get unionClippingCount() { return this.unionPlanes.length; diff --git a/src/renderers/common/Color4.js b/src/renderers/common/Color4.js index 86c58b1d216f69..065da9559b37a2 100644 --- a/src/renderers/common/Color4.js +++ b/src/renderers/common/Color4.js @@ -1,7 +1,25 @@ import { Color } from '../../math/Color.js'; +/** + * A four-component version of {@link Color} which is internally + * used by the renderer to represents clear color with alpha as + * one object. + * + * @private + * @augments Color + */ class Color4 extends Color { + /** + * Constructs a new four-component color. + * You can also pass a single THREE.Color, hex or + * string argument to this constructor. + * + * @param {Number|String} [r=1] - The red value. + * @param {Number} [g=1] - The green value. + * @param {Number} [b=1] - The blue value. + * @param {Number} [a=1] - The alpha value. + */ constructor( r, g, b, a = 1 ) { super( r, g, b ); @@ -10,6 +28,17 @@ class Color4 extends Color { } + /** + * Overwrites the default to honor alpha. + * You can also pass a single THREE.Color, hex or + * string argument to this method. + * + * @param {Number|String} r - The red value. + * @param {Number} g - The green value. + * @param {Number} b - The blue value. + * @param {Number} [a=1] - The alpha value. + * @return {Color4} A reference to this object. + */ set( r, g, b, a = 1 ) { this.a = a; @@ -18,6 +47,12 @@ class Color4 extends Color { } + /** + * Overwrites the default to honor alpha. + * + * @param {Color4} color - The color to copy. + * @return {Color4} A reference to this object. + */ copy( color ) { if ( color.a !== undefined ) this.a = color.a; @@ -26,6 +61,11 @@ class Color4 extends Color { } + /** + * Overwrites the default to honor alpha. + * + * @return {Color4} The cloned color. + */ clone() { return new this.constructor( this.r, this.g, this.b, this.a ); diff --git a/src/renderers/common/ComputePipeline.js b/src/renderers/common/ComputePipeline.js index 8f29dc4756dbbe..7735939208cbb4 100644 --- a/src/renderers/common/ComputePipeline.js +++ b/src/renderers/common/ComputePipeline.js @@ -1,13 +1,37 @@ import Pipeline from './Pipeline.js'; +/** + * Class for representing compute pipelines. + * + * @private + * @augments Pipeline + */ class ComputePipeline extends Pipeline { + /** + * Constructs a new render pipeline. + * + * @param {String} cacheKey - The pipeline's cache key. + * @param {ProgrammableStage} computeProgram - The pipeline's compute shader. + */ constructor( cacheKey, computeProgram ) { super( cacheKey ); + /** + * The pipeline's compute shader. + * + * @type {ProgrammableStage} + */ this.computeProgram = computeProgram; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isComputePipeline = true; } diff --git a/src/renderers/common/CubeRenderTarget.js b/src/renderers/common/CubeRenderTarget.js index 29bd3a6fbc7822..64987a3ddf6738 100644 --- a/src/renderers/common/CubeRenderTarget.js +++ b/src/renderers/common/CubeRenderTarget.js @@ -12,6 +12,12 @@ import { BackSide, NoBlending, LinearFilter, LinearMipmapLinearFilter } from '.. // @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget +/** + * This class represents a cube render target. It is a special version + * of `WebGLCubeRenderTarget` which is compatible with `WebGPURenderer`. + * + * @augments WebGLCubeRenderTarget + */ class CubeRenderTarget extends WebGLCubeRenderTarget { constructor( size = 1, options = {} ) { @@ -22,6 +28,13 @@ class CubeRenderTarget extends WebGLCubeRenderTarget { } + /** + * Converts the given equirectangular texture to a cube map. + * + * @param {Renderer} renderer - The renderer. + * @param {Texture} texture - The equirectangular texture. + * @return {CubeRenderTarget} A reference to this cube render target. + */ fromEquirectangularTexture( renderer, texture ) { const currentMinFilter = texture.minFilter; diff --git a/src/renderers/common/DataMap.js b/src/renderers/common/DataMap.js index 28e05d1c46edcd..1316c0f1c2d2a3 100644 --- a/src/renderers/common/DataMap.js +++ b/src/renderers/common/DataMap.js @@ -1,11 +1,32 @@ +/** + * Data structure for the renderer. It is intended to manage + * data of objects in dictionaries. + * + * @private + */ class DataMap { + /** + * Constructs a new data map. + */ constructor() { + /** + * `DataMap` internally uses a weak map + * to manage its data. + * + * @type {WeakMap} + */ this.data = new WeakMap(); } + /** + * Returns the dictionary for the given object. + * + * @param {Object} object - The object. + * @return {Object} The dictionary. + */ get( object ) { let map = this.data.get( object ); @@ -21,9 +42,15 @@ class DataMap { } + /** + * Deletes the dictionary for the given object. + * + * @param {Object} object - The object. + * @return {Object?} The deleted dictionary. + */ delete( object ) { - let map; + let map = null; if ( this.data.has( object ) ) { @@ -37,12 +64,21 @@ class DataMap { } + /** + * Returns `true` if the given object has a dictionary defined. + * + * @param {Object} object - The object to test. + * @return {Boolean} Whether a dictionary is defined or not. + */ has( object ) { return this.data.has( object ); } + /** + * Frees internal resources. + */ dispose() { this.data = new WeakMap(); diff --git a/src/renderers/common/Geometries.js b/src/renderers/common/Geometries.js index 271f8a7991c009..3c0848ec3605b3 100644 --- a/src/renderers/common/Geometries.js +++ b/src/renderers/common/Geometries.js @@ -3,6 +3,14 @@ import { AttributeType } from './Constants.js'; import { Uint16BufferAttribute, Uint32BufferAttribute } from '../../core/BufferAttribute.js'; +/** + * Returns `true` if the given array has values that require an Uint32 array type. + * + * @private + * @function + * @param {Array} array - The array to test. + * @return {Boolean} Whether the given array has values that require an Uint32 array type or not. + */ function arrayNeedsUint32( array ) { // assumes larger values usually on last @@ -17,12 +25,28 @@ function arrayNeedsUint32( array ) { } +/** + * Returns the wireframe version for the given geometry. + * + * @private + * @function + * @param {BufferGeometry} geometry - The geometry. + * @return {Number} The version. + */ function getWireframeVersion( geometry ) { return ( geometry.index !== null ) ? geometry.index.version : geometry.attributes.position.version; } +/** + * Returns a wireframe index attribute for the given geometry. + * + * @private + * @function + * @param {BufferGeometry} geometry - The geometry. + * @return {BufferAttribute} The wireframe index attribute. + */ function getWireframeIndex( geometry ) { const indices = []; @@ -67,21 +91,61 @@ function getWireframeIndex( geometry ) { } +/** + * This renderer module manages geometries. + * + * @private + * @augments DataMap + */ class Geometries extends DataMap { + /** + * Constructs a new geometry management component. + * + * @param {Attributes} attributes - Renderer component for managing attributes. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( attributes, info ) { super(); + /** + * Renderer component for managing attributes. + * + * @type {Attributes} + */ this.attributes = attributes; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; + /** + * Weak Map for managing attributes for wireframe rendering. + * + * @type {WeakMap} + */ this.wireframes = new WeakMap(); + /** + * This Weak Map is used to make sure buffer attributes are + * updated only once per render call. + * + * @type {WeakMap} + */ this.attributeCall = new WeakMap(); } + /** + * Returns `true` if the given render object has an initialized geometry. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether if the given render object has an initialized geometry or not. + */ has( renderObject ) { const geometry = renderObject.geometry; @@ -90,6 +154,11 @@ class Geometries extends DataMap { } + /** + * Prepares the geometry of the given render object for rendering. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { if ( this.has( renderObject ) === false ) this.initGeometry( renderObject ); @@ -98,6 +167,11 @@ class Geometries extends DataMap { } + /** + * Initializes the geometry of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ initGeometry( renderObject ) { const geometry = renderObject.geometry; @@ -142,6 +216,11 @@ class Geometries extends DataMap { } + /** + * Updates the geometry attributes of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateAttributes( renderObject ) { // attributes @@ -184,6 +263,12 @@ class Geometries extends DataMap { } + /** + * Updates the given attribute. + * + * @param {BufferAttribute} attribute - The attribute to update. + * @param {Number} type - The attribute type. + */ updateAttribute( attribute, type ) { const callId = this.info.render.calls; @@ -220,12 +305,25 @@ class Geometries extends DataMap { } + /** + * Returns the indirect buffer attribute of the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {BufferAttribute?} The indirect attribute. `null` if no indirect drawing is used. + */ getIndirect( renderObject ) { return renderObject.geometry.indirect; } + /** + * Returns the index of the given render object's geometry. This is implemented + * in a method to return a wireframe index if necessary. + * + * @param {RenderObject} renderObject - The render object. + * @return {BufferAttribute?} The index. Returns `null` for non-indexed geometries. + */ getIndex( renderObject ) { const { geometry, material } = renderObject; diff --git a/src/renderers/common/IndirectStorageBufferAttribute.js b/src/renderers/common/IndirectStorageBufferAttribute.js index aaa2fb7bb668c6..731543f63e35f3 100644 --- a/src/renderers/common/IndirectStorageBufferAttribute.js +++ b/src/renderers/common/IndirectStorageBufferAttribute.js @@ -1,11 +1,34 @@ import StorageBufferAttribute from './StorageBufferAttribute.js'; +/** + * This special type of buffer attribute is intended for compute shaders. + * It can be used to encode draw parameters for indirect draw calls. + * + * Note: This type of buffer attribute can only be used with `WebGPURenderer` + * and a WebGPU backend. + * + * @augments StorageBufferAttribute + */ class IndirectStorageBufferAttribute extends StorageBufferAttribute { - constructor( array, itemSize ) { + /** + * Constructs a new storage buffer attribute. + * + * @param {Number|Uint32Array} count - The item count. It is also valid to pass a `Uint32Array` as an argument. + * The subsequent parameter is then obsolete. + * @param {Number} itemSize - The item size. + */ + constructor( count, itemSize ) { - super( array, itemSize, Uint32Array ); + super( count, itemSize, Uint32Array ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isIndirectStorageBufferAttribute = true; } diff --git a/src/renderers/common/Info.js b/src/renderers/common/Info.js index 2de51487092447..4019720cd0105a 100644 --- a/src/renderers/common/Info.js +++ b/src/renderers/common/Info.js @@ -1,12 +1,61 @@ +/** + * This renderer module provides a series of statistical information + * about the GPU memory and the rendering process. Useful for debugging + * and monitoring. + */ class Info { + /** + * Constructs a new info component. + */ constructor() { + /** + * Whether frame related metrics should automatically + * be resetted or not. This property should be set to `false` + * by apps which manage their own animation loop. They must + * then call `renderer.info.reset()` once per frame manually. + * + * @type {Boolean} + * @default true + */ this.autoReset = true; + /** + * The current frame ID. This ID is managed + * by `NodeFrame`. + * + * @type {Number} + * @readonly + * @default 0 + */ this.frame = 0; + + /** + * The number of render calls since the + * app has been started. + * + * @type {Number} + * @readonly + * @default 0 + */ this.calls = 0; + /** + * Render related metrics. + * + * @type {Object} + * @readonly + * @property {Number} calls - The number of render calls since the app has been started. + * @property {Number} frameCalls - The number of render calls of the current frame. + * @property {Number} drawCalls - The number of draw calls of the current frame. + * @property {Number} triangles - The number of rendered triangle primitives of the current frame. + * @property {Number} points - The number of rendered point primitives of the current frame. + * @property {Number} lines - The number of rendered line primitives of the current frame. + * @property {Number} previousFrameCalls - The number of render calls of the previous frame. + * @property {Number} timestamp - The timestamp of the frame when using `renderer.renderAsync()`. + * @property {Number} timestampCalls - The number of render calls using `renderer.renderAsync()`. + */ this.render = { calls: 0, frameCalls: 0, @@ -19,6 +68,17 @@ class Info { timestampCalls: 0 }; + /** + * Compute related metrics. + * + * @type {Object} + * @readonly + * @property {Number} calls - The number of compute calls since the app has been started. + * @property {Number} frameCalls - The number of compute calls of the current frame. + * @property {Number} previousFrameCalls - The number of compute calls of the previous frame. + * @property {Number} timestamp - The timestamp of the frame when using `renderer.computeAsync()`. + * @property {Number} timestampCalls - The number of render calls using `renderer.computeAsync()`. + */ this.compute = { calls: 0, frameCalls: 0, @@ -27,6 +87,14 @@ class Info { timestampCalls: 0 }; + /** + * Memory related metrics. + * + * @type {Object} + * @readonly + * @property {Number} geometries - The number of active geometries. + * @property {Number} frameCalls - The number of active textures. + */ this.memory = { geometries: 0, textures: 0 @@ -34,6 +102,13 @@ class Info { } + /** + * This method should be executed per draw call and updates the corresponding metrics. + * + * @param {Object3D} object - The 3D object that is going to be rendered. + * @param {Number} count - The vertex or index count. + * @param {Number} instanceCount - The instance count. + */ update( object, count, instanceCount ) { this.render.drawCalls ++; @@ -62,6 +137,12 @@ class Info { } + /** + * Used by async render methods to updated timestamp metrics. + * + * @param {('render'|'compute')} type - The type of render call. + * @param {Number} time - The duration of the compute/render call in milliseconds. + */ updateTimestamp( type, time ) { if ( this[ type ].timestampCalls === 0 ) { @@ -85,6 +166,9 @@ class Info { } + /** + * Resets frame related metrics. + */ reset() { const previousRenderFrameCalls = this.render.frameCalls; @@ -105,6 +189,9 @@ class Info { } + /** + * Performs a complete reset of the object. + */ dispose() { this.reset(); diff --git a/src/renderers/common/Lighting.js b/src/renderers/common/Lighting.js index 9a1d4f36f68966..1d332ee7eedc0c 100644 --- a/src/renderers/common/Lighting.js +++ b/src/renderers/common/Lighting.js @@ -2,40 +2,68 @@ import { LightsNode } from '../../nodes/Nodes.js'; import ChainMap from './ChainMap.js'; const _defaultLights = /*@__PURE__*/ new LightsNode(); - +const _chainKeys = []; + +/** + * This renderer module manages the lights nodes which are unique + * per scene and camera combination. + * + * The lights node itself is later configured in the render list + * with the actual lights from the scene. + * + * @private + * @augments ChainMap + */ class Lighting extends ChainMap { + /** + * Constructs a lighting management component. + */ constructor() { super(); } + /** + * Creates a new lights node for the given array of lights. + * + * @param {Array} lights - The render object. + * @return {LightsNode} The lights node. + */ createNode( lights = [] ) { return new LightsNode().setLights( lights ); } + /** + * Returns a lights node for the given scene and camera. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera. + * @return {LightsNode} The lights node. + */ getNode( scene, camera ) { // ignore post-processing if ( scene.isQuadMesh ) return _defaultLights; - // tiled lighting - - const keys = [ scene, camera ]; + _chainKeys[ 0 ] = scene; + _chainKeys[ 1 ] = camera; - let node = this.get( keys ); + let node = this.get( _chainKeys ); if ( node === undefined ) { node = this.createNode(); - this.set( keys, node ); + this.set( _chainKeys, node ); } + _chainKeys.length = 0; + return node; } diff --git a/src/renderers/common/Pipeline.js b/src/renderers/common/Pipeline.js index 8f0f30418f5893..a12f9f01e0cd33 100644 --- a/src/renderers/common/Pipeline.js +++ b/src/renderers/common/Pipeline.js @@ -1,9 +1,31 @@ +/** + * Abstract class for representing pipelines. + * + * @private + * @abstract + */ class Pipeline { + /** + * Constructs a new pipeline. + * + * @param {String} cacheKey - The pipeline's cache key. + */ constructor( cacheKey ) { + /** + * The pipeline's cache key. + * + * @type {String} + */ this.cacheKey = cacheKey; + /** + * How often the pipeline is currently in use. + * + * @type {Number} + * @default 0 + */ this.usedTimes = 0; } diff --git a/src/renderers/common/Pipelines.js b/src/renderers/common/Pipelines.js index 4cae37d1260006..7da76e51af61e9 100644 --- a/src/renderers/common/Pipelines.js +++ b/src/renderers/common/Pipelines.js @@ -3,18 +3,63 @@ import RenderPipeline from './RenderPipeline.js'; import ComputePipeline from './ComputePipeline.js'; import ProgrammableStage from './ProgrammableStage.js'; +/** + * This renderer module manages the pipelines of the renderer. + * + * @private + * @augments DataMap + */ class Pipelines extends DataMap { + /** + * Constructs a new pipeline management component. + * + * @param {Backend} backend - The renderer's backend. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + */ constructor( backend, nodes ) { super(); + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; - this.nodes = nodes; - this.bindings = null; // set by the bindings + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ + this.nodes = nodes; + /** + * A references to the bindings management component. + * This reference will be set inside the `Bindings` + * constructor. + * + * @type {Bindings?} + * @default null + */ + this.bindings = null; + + /** + * Internal cache for maintaining pipelines. + * The key of the map is a cache key, the value the pipeline. + * + * @type {Map} + */ this.caches = new Map(); + + /** + * This dictionary maintains for each shader stage type (vertex, + * fragment and compute) the programmable stage objects which + * represent the actual shader code. + * + * @type {Object} + */ this.programs = { vertex: new Map(), fragment: new Map(), @@ -23,6 +68,13 @@ class Pipelines extends DataMap { } + /** + * Returns a compute pipeline for the given compute node. + * + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @return {ComputePipeline} The compute pipeline. + */ getForCompute( computeNode, bindings ) { const { backend } = this; @@ -52,7 +104,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.computeProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.computeProgram ); - stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); + stageCompute = new ProgrammableStage( nodeBuilderState.computeShader, 'compute', computeNode.name, nodeBuilderState.transforms, nodeBuilderState.nodeAttributes ); this.programs.compute.set( nodeBuilderState.computeShader, stageCompute ); backend.createProgram( stageCompute ); @@ -89,6 +141,13 @@ class Pipelines extends DataMap { } + /** + * Returns a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array?} [promises=null] - An array of compilation promises which is only relevant in context of `Renderer.compileAsync()`. + * @return {RenderPipeline} The render pipeline. + */ getForRender( renderObject, promises = null ) { const { backend } = this; @@ -111,6 +170,8 @@ class Pipelines extends DataMap { const nodeBuilderState = renderObject.getNodeBuilderState(); + const name = renderObject.material ? renderObject.material.name : ''; + // programmable stages let stageVertex = this.programs.vertex.get( nodeBuilderState.vertexShader ); @@ -119,7 +180,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.vertexProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.vertexProgram ); - stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex' ); + stageVertex = new ProgrammableStage( nodeBuilderState.vertexShader, 'vertex', name ); this.programs.vertex.set( nodeBuilderState.vertexShader, stageVertex ); backend.createProgram( stageVertex ); @@ -132,7 +193,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.fragmentProgram.usedTimes === 0 ) this._releaseProgram( previousPipeline.fragmentProgram ); - stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment' ); + stageFragment = new ProgrammableStage( nodeBuilderState.fragmentShader, 'fragment', name ); this.programs.fragment.set( nodeBuilderState.fragmentShader, stageFragment ); backend.createProgram( stageFragment ); @@ -173,6 +234,12 @@ class Pipelines extends DataMap { } + /** + * Deletes the pipeline for the given render object. + * + * @param {RenderObject} object - The render object. + * @return {Object?} The deleted dictionary. + */ delete( object ) { const pipeline = this.get( object ).pipeline; @@ -209,6 +276,9 @@ class Pipelines extends DataMap { } + /** + * Frees internal resources. + */ dispose() { super.dispose(); @@ -222,12 +292,27 @@ class Pipelines extends DataMap { } + /** + * Updates the pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { this.getForRender( renderObject ); } + /** + * Returns a compute pipeline for the given parameters. + * + * @private + * @param {Node} computeNode - The compute node. + * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. + * @param {String} cacheKey - The cache key. + * @param {Array} bindings - The bindings. + * @return {ComputePipeline} The compute pipeline. + */ _getComputePipeline( computeNode, stageCompute, cacheKey, bindings ) { // check for existing pipeline @@ -250,6 +335,17 @@ class Pipelines extends DataMap { } + /** + * Returns a render pipeline for the given parameters. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @param {ProgrammableStage} stageVertex - The programmable stage representing the vertex shader. + * @param {ProgrammableStage} stageFragment - The programmable stage representing the fragment shader. + * @param {String} cacheKey - The cache key. + * @param {Array?} promises - An array of compilation promises which is only relevant in context of `Renderer.compileAsync()`. + * @return {ComputePipeline} The compute pipeline. + */ _getRenderPipeline( renderObject, stageVertex, stageFragment, cacheKey, promises ) { // check for existing pipeline @@ -266,6 +362,10 @@ class Pipelines extends DataMap { renderObject.pipeline = pipeline; + // The `promises` array is `null` by default and only set to an empty array when + // `Renderer.compileAsync()` is used. The next call actually fills the array with + // pending promises that resolve when the render pipelines are ready for rendering. + this.backend.createRenderPipeline( renderObject, promises ); } @@ -274,24 +374,53 @@ class Pipelines extends DataMap { } + /** + * Computes a cache key representing a compute pipeline. + * + * @private + * @param {Node} computeNode - The compute node. + * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. + * @return {String} The cache key. + */ _getComputeCacheKey( computeNode, stageCompute ) { return computeNode.id + ',' + stageCompute.id; } + /** + * Computes a cache key representing a render pipeline. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @param {ProgrammableStage} stageVertex - The programmable stage representing the vertex shader. + * @param {ProgrammableStage} stageFragment - The programmable stage representing the fragment shader. + * @return {String} The cache key. + */ _getRenderCacheKey( renderObject, stageVertex, stageFragment ) { return stageVertex.id + ',' + stageFragment.id + ',' + this.backend.getRenderCacheKey( renderObject ); } + /** + * Releases the given pipeline. + * + * @private + * @param {Pipeline} pipeline - The pipeline to release. + */ _releasePipeline( pipeline ) { this.caches.delete( pipeline.cacheKey ); } + /** + * Releases the shader program. + * + * @private + * @param {Object} program - The shader program to release. + */ _releaseProgram( program ) { const code = program.code; @@ -301,6 +430,13 @@ class Pipelines extends DataMap { } + /** + * Returns `true` if the compute pipeline for the given compute node requires an update. + * + * @private + * @param {Node} computeNode - The compute node. + * @return {Boolean} Whether the compute pipeline for the given compute node requires an update or not. + */ _needsComputeUpdate( computeNode ) { const data = this.get( computeNode ); @@ -309,6 +445,13 @@ class Pipelines extends DataMap { } + /** + * Returns `true` if the render pipeline for the given render object requires an update. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render object for the given render object requires an update or not. + */ _needsRenderUpdate( renderObject ) { const data = this.get( renderObject ); diff --git a/src/renderers/common/PostProcessing.js b/src/renderers/common/PostProcessing.js index 3792420048329f..64310d9fb9e54a 100644 --- a/src/renderers/common/PostProcessing.js +++ b/src/renderers/common/PostProcessing.js @@ -3,27 +3,93 @@ import { vec4, renderOutput } from '../../nodes/TSL.js'; import { LinearSRGBColorSpace, NoToneMapping } from '../../constants.js'; import QuadMesh from '../../renderers/common/QuadMesh.js'; -const _material = /*@__PURE__*/ new NodeMaterial(); -const _quadMesh = /*@__PURE__*/ new QuadMesh( _material ); - +/** + * This module is responsible to manage the post processing setups in apps. + * You usually create a single instance of this class and use it to define + * the output of your post processing effect chain. + * ```js + * const postProcessing = new PostProcessing( renderer ); + * + * const scenePass = pass( scene, camera ); + * + * postProcessing.outputNode = scenePass; + * ``` + */ class PostProcessing { + /** + * Constructs a new post processing management module. + * + * @param {Renderer} renderer - A reference to the renderer. + * @param {Node} outputNode - An optional output node. + */ constructor( renderer, outputNode = vec4( 0, 0, 1, 1 ) ) { + /** + * A reference to the renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * A node which defines the final output of the post + * processing. This is usually the last node in a chain + * of effect nodes. + * + * @type {Node} + */ this.outputNode = outputNode; + /** + * Whether the default output tone mapping and color + * space transformation should be enabled or not. + * + * It is enabled by default by it must be disabled when + * effects must be executed after tone mapping and color + * space conversion. A typical example is FXAA which + * requires sRGB input. + * + * When set to `false`, the app must control the output + * transformation with `RenderOutputNode`. + * + * ```js + * const outputPass = renderOutput( scenePass ); + * ``` + * + * @type {Boolean} + */ this.outputColorTransform = true; + /** + * Must be set to `true` when the output node changes. + * + * @type {Node} + */ this.needsUpdate = true; - _material.name = 'PostProcessing'; + const material = new NodeMaterial(); + material.name = 'PostProcessing'; + + /** + * The full screen quad that is used to render + * the effects. + * + * @private + * @type {QuadMesh} + */ + this._quadMesh = new QuadMesh( material ); } + /** + * When `PostProcessing` is used to apply post processing effects, + * the application must use this version of `render()` inside + * its animation loop (not the one from the renderer). + */ render() { - this.update(); + this._update(); const renderer = this.renderer; @@ -35,7 +101,7 @@ class PostProcessing { // - _quadMesh.render( renderer ); + this._quadMesh.render( renderer ); // @@ -44,7 +110,21 @@ class PostProcessing { } - update() { + /** + * Frees internal resources. + */ + dispose() { + + this._quadMesh.material.dispose(); + + } + + /** + * Updates the state of the module. + * + * @private + */ + _update() { if ( this.needsUpdate === true ) { @@ -53,8 +133,8 @@ class PostProcessing { 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._quadMesh.material.fragmentNode = this.outputColorTransform === true ? renderOutput( this.outputNode, toneMapping, outputColorSpace ) : this.outputNode.context( { toneMapping, outputColorSpace } ); + this._quadMesh.material.needsUpdate = true; this.needsUpdate = false; @@ -62,9 +142,17 @@ class PostProcessing { } + /** + * When `PostProcessing` is used to apply post processing effects, + * the application must use this version of `renderAsync()` inside + * its animation loop (not the one from the renderer). + * + * @async + * @return {Promise} A Promise that resolves when the render has been finished. + */ async renderAsync() { - this.update(); + this._update(); const renderer = this.renderer; @@ -76,7 +164,7 @@ class PostProcessing { // - await _quadMesh.renderAsync( renderer ); + await this._quadMesh.renderAsync( renderer ); // diff --git a/src/renderers/common/PostProcessingUtils.js b/src/renderers/common/PostProcessingUtils.js deleted file mode 100644 index 0720c77179cf9a..00000000000000 --- a/src/renderers/common/PostProcessingUtils.js +++ /dev/null @@ -1,86 +0,0 @@ -import { Color } from '../../math/Color.js'; - -// renderer state - -export function saveRendererState( renderer, state = {} ) { - - state.toneMapping = renderer.toneMapping; - state.toneMappingExposure = renderer.toneMappingExposure; - state.outputColorSpace = renderer.outputColorSpace; - state.renderTarget = renderer.getRenderTarget(); - state.activeCubeFace = renderer.getActiveCubeFace(); - state.activeMipmapLevel = renderer.getActiveMipmapLevel(); - state.renderObjectFunction = renderer.getRenderObjectFunction(); - state.pixelRatio = renderer.getPixelRatio(); - state.mrt = renderer.getMRT(); - state.clearColor = renderer.getClearColor( state.clearColor || new Color() ); - state.clearAlpha = renderer.getClearAlpha(); - state.autoClear = renderer.autoClear; - state.scissorTest = renderer.getScissorTest(); - - return state; - -} - -export function resetRendererState( renderer, state ) { - - state = saveRendererState( renderer, state ); - - renderer.setMRT( null ); - renderer.setRenderObjectFunction( null ); - renderer.setClearColor( 0x000000, 1 ); - renderer.autoClear = true; - - return state; - -} - -export function restoreRendererState( renderer, state ) { - - renderer.toneMapping = state.toneMapping; - renderer.toneMappingExposure = state.toneMappingExposure; - renderer.outputColorSpace = state.outputColorSpace; - renderer.setRenderTarget( state.renderTarget, state.activeCubeFace, state.activeMipmapLevel ); - renderer.setRenderObjectFunction( state.renderObjectFunction ); - renderer.setPixelRatio( state.pixelRatio ); - renderer.setMRT( state.mrt ); - renderer.setClearColor( state.clearColor, state.clearAlpha ); - renderer.autoClear = state.autoClear; - renderer.setScissorTest( state.scissorTest ); - -} - -// renderer and scene state - -export function saveRendererAndSceneState( renderer, scene, state = {} ) { - - state = saveRendererState( renderer, state ); - state.background = scene.background; - state.backgroundNode = scene.backgroundNode; - state.overrideMaterial = scene.overrideMaterial; - - return state; - -} - -export function resetRendererAndSceneState( renderer, scene, state ) { - - state = saveRendererAndSceneState( renderer, scene, state ); - - scene.background = null; - scene.backgroundNode = null; - scene.overrideMaterial = null; - - return state; - -} - -export function restoreRendererAndSceneState( renderer, scene, state ) { - - restoreRendererState( renderer, state ); - - scene.background = state.background; - scene.backgroundNode = state.backgroundNode; - scene.overrideMaterial = state.overrideMaterial; - -} diff --git a/src/renderers/common/ProgrammableStage.js b/src/renderers/common/ProgrammableStage.js index c69627bf0cd9c8..502cba31e23b3e 100644 --- a/src/renderers/common/ProgrammableStage.js +++ b/src/renderers/common/ProgrammableStage.js @@ -1,16 +1,74 @@ let _id = 0; +/** + * Class for representing programmable stages which are vertex, + * fragment or compute shaders. Unlike fixed-function states (like blending), + * they represent the programmable part of a pipeline. + * + * @private + */ class ProgrammableStage { - constructor( code, type, transforms = null, attributes = null ) { + /** + * Constructs a new programmable stage. + * + * @param {String} code - The shader code. + * @param {('vertex'|'fragment'|'compute')} stage - The type of stage. + * @param {String} name - The name of the shader. + * @param {Array?} [transforms=null] - The transforms (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + * @param {Array?} [attributes=null] - The attributes (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + */ + constructor( code, stage, name, transforms = null, attributes = null ) { + /** + * The id of the programmable stage. + * + * @type {Number} + */ this.id = _id ++; + /** + * The shader code. + * + * @type {String} + */ this.code = code; - this.stage = type; + + /** + * The type of stage. + * + * @type {String} + */ + this.stage = stage; + + /** + * The name of the stage. + * This is used for debugging purposes. + * + * @type {String} + */ + this.name = name; + + /** + * The transforms (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + * + * @type {Array?} + */ this.transforms = transforms; + + /** + * The attributes (only relevant for compute stages with WebGL 2 which uses Transform Feedback). + * + * @type {Array?} + */ this.attributes = attributes; + /** + * How often the programmable stage is currently in use. + * + * @type {Number} + * @default 0 + */ this.usedTimes = 0; } diff --git a/src/renderers/common/QuadMesh.js b/src/renderers/common/QuadMesh.js index 1274e4ba75276f..6cdc495e65732f 100644 --- a/src/renderers/common/QuadMesh.js +++ b/src/renderers/common/QuadMesh.js @@ -3,14 +3,23 @@ import { Float32BufferAttribute } from '../../core/BufferAttribute.js'; import { Mesh } from '../../objects/Mesh.js'; import { OrthographicCamera } from '../../cameras/OrthographicCamera.js'; -// 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 - +/** + * The purpose of this special geometry is to fill the entire viewport with a single triangle. + * + * Reference: {@link https://github.com/mrdoob/three.js/pull/21358} + * + * @private + * @augments BufferGeometry + */ class QuadGeometry extends BufferGeometry { + /** + * Constructs a new quad geometry. + * + * @param {Boolean} [flipY=false] - Whether the uv coordinates should be flipped along the vertical axis or not. + */ constructor( flipY = false ) { super(); @@ -26,24 +35,64 @@ class QuadGeometry extends BufferGeometry { const _geometry = /*@__PURE__*/ new QuadGeometry(); + +/** + * This module is a helper for passes which need to render a full + * screen effect which is quite common in context of post processing. + * + * The intended usage is to reuse a single quad mesh for rendering + * subsequent passes by just reassigning the `material` reference. + * + * @augments Mesh + */ class QuadMesh extends Mesh { + /** + * Constructs a new quad mesh. + * + * @param {Material?} [material=null] - The material to render the quad mesh with. + */ constructor( material = null ) { super( _geometry, material ); + /** + * The camera to render the quad mesh with. + * + * @type {OrthographicCamera} + * @readonly + */ this.camera = _camera; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isQuadMesh = true; } - renderAsync( renderer ) { + /** + * Async version of `render()`. + * + * @async + * @param {Renderer} renderer - The renderer. + * @return {Promise} A Promise that resolves when the render has been finished. + */ + async renderAsync( renderer ) { return renderer.renderAsync( this, _camera ); } + /** + * Renders the quad mesh + * + * @param {Renderer} renderer - The renderer. + */ render( renderer ) { renderer.render( this, _camera ); diff --git a/src/renderers/common/RenderBundle.js b/src/renderers/common/RenderBundle.js index e84c0ad0de8d5c..84598acb067dd2 100644 --- a/src/renderers/common/RenderBundle.js +++ b/src/renderers/common/RenderBundle.js @@ -1,18 +1,24 @@ +/** + * This module is used to represent render bundles inside the renderer + * for further processing. + * + * @private + */ class RenderBundle { - constructor( scene, camera ) { + /** + * Constructs a new bundle group. + * + * @param {BundleGroup} bundleGroup - The bundle group. + * @param {Camera} camera - The camera the bundle group is rendered with. + */ + constructor( bundleGroup, camera ) { - this.scene = scene; + this.bundleGroup = bundleGroup; this.camera = camera; } - clone() { - - return Object.assign( new this.constructor(), this ); - - } - } export default RenderBundle; diff --git a/src/renderers/common/RenderBundles.js b/src/renderers/common/RenderBundles.js index 66045184139de4..25f90a7261b4ab 100644 --- a/src/renderers/common/RenderBundles.js +++ b/src/renderers/common/RenderBundles.js @@ -1,35 +1,64 @@ import ChainMap from './ChainMap.js'; import RenderBundle from './RenderBundle.js'; +const _chainKeys = []; + +/** + * This renderer module manages render bundles. + * + * @private + */ class RenderBundles { + /** + * Constructs a new render bundle management component. + */ constructor() { - this.lists = new ChainMap(); + /** + * A chain map for maintaining the render bundles. + * + * @type {ChainMap} + */ + this.bundles = new ChainMap(); } - get( scene, camera ) { + /** + * Returns a render bundle for the given bundle group and camera. + * + * @param {BundleGroup} bundleGroup - The bundle group. + * @param {Camera} camera - The camera the bundle group is rendered with. + * @return {RenderBundle} The render bundle. + */ + get( bundleGroup, camera ) { + + const bundles = this.bundles; - const lists = this.lists; - const keys = [ scene, camera ]; + _chainKeys[ 0 ] = bundleGroup; + _chainKeys[ 1 ] = camera; - let list = lists.get( keys ); + let bundle = bundles.get( _chainKeys ); - if ( list === undefined ) { + if ( bundle === undefined ) { - list = new RenderBundle( scene, camera ); - lists.set( keys, list ); + bundle = new RenderBundle( bundleGroup, camera ); + bundles.set( _chainKeys, bundle ); } - return list; + _chainKeys.length = 0; + + return bundle; } + /** + * Frees all internal resources. + */ dispose() { - this.lists = new ChainMap(); + this.bundles = new ChainMap(); } diff --git a/src/renderers/common/RenderContext.js b/src/renderers/common/RenderContext.js index 1f1d543a5b1c3d..f9bbf6de060fda 100644 --- a/src/renderers/common/RenderContext.js +++ b/src/renderers/common/RenderContext.js @@ -1,44 +1,235 @@ import { Vector4 } from '../../math/Vector4.js'; import { hashArray } from '../../nodes/core/NodeUtils.js'; -let id = 0; +let _id = 0; +/** + * Any render or compute command is executed in a specific context that defines + * the state of the renderer and its backend. Typical examples for such context + * data are the current clear values or data from the active framebuffer. This + * module is used to represent these contexts as objects. + * + * @private + */ class RenderContext { + /** + * Constructs a new render context. + */ constructor() { - this.id = id ++; + /** + * The context's ID. + * + * @type {Number} + */ + this.id = _id ++; + /** + * Whether the current active framebuffer has a color attachment. + * + * @type {Boolean} + * @default true + */ this.color = true; + + /** + * Whether the color attachment should be cleared or not. + * + * @type {Boolean} + * @default true + */ this.clearColor = true; + + /** + * The clear color value. + * + * @type {Object} + * @default true + */ this.clearColorValue = { r: 0, g: 0, b: 0, a: 1 }; + /** + * Whether the current active framebuffer has a depth attachment. + * + * @type {Boolean} + * @default true + */ this.depth = true; + + /** + * Whether the depth attachment should be cleared or not. + * + * @type {Boolean} + * @default true + */ this.clearDepth = true; + + /** + * The clear depth value. + * + * @type {Number} + * @default 1 + */ this.clearDepthValue = 1; + /** + * Whether the current active framebuffer has a stencil attachment. + * + * @type {Boolean} + * @default false + */ this.stencil = false; + + /** + * Whether the stencil attachment should be cleared or not. + * + * @type {Boolean} + * @default true + */ this.clearStencil = true; + + /** + * The clear stencil value. + * + * @type {Number} + * @default 1 + */ this.clearStencilValue = 1; + /** + * By default the viewport encloses the entire framebuffer If a smaller + * viewport is manually defined, this property is to `true` by the renderer. + * + * @type {Boolean} + * @default false + */ this.viewport = false; + + /** + * The viewport value. This value is in physical pixels meaning it incorporates + * the renderer's pixel ratio. The viewport property of render targets or + * the renderer is in logical pixels. + * + * @type {Vector4} + */ this.viewportValue = new Vector4(); + /** + * When the scissor test is active and scissor rectangle smaller than the + * framebuffers dimensions, this property is to `true` by the renderer. + * + * @type {Boolean} + * @default false + */ this.scissor = false; + + /** + * The scissor rectangle. + * + * @type {Vector4} + */ this.scissorValue = new Vector4(); + /** + * The active render target. + * + * @type {RenderTarget?} + * @default null + */ + this.renderTarget = null; + + /** + * The textures of the active render target. + * `null` when no render target is set. + * + * @type {Array?} + * @default null + */ this.textures = null; + + /** + * The depth texture of the active render target. + * `null` when no render target is set. + * + * @type {DepthTexture?} + * @default null + */ this.depthTexture = null; + + /** + * The active cube face. + * + * @type {Number} + * @default 0 + */ this.activeCubeFace = 0; + + /** + * The active mipmap level. + * + * @type {Number} + * @default 0 + */ + this.activeMipmapLevel = 0; + + /** + * The number of MSAA samples. This value is always `1` when + * MSAA isn't used. + * + * @type {Number} + * @default 1 + */ this.sampleCount = 1; + /** + * The active render target's width in physical pixels. + * + * @type {Number} + * @default 0 + */ this.width = 0; + + /** + * The active render target's height in physical pixels. + * + * @type {Number} + * @default 0 + */ this.height = 0; + /** + * The occlusion query count. + * + * @type {Number} + * @default 0 + */ + this.occlusionQueryCount = 0; + + /** + * The current clipping context. + * + * @type {ClippingContext?} + * @default null + */ + this.clippingContext = null; + + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isRenderContext = true; } + /** + * Returns the cache key of this render context. + * + * @return {Number} The cache key. + */ getCacheKey() { return getCacheKey( this ); @@ -47,6 +238,14 @@ class RenderContext { } +/** + * Computes a cache key for the given render context. This key + * should identify the render target state so it is possible to + * configure the correct attachments in the respective backend. + * + * @param {RenderContext} renderContext - The render context. + * @return {Number} The cache key. + */ export function getCacheKey( renderContext ) { const { textures, activeCubeFace } = renderContext; diff --git a/src/renderers/common/RenderContexts.js b/src/renderers/common/RenderContexts.js index cdbfc8c26d8100..8a6e2467873217 100644 --- a/src/renderers/common/RenderContexts.js +++ b/src/renderers/common/RenderContexts.js @@ -1,17 +1,46 @@ import ChainMap from './ChainMap.js'; import RenderContext from './RenderContext.js'; - +import { Scene } from '../../scenes/Scene.js'; +import { Camera } from '../../cameras/Camera.js'; + +const _chainKeys = []; +const _defaultScene = /*@__PURE__*/ new Scene(); +const _defaultCamera = /*@__PURE__*/ new Camera(); + +/** + * This module manages the render contexts of the renderer. + * + * @private + */ class RenderContexts { + /** + * Constructs a new render context management component. + */ constructor() { + /** + * A dictionary that manages render contexts in chain maps + * for each attachment state. + * + * @type {Object} + */ this.chainMaps = {}; } + /** + * Returns a render context for the given scene, camera and render target. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera that is used to render the scene. + * @param {RenderTarget?} [renderTarget=null] - The active render target. + * @return {RenderContext} The render context. + */ get( scene, camera, renderTarget = null ) { - const chainKey = [ scene, camera ]; + _chainKeys[ 0 ] = scene; + _chainKeys[ 1 ] = camera; let attachmentState; @@ -28,30 +57,54 @@ class RenderContexts { } - const chainMap = this.getChainMap( attachmentState ); + const chainMap = this._getChainMap( attachmentState ); - let renderState = chainMap.get( chainKey ); + let renderState = chainMap.get( _chainKeys ); if ( renderState === undefined ) { renderState = new RenderContext(); - chainMap.set( chainKey, renderState ); + chainMap.set( _chainKeys, renderState ); } + _chainKeys.length = 0; + if ( renderTarget !== null ) renderState.sampleCount = renderTarget.samples === 0 ? 1 : renderTarget.samples; return renderState; } - getChainMap( attachmentState ) { + /** + * Returns a render context intended for clear operations. + * + * @param {RenderTarget?} [renderTarget=null] - The active render target. + * @return {RenderContext} The render context. + */ + getForClear( renderTarget = null ) { + + return this.get( _defaultScene, _defaultCamera, renderTarget ); + + } + + /** + * Returns a chain map for the given attachment state. + * + * @private + * @param {String} attachmentState - The attachment state. + * @return {ChainMap} The chain map. + */ + _getChainMap( attachmentState ) { return this.chainMaps[ attachmentState ] || ( this.chainMaps[ attachmentState ] = new ChainMap() ); } + /** + * Frees internal resources. + */ dispose() { this.chainMaps = {}; diff --git a/src/renderers/common/RenderList.js b/src/renderers/common/RenderList.js index d819ee90bbb4c2..069bdf2fd5a0ec 100644 --- a/src/renderers/common/RenderList.js +++ b/src/renderers/common/RenderList.js @@ -1,5 +1,14 @@ import { DoubleSide } from '../../constants.js'; +/** + * Default sorting function for opaque render items. + * + * @private + * @function + * @param {Object} a - The first render item. + * @param {Object} b - The second render item. + * @return {Number} A numeric value which defines the sort order. + */ function painterSortStable( a, b ) { if ( a.groupOrder !== b.groupOrder ) { @@ -26,6 +35,15 @@ function painterSortStable( a, b ) { } +/** + * Default sorting function for transparent render items. + * + * @private + * @function + * @param {Object} a - The first render item. + * @param {Object} b - The second render item. + * @return {Number} A numeric value which defines the sort order. + */ function reversePainterSortStable( a, b ) { if ( a.groupOrder !== b.groupOrder ) { @@ -48,6 +66,14 @@ function reversePainterSortStable( a, b ) { } +/** + * Returns `true` if the given transparent material requires a double pass. + * + * @private + * @function + * @param {Material} material - The transparent material. + * @return {Boolean} Whether the given material requires a double pass or not. + */ function needsDoublePass( material ) { const hasTransmission = material.transmission > 0 || material.transmissionNode; @@ -56,28 +82,120 @@ function needsDoublePass( material ) { } +/** + * When the renderer analyzes the scene at the beginning of a render call, + * it stores 3D object for further processing in render lists. Depending on the + * properties of a 3D objects (like their transformation or material state), the + * objects are maintained in ordered lists for the actual rendering. + * + * Render lists are unique per scene and camera combination. + * + * @private + * @augments Pipeline + */ class RenderList { + /** + * Constructs a render list. + * + * @param {Lighting} lighting - The lighting management component. + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera the scene is rendered with. + */ constructor( lighting, scene, camera ) { + /** + * 3D objects are transformed into render items and stored in this array. + * + * @type {Array} + */ this.renderItems = []; + + /** + * The current render items index. + * + * @type {Number} + * @default 0 + */ this.renderItemsIndex = 0; + /** + * A list with opaque render items. + * + * @type {Array} + */ this.opaque = []; + + /** + * A list with transparent render items which require + * double pass rendering (e.g. transmissive objects). + * + * @type {Array} + */ this.transparentDoublePass = []; + + /** + * A list with transparent render items. + * + * @type {Array} + */ this.transparent = []; + + /** + * A list with transparent render bundle data. + * + * @type {Array} + */ this.bundles = []; + /** + * The render list's lights node. This node is later + * relevant for the actual analytical light nodes which + * compute the scene's lighting in the shader. + * + * @type {LightsNode} + */ this.lightsNode = lighting.getNode( scene, camera ); + + /** + * The scene's lights stored in an array. This array + * is used to setup the lights node. + * + * @type {Array} + */ this.lightsArray = []; + /** + * The scene. + * + * @type {Scene} + */ this.scene = scene; + + /** + * The camera the scene is rendered with. + * + * @type {Camera} + */ this.camera = camera; + /** + * How many objects perform occlusion query tests. + * + * @type {Number} + * @default 0 + */ this.occlusionQueryCount = 0; } + /** + * This method is called right at the beginning of a render call + * before the scene is analyzed. It prepares the internal data + * structures for the upcoming render lists generation. + * + * @return {RenderList} A reference to this render list. + */ begin() { this.renderItemsIndex = 0; @@ -95,6 +213,22 @@ class RenderList { } + /** + * Returns a render item for the giving render item state. The state is defined + * by a series of object-related parameters. + * + * The method avoids object creation by holding render items and reusing them in + * subsequent render calls (just with different property values). + * + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The 3D object's geometry. + * @param {Material} material - The 3D object's material. + * @param {Number} groupOrder - The current group order. + * @param {Number} z - Th 3D object's depth value (z value in clip space). + * @param {Number?} group - {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The current clipping context. + * @return {Object} The render item. + */ getNextRenderItem( object, geometry, material, groupOrder, z, group, clippingContext ) { let renderItem = this.renderItems[ this.renderItemsIndex ]; @@ -135,6 +269,18 @@ class RenderList { } + /** + * Pushes the given object as a render item to the internal render lists. + * The selected lists depend on the object properties. + * + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The 3D object's geometry. + * @param {Material} material - The 3D object's material. + * @param {Number} groupOrder - The current group order. + * @param {Number} z - Th 3D object's depth value (z value in clip space). + * @param {Number?} group - {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The current clipping context. + */ push( object, geometry, material, groupOrder, z, group, clippingContext ) { const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group, clippingContext ); @@ -155,6 +301,18 @@ class RenderList { } + /** + * Inserts the given object as a render item at the start of the internal render lists. + * The selected lists depend on the object properties. + * + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The 3D object's geometry. + * @param {Material} material - The 3D object's material. + * @param {Number} groupOrder - The current group order. + * @param {Number} z - Th 3D object's depth value (z value in clip space). + * @param {Number?} group - {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The current clipping context. + */ unshift( object, geometry, material, groupOrder, z, group, clippingContext ) { const renderItem = this.getNextRenderItem( object, geometry, material, groupOrder, z, group, clippingContext ); @@ -173,18 +331,34 @@ class RenderList { } + /** + * Pushes render bundle group data into the render list. + * + * @param {Object} group - Bundle group data. + */ pushBundle( group ) { this.bundles.push( group ); } + /** + * Pushes a light into the render list. + * + * @param {Light} light - The light. + */ pushLight( light ) { this.lightsArray.push( light ); } + /** + * Sorts the internal render lists. + * + * @param {function(Any, Any): Number} customOpaqueSort - A custom sort function for opaque objects. + * @param {function(Any, Any): Number} customTransparentSort - A custom sort function for transparent objects. + */ sort( customOpaqueSort, customTransparentSort ) { if ( this.opaque.length > 1 ) this.opaque.sort( customOpaqueSort || painterSortStable ); @@ -193,6 +367,10 @@ class RenderList { } + /** + * This method performs finalizing tasks right after the render lists + * have been generated. + */ finish() { // update lights diff --git a/src/renderers/common/RenderLists.js b/src/renderers/common/RenderLists.js index 60cb94c30f2a81..1818d25e0156a6 100644 --- a/src/renderers/common/RenderLists.js +++ b/src/renderers/common/RenderLists.js @@ -1,34 +1,71 @@ import ChainMap from './ChainMap.js'; import RenderList from './RenderList.js'; +const _chainKeys = []; + +/** + * This renderer module manages the render lists which are unique + * per scene and camera combination. + * + * @private + */ class RenderLists { + /** + * Constructs a render lists management component. + * + * @param {Lighting} lighting - The lighting management component. + */ constructor( lighting ) { + /** + * The lighting management component. + * + * @type {Lighting} + */ this.lighting = lighting; + /** + * The internal chain map which holds the render lists. + * + * @type {ChainMap} + */ this.lists = new ChainMap(); } + /** + * Returns a render list for the given scene and camera. + * + * @param {Scene} scene - The scene. + * @param {Camera} camera - The camera. + * @return {RenderList} The render list. + */ get( scene, camera ) { const lists = this.lists; - const keys = [ scene, camera ]; - let list = lists.get( keys ); + _chainKeys[ 0 ] = scene; + _chainKeys[ 1 ] = camera; + + let list = lists.get( _chainKeys ); if ( list === undefined ) { list = new RenderList( this.lighting, scene, camera ); - lists.set( keys, list ); + lists.set( _chainKeys, list ); } + _chainKeys.length = 0; + return list; } + /** + * Frees all internal resources. + */ dispose() { this.lists = new ChainMap(); diff --git a/src/renderers/common/RenderObject.js b/src/renderers/common/RenderObject.js index 50daed6be71425..03e96df667e12b 100644 --- a/src/renderers/common/RenderObject.js +++ b/src/renderers/common/RenderObject.js @@ -36,49 +36,264 @@ function getKeys( obj ) { } -export default class RenderObject { - +/** + * A render object is the renderer's representation of single entity that gets drawn + * with a draw command. There is no unique mapping of render objects to 3D objects in the + * scene since render objects also depend from the used material, the current render context + * and the current scene's lighting. + * + * In general, the basic process of the renderer is: + * + * - Analyze the 3D objects in the scene and generate render lists containing render items. + * - Process the render lists by calling one or more render commands for each render item. + * - For each render command, request a render object and perform the draw. + * + * The module provides an interface to get data required for the draw command like the actual + * draw parameters or vertex buffers. It also holds a series of caching related methods since + * creating render objects should only be done when necessary. + * + * @private + */ +class RenderObject { + + /** + * Constructs a new render object. + * + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Geometries} geometries - Renderer component for managing geometries. + * @param {Renderer} renderer - The renderer. + * @param {Object3D} object - The 3D object. + * @param {Material} material - The 3D object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The lights node. + * @param {RenderContext} renderContext - The render context. + * @param {ClippingContext} clippingContext - The clipping context. + */ constructor( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext ) { + this.id = _id ++; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + * @private + */ this._nodes = nodes; - this._geometries = geometries; - this.id = _id ++; + /** + * Renderer component for managing geometries. + * + * @type {Geometries} + * @private + */ + this._geometries = geometries; + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * The 3D object. + * + * @type {Object3D} + */ this.object = object; + + /** + * The 3D object's material. + * + * @type {Material} + */ this.material = material; + + /** + * The scene the 3D object belongs to. + * + * @type {Scene} + */ this.scene = scene; + + /** + * The camera the 3D object should be rendered with. + * + * @type {Camera} + */ this.camera = camera; + + /** + * The lights node. + * + * @type {LightsNode} + */ this.lightsNode = lightsNode; + + /** + * The render context. + * + * @type {RenderContext} + */ this.context = renderContext; + /** + * The 3D object's geometry. + * + * @type {BufferGeometry} + */ this.geometry = object.geometry; + + /** + * The render object's version. + * + * @type {Number} + */ this.version = material.version; + /** + * The draw range of the geometry. + * + * @type {Object?} + * @default null + */ this.drawRange = null; + /** + * An array holding the buffer attributes + * of the render object. This entails attribute + * definitions on geometry and node level. + * + * @type {Array?} + * @default null + */ this.attributes = null; + + /** + * A reference to a render pipeline the render + * object is processed with. + * + * @type {RenderPipeline} + * @default null + */ this.pipeline = null; + + /** + * Only relevant for objects using + * multiple materials. This represents a group entry + * from the respective `BufferGeometry`. + * + * @type {{start: Number, count: Number}?} + * @default null + */ + this.group = null; + + /** + * An array holding the vertex buffers which can + * be buffer attributes but also interleaved buffers. + * + * @type {Array?} + * @default null + */ this.vertexBuffers = null; + + /** + * The parameters for the draw command. + * + * @type {Object?} + * @default null + */ this.drawParams = null; + /** + * If this render object is used inside a render bundle, + * this property points to the respective bundle group. + * + * @type {BundleGroup?} + * @default null + */ this.bundle = null; + /** + * The clipping context. + * + * @type {ClippingContext} + */ this.clippingContext = clippingContext; + + /** + * The clipping context's cache key. + * + * @type {String} + */ this.clippingContextCacheKey = clippingContext !== null ? clippingContext.cacheKey : ''; + /** + * The initial node cache key. + * + * @type {Number} + */ this.initialNodesCacheKey = this.getDynamicCacheKey(); + + /** + * The initial cache key. + * + * @type {Number} + */ this.initialCacheKey = this.getCacheKey(); + /** + * The node builder state. + * + * @type {NodeBuilderState?} + * @private + * @default null + */ this._nodeBuilderState = null; + + /** + * An array of bindings. + * + * @type {Array?} + * @private + * @default null + */ this._bindings = null; + + /** + * Reference to the node material observer. + * + * @type {NodeMaterialObserver?} + * @private + * @default null + */ this._monitor = null; + /** + * An event listener which is defined by `RenderObjects`. It performs + * clean up tasks when `dispose()` on this render object. + * + * @method + */ this.onDispose = null; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isRenderObject = true; + /** + * An event listener which is executed when `dispose()` is called on + * the render object's material. + * + * @method + */ this.onMaterialDispose = () => { this.dispose(); @@ -89,12 +304,23 @@ export default class RenderObject { } - updateClipping( parent ) { + /** + * Updates the clipping context. + * + * @param {ClippingContext} context - The clipping context to set. + */ + updateClipping( context ) { - this.clippingContext = parent; + this.clippingContext = context; } + /** + * Whether the clipping requires an update or not. + * + * @type {Boolean} + * @readonly + */ get clippingNeedsUpdate() { if ( this.clippingContext === null || this.clippingContext.cacheKey === this.clippingContextCacheKey ) return false; @@ -105,48 +331,90 @@ export default class RenderObject { } + /** + * The number of clipping planes defined in context of hardware clipping. + * + * @type {Number} + * @readonly + */ get hardwareClippingPlanes() { return this.material.hardwareClipping === true ? this.clippingContext.unionClippingCount : 0; } + /** + * Returns the node builder state of this render object. + * + * @return {NodeBuilderState} The node builder state. + */ getNodeBuilderState() { return this._nodeBuilderState || ( this._nodeBuilderState = this._nodes.getForRender( this ) ); } + /** + * Returns the node material observer of this render object. + * + * @return {NodeMaterialObserver} The node material observer. + */ getMonitor() { return this._monitor || ( this._monitor = this.getNodeBuilderState().monitor ); } + /** + * Returns an array of bind groups of this render object. + * + * @return {Array} The bindings. + */ getBindings() { return this._bindings || ( this._bindings = this.getNodeBuilderState().createBindings() ); } + /** + * Returns the index of the render object's geometry. + * + * @return {BufferAttribute?} The index. Returns `null` for non-indexed geometries. + */ getIndex() { return this._geometries.getIndex( this ); } + /** + * Returns the indirect buffer attribute. + * + * @return {BufferAttribute?} The indirect attribute. `null` if no indirect drawing is used. + */ getIndirect() { return this._geometries.getIndirect( this ); } + /** + * Returns an array that acts as a key for identifying the render object in a chain map. + * + * @return {Array} An array with object references. + */ getChainArray() { return [ this.object, this.material, this.context, this.lightsNode ]; } + /** + * This method is used when the geometry of a 3D object has been exchanged and the + * respective render object now requires an update. + * + * @param {BufferGeometry} geometry - The geometry to set. + */ setGeometry( geometry ) { this.geometry = geometry; @@ -154,6 +422,12 @@ export default class RenderObject { } + /** + * Returns the buffer attributes of the render object. The returned array holds + * attribute definitions on geometry and node level. + * + * @return {Array} An array with buffer attributes. + */ getAttributes() { if ( this.attributes !== null ) return this.attributes; @@ -184,6 +458,11 @@ export default class RenderObject { } + /** + * Returns the vertex buffers of the render object. + * + * @return {Array} An array with buffer attribute or interleaved buffers. + */ getVertexBuffers() { if ( this.vertexBuffers === null ) this.getAttributes(); @@ -192,6 +471,11 @@ export default class RenderObject { } + /** + * Returns the draw parameters for the render object. + * + * @return {{vertexCount: Number, firstVertex: Number, instanceCount: Number, firstInstance: Number}} The draw parameters. + */ getDrawParameters() { const { object, material, geometry, group, drawRange } = this; @@ -258,6 +542,13 @@ export default class RenderObject { } + /** + * Returns the render object's geometry cache key. + * + * The geometry cache key is part of the material cache key. + * + * @return {String} The geometry cache key. + */ getGeometryCacheKey() { const { geometry } = this; @@ -277,6 +568,26 @@ export default class RenderObject { } + // structural equality isn't sufficient for morph targets since the + // data are maintained in textures. only if the targets are all equal + // the texture and thus the instance of `MorphNode` can be shared. + + for ( const name of Object.keys( geometry.morphAttributes ).sort() ) { + + const targets = geometry.morphAttributes[ name ]; + + cacheKey += 'morph-' + name + ','; + + for ( let i = 0, l = targets.length; i < l; i ++ ) { + + const attribute = targets[ i ]; + + cacheKey += attribute.id + ','; + + } + + } + if ( geometry.index ) { cacheKey += 'index,'; @@ -287,6 +598,13 @@ export default class RenderObject { } + /** + * Returns the render object's material cache key. + * + * The material cache key is part of the render object cache key. + * + * @return {Number} The material cache key. + */ getMaterialCacheKey() { const { object, material } = this; @@ -353,12 +671,6 @@ export default class RenderObject { } - if ( object.morphTargetInfluences ) { - - cacheKey += object.morphTargetInfluences.length + ','; - - } - if ( object.isBatchedMesh ) { cacheKey += object._matricesTexture.uuid + ','; @@ -385,23 +697,58 @@ export default class RenderObject { } + /** + * Whether the geometry requires an update or not. + * + * @type {Boolean} + * @readonly + */ get needsGeometryUpdate() { return this.geometry.id !== this.object.geometry.id; } + /** + * Whether the render object requires an update or not. + * + * Note: There are two distinct places where render objects are checked for an update. + * + * 1. In `RenderObjects.get()` which is executed when the render object is request. This + * method checks the `needsUpdate` flag and recreates the render object if necessary. + * 2. In `Renderer._renderObjectDirect()` right after getting the render object via + * `RenderObjects.get()`. The render object's NodeMaterialObserver is then used to detect + * a need for a refresh due to material, geometry or object related value changes. + * + * TODO: Investigate if it's possible to merge both steps so there is only a single place + * that performs the 'needsUpdate' check. + * + * @type {Boolean} + * @readonly + */ get needsUpdate() { return /*this.object.static !== true &&*/ ( this.initialNodesCacheKey !== this.getDynamicCacheKey() || this.clippingNeedsUpdate ); } + /** + * Returns the dynamic cache key which represents a key that is computed per draw command. + * + * @return {Number} The cache key. + */ getDynamicCacheKey() { - // Environment Nodes Cache Key + let cacheKey = 0; - let cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); + // `Nodes.getCacheKey()` returns an environment cache key which is not relevant when + // the renderer is inside a shadow pass. + + if ( this.material.isShadowPassMaterial !== true ) { + + cacheKey = this._nodes.getCacheKey( this.scene, this.lightsNode ); + + } if ( this.object.receiveShadow ) { @@ -413,12 +760,20 @@ export default class RenderObject { } + /** + * Returns the render object's cache key. + * + * @return {Number} The cache key. + */ getCacheKey() { return this.getMaterialCacheKey() + this.getDynamicCacheKey(); } + /** + * Frees internal resources. + */ dispose() { this.material.removeEventListener( 'dispose', this.onMaterialDispose ); @@ -428,3 +783,5 @@ export default class RenderObject { } } + +export default RenderObject; diff --git a/src/renderers/common/RenderObjects.js b/src/renderers/common/RenderObjects.js index 63c1f3a54cf8ec..b9ffe747681f2a 100644 --- a/src/renderers/common/RenderObjects.js +++ b/src/renderers/common/RenderObjects.js @@ -1,40 +1,109 @@ import ChainMap from './ChainMap.js'; import RenderObject from './RenderObject.js'; -const chainArray = []; +const _chainKeys = []; +/** + * This module manages the render objects of the renderer. + * + * @private + */ class RenderObjects { + /** + * Constructs a new render object management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Geometries} geometries - Renderer component for managing geometries. + * @param {Pipelines} pipelines - Renderer component for managing pipelines. + * @param {Bindings} bindings - Renderer component for managing bindings. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( renderer, nodes, geometries, pipelines, bindings, info ) { + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * Renderer component for managing nodes related logic. + * + * @type {Nodes} + */ this.nodes = nodes; + + /** + * Renderer component for managing geometries. + * + * @type {Geometries} + */ this.geometries = geometries; + + /** + * Renderer component for managing pipelines. + * + * @type {Pipelines} + */ this.pipelines = pipelines; + + /** + * Renderer component for managing bindings. + * + * @type {Bindings} + */ this.bindings = bindings; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; + /** + * A dictionary that manages render contexts in chain maps + * for each pass ID. + * + * @type {Object} + */ this.chainMaps = {}; } + /** + * Returns a render object for the given object and state data. + * + * @param {Object3D} object - The 3D object. + * @param {Material} material - The 3D object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the 3D object should be rendered with. + * @param {LightsNode} lightsNode - The lights node. + * @param {RenderContext} renderContext - The render context. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} passId - An optional ID for identifying the pass. + * @return {RenderObject} The render object. + */ get( object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ) { const chainMap = this.getChainMap( passId ); // reuse chainArray - chainArray[ 0 ] = object; - chainArray[ 1 ] = material; - chainArray[ 2 ] = renderContext; - chainArray[ 3 ] = lightsNode; + _chainKeys[ 0 ] = object; + _chainKeys[ 1 ] = material; + _chainKeys[ 2 ] = renderContext; + _chainKeys[ 3 ] = lightsNode; - let renderObject = chainMap.get( chainArray ); + let renderObject = chainMap.get( _chainKeys ); if ( renderObject === undefined ) { renderObject = this.createRenderObject( this.nodes, this.geometries, this.renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ); - chainMap.set( chainArray, renderObject ); + chainMap.set( _chainKeys, renderObject ); } else { @@ -64,22 +133,49 @@ class RenderObjects { } + _chainKeys.length = 0; + return renderObject; } + /** + * Returns a chain map for the given pass ID. + * + * @param {String} [passId='default'] - The pass ID. + * @return {ChainMap} The chain map. + */ getChainMap( passId = 'default' ) { return this.chainMaps[ passId ] || ( this.chainMaps[ passId ] = new ChainMap() ); } + /** + * Frees internal resources. + */ dispose() { this.chainMaps = {}; } + /** + * Factory method for creating render objects with the given list of parameters. + * + * @param {Nodes} nodes - Renderer component for managing nodes related logic. + * @param {Geometries} geometries - Renderer component for managing geometries. + * @param {Renderer} renderer - The renderer. + * @param {Object3D} object - The 3D object. + * @param {Material} material - The object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The lights node. + * @param {RenderContext} renderContext - The render context. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} passId - An optional ID for identifying the pass. + * @return {RenderObject} The render object. + */ createRenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext, passId ) { const chainMap = this.getChainMap( passId ); diff --git a/src/renderers/common/RenderPipeline.js b/src/renderers/common/RenderPipeline.js index d9aeadda798322..bcc91a22b5c2fa 100644 --- a/src/renderers/common/RenderPipeline.js +++ b/src/renderers/common/RenderPipeline.js @@ -1,12 +1,36 @@ import Pipeline from './Pipeline.js'; +/** + * Class for representing render pipelines. + * + * @private + * @augments Pipeline + */ class RenderPipeline extends Pipeline { + /** + * Constructs a new render pipeline. + * + * @param {String} cacheKey - The pipeline's cache key. + * @param {ProgrammableStage} vertexProgram - The pipeline's vertex shader. + * @param {ProgrammableStage} fragmentProgram - The pipeline's fragment shader. + */ constructor( cacheKey, vertexProgram, fragmentProgram ) { super( cacheKey ); + /** + * The pipeline's vertex shader. + * + * @type {ProgrammableStage} + */ this.vertexProgram = vertexProgram; + + /** + * The pipeline's fragment shader. + * + * @type {ProgrammableStage} + */ this.fragmentProgram = fragmentProgram; } diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index 140074613b420a..3291b833ac9063 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -27,6 +27,8 @@ import { Vector4 } from '../../math/Vector4.js'; import { RenderTarget } from '../../core/RenderTarget.js'; import { DoubleSide, BackSide, FrontSide, SRGBColorSpace, NoToneMapping, LinearFilter, LinearSRGBColorSpace, HalfFloatType, RGBAFormat, PCFShadowMap } from '../../constants.js'; +/** @module Renderer **/ + const _scene = /*@__PURE__*/ new Scene(); const _drawingBufferSize = /*@__PURE__*/ new Vector2(); const _screen = /*@__PURE__*/ new Vector4(); @@ -34,10 +36,34 @@ const _frustum = /*@__PURE__*/ new Frustum(); const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); const _vector4 = /*@__PURE__*/ new Vector4(); +/** + * Base class for renderers. + */ class Renderer { + /** + * Constructs a new renderer. + * + * @param {Backend} backend - The backend the renderer is targeting (e.g. WebGPU or WebGL 2). + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. This parameter can set to any other integer value than 0 + * to overwrite the default. + * @param {Function?} [parameters.getFallback=null] - This callback function can be used to provide a fallback backend, if the primary backend can't be targeted. + */ constructor( backend, parameters = {} ) { + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isRenderer = true; // @@ -52,32 +78,142 @@ class Renderer { getFallback = null } = parameters; - // public + /** + * A reference to the canvas element the renderer is drawing to. + * This value of this property will automatically be created by + * the renderer. + * + * @type {HTMLCanvasElement|OffscreenCanvas} + */ this.domElement = backend.getDomElement(); + /** + * A reference to the current backend. + * + * @type {Backend} + */ this.backend = backend; + /** + * The number of MSAA samples. + * + * @type {Number} + * @default 0 + */ this.samples = samples || ( antialias === true ) ? 4 : 0; + /** + * Whether the renderer should automatically clear the current rendering target + * before execute a `render()` call. The target can be the canvas (default framebuffer) + * or the current bound render target (custom framebuffer). + * + * @type {Boolean} + * @default true + */ this.autoClear = true; + + /** + * When `autoClear` is set to `true`, this property defines whether the renderer + * should clear the color buffer. + * + * @type {Boolean} + * @default true + */ this.autoClearColor = true; + + /** + * When `autoClear` is set to `true`, this property defines whether the renderer + * should clear the depth buffer. + * + * @type {Boolean} + * @default true + */ this.autoClearDepth = true; + + /** + * When `autoClear` is set to `true`, this property defines whether the renderer + * should clear the stencil buffer. + * + * @type {Boolean} + * @default true + */ this.autoClearStencil = true; + /** + * Whether the default framebuffer should be transparent or opaque. + * + * @type {Boolean} + * @default true + */ this.alpha = alpha; + /** + * Whether logarithmic depth buffer is enabled or not. + * + * @type {Boolean} + * @default false + */ this.logarithmicDepthBuffer = logarithmicDepthBuffer; + /** + * Defines the output color space of the renderer. + * + * @type {String} + * @default SRGBColorSpace + */ this.outputColorSpace = SRGBColorSpace; + /** + * Defines the tone mapping of the renderer. + * + * @type {Number} + * @default NoToneMapping + */ this.toneMapping = NoToneMapping; + + /** + * Defines the tone mapping exposure. + * + * @type {Number} + * @default 1 + */ this.toneMappingExposure = 1.0; + /** + * Whether the renderer should sort its render lists or not. + * + * Note: Sorting is used to attempt to properly render objects that have some degree of transparency. + * By definition, sorting objects may not work in all cases. Depending on the needs of application, + * it may be necessary to turn off sorting and use other methods to deal with transparency rendering + * e.g. manually determining each object's rendering order. + * + * @type {Boolean} + * @default true + */ this.sortObjects = true; + /** + * Whether the default framebuffer should have a depth buffer or not. + * + * @type {Boolean} + * @default true + */ this.depth = depth; + + /** + * Whether the default framebuffer should have a stencil buffer or not. + * + * @type {Boolean} + * @default false + */ this.stencil = stencil; + /** + * Holds a series of statistical information about the GPU memory + * and the rendering process. Useful for debugging and monitoring. + * + * @type {Info} + */ this.info = new Info(); this.nodes = { @@ -85,82 +221,449 @@ class Renderer { modelNormalViewMatrix: null }; + /** + * The node library defines how certain library objects like materials, lights + * or tone mapping functions are mapped to node types. This is required since + * although instances of classes like `MeshBasicMaterial` or `PointLight` can + * be part of the scene graph, they are internally represented as nodes for + * further processing. + * + * @type {NodeLibrary} + */ this.library = new NodeLibrary(); + + /** + * A map-like data structure for managing lights. + * + * @type {Lighting} + */ this.lighting = new Lighting(); // internals + /** + * This callback function can be used to provide a fallback backend, if the primary backend can't be targeted. + * + * @private + * @type {Function} + */ this._getFallback = getFallback; + /** + * The renderer's pixel ration. + * + * @private + * @type {Number} + * @default 1 + */ this._pixelRatio = 1; + + /** + * The width of the renderer's default framebuffer in logical pixel unit. + * + * @private + * @type {Number} + */ this._width = this.domElement.width; + + /** + * The height of the renderer's default framebuffer in logical pixel unit. + * + * @private + * @type {Number} + */ this._height = this.domElement.height; + /** + * The viewport of the renderer in logical pixel unit. + * + * @private + * @type {Vector4} + */ this._viewport = new Vector4( 0, 0, this._width, this._height ); + + /** + * The scissor rectangle of the renderer in logical pixel unit. + * + * @private + * @type {Vector4} + */ this._scissor = new Vector4( 0, 0, this._width, this._height ); + + /** + * Whether the scissor test should be enabled or not. + * + * @private + * @type {Boolean} + */ this._scissorTest = false; + /** + * A reference to a renderer module for managing shader attributes. + * + * @private + * @type {Attributes?} + * @default null + */ this._attributes = null; + + /** + * A reference to a renderer module for managing geometries. + * + * @private + * @type {Geometries?} + * @default null + */ this._geometries = null; + + /** + * A reference to a renderer module for managing node related logic. + * + * @private + * @type {Nodes?} + * @default null + */ this._nodes = null; + + /** + * A reference to a renderer module for managing the internal animation loop. + * + * @private + * @type {Animation?} + * @default null + */ this._animation = null; + + /** + * A reference to a renderer module for managing shader program bindings. + * + * @private + * @type {Bindings?} + * @default null + */ this._bindings = null; + + /** + * A reference to a renderer module for managing render objects. + * + * @private + * @type {RenderObjects?} + * @default null + */ this._objects = null; + + /** + * A reference to a renderer module for managing render and compute pipelines. + * + * @private + * @type {Pipelines?} + * @default null + */ this._pipelines = null; + + /** + * A reference to a renderer module for managing render bundles. + * + * @private + * @type {RenderBundles?} + * @default null + */ this._bundles = null; + + /** + * A reference to a renderer module for managing render lists. + * + * @private + * @type {RenderLists?} + * @default null + */ this._renderLists = null; + + /** + * A reference to a renderer module for managing render contexts. + * + * @private + * @type {RenderContexts?} + * @default null + */ this._renderContexts = null; + + /** + * A reference to a renderer module for managing textures. + * + * @private + * @type {Textures?} + * @default null + */ this._textures = null; + + /** + * A reference to a renderer module for backgrounds. + * + * @private + * @type {Background?} + * @default null + */ this._background = null; + /** + * This fullscreen quad is used for internal render passes + * like the tone mapping and color space output pass. + * + * @private + * @type {QuadMesh} + */ this._quad = new QuadMesh( new NodeMaterial() ); - this._quad.material.type = 'Renderer_output'; - + this._quad.material.name = 'Renderer_output'; + + /** + * A reference to the current render context. + * + * @private + * @type {RenderContext?} + * @default null + */ this._currentRenderContext = null; + /** + * A custom sort function for the opaque render list. + * + * @private + * @type {Function?} + * @default null + */ this._opaqueSort = null; + + /** + * A custom sort function for the transparent render list. + * + * @private + * @type {Function?} + * @default null + */ this._transparentSort = null; + /** + * The framebuffer target. + * + * @private + * @type {RenderTarget?} + * @default null + */ this._frameBufferTarget = null; const alphaClear = this.alpha === true ? 0 : 1; + /** + * The clear color value. + * + * @private + * @type {Color4} + */ this._clearColor = new Color4( 0, 0, 0, alphaClear ); + + /** + * The clear depth value. + * + * @private + * @type {Number} + * @default 1 + */ this._clearDepth = 1; + + /** + * The clear stencil value. + * + * @private + * @type {Number} + * @default 0 + */ this._clearStencil = 0; + /** + * The current render target. + * + * @private + * @type {RenderTarget?} + * @default null + */ this._renderTarget = null; + + /** + * The active cube face. + * + * @private + * @type {Number} + * @default 0 + */ this._activeCubeFace = 0; + + /** + * The active mipmap level. + * + * @private + * @type {Number} + * @default 0 + */ this._activeMipmapLevel = 0; + /** + * The MRT setting. + * + * @private + * @type {MRTNode?} + * @default null + */ this._mrt = null; + /** + * This function defines how a render object is going + * to be rendered. + * + * @private + * @type {Function?} + * @default null + */ this._renderObjectFunction = null; + + /** + * Used to keep track of the current render object function. + * + * @private + * @type {Function?} + * @default null + */ this._currentRenderObjectFunction = null; + + /** + * Used to keep track of the current render bundle. + * + * @private + * @type {RenderBundle?} + * @default null + */ this._currentRenderBundle = null; + /** + * Next to `_renderObjectFunction()`, this function provides another hook + * for influencing the render process of a render object. It is meant for internal + * use and only relevant for `compileAsync()` right now. Instead of using + * the default logic of `_renderObjectDirect()` which actually draws the render object, + * a different function might be used which performs no draw but just the node + * and pipeline updates. + * + * @private + * @type {Function?} + * @default null + */ this._handleObjectFunction = this._renderObjectDirect; + /** + * Indicates whether the device has been lost or not. In WebGL terms, the device + * lost is considered as a context lost. When this is set to `true`, rendering + * isn't possible anymore. + * + * @private + * @type {Boolean} + * @default false + */ this._isDeviceLost = false; + + /** + * A callback function that defines what should happen when a device/context lost occurs. + * + * @type {Function} + */ this.onDeviceLost = this._onDeviceLost; + /** + * Whether the renderer has been initialized or not. + * + * @private + * @type {Boolean} + * @default false + */ this._initialized = false; + + /** + * A reference to the promise which initializes the renderer. + * + * @private + * @type {Promise?} + * @default null + */ this._initPromise = null; + /** + * An array of compilation promises which are used in `compileAsync()`. + * + * @private + * @type {Array?} + * @default null + */ this._compilationPromises = null; + /** + * Whether the renderer should render transparent render objects or not. + * + * @type {Boolean} + * @default true + */ this.transparent = true; + + /** + * Whether the renderer should render opaque render objects or not. + * + * @type {Boolean} + * @default true + */ this.opaque = true; + /** + * Shadow map configuration + * @typedef {Object} ShadowMapConfig + * @property {Boolean} enabled - Whether to globally enable shadows or not. + * @property {Number} type - The shadow map type. + */ + + /** + * The renderer's shadow configuration. + * + * @type {module:Renderer~ShadowMapConfig} + */ this.shadowMap = { enabled: false, type: PCFShadowMap }; + /** + * XR configuration. + * @typedef {Object} XRConfig + * @property {Boolean} enabled - Whether to globally enable XR or not. + */ + + /** + * The renderer's XR configuration. + * + * @type {module:Renderer~XRConfig} + */ this.xr = { enabled: false }; + /** + * Debug configuration. + * @typedef {Object} DebugConfig + * @property {Boolean} checkShaderErrors - Whether shader errors should be checked or not. + * @property {Function} onShaderError - A callback function that is executed when a shader error happens. Only supported with WebGL 2 right now. + * @property {Function} getShaderAsync - Allows the get the raw shader code for the given scene, camera and 3D object. + */ + + /** + * The renderer's debug configuration. + * + * @type {module:Renderer~DebugConfig} + */ this.debug = { checkShaderErrors: true, onShaderError: null, @@ -184,6 +687,12 @@ class Renderer { } + /** + * Initializes the renderer so it is ready for usage. + * + * @async + * @return {Promise} A Promise that resolves when the renderer has been initialized. + */ async init() { if ( this._initialized ) { @@ -259,12 +768,35 @@ class Renderer { } + /** + * The coordinate system of the renderer. The value of this property + * depends on the selected backend. Either `THREE.WebGLCoordinateSystem` or + * `THREE.WebGPUCoordinateSystem`. + * + * @readonly + * @type {Number} + */ get coordinateSystem() { return this.backend.coordinateSystem; } + /** + * Compiles all materials in the given scene. This can be useful to avoid a + * phenomenon which is called "shader compilation stutter", which occurs when + * rendering an object with a new shader for the first time. + * + * If you want to add a 3D object to an existing scene, use the third optional + * parameter for applying the target scene. Note that the (target) scene's lighting + * and environment must be configured before calling this method. + * + * @async + * @param {Object3D} scene - The scene or 3D object to precompile. + * @param {Camera} camera - The camera that is used to render the scene. + * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. + * @return {Promise} A Promise that resolves when the compile has been finished. + */ async compileAsync( scene, camera, targetScene = null ) { if ( this._isDeviceLost === true ) return; @@ -361,10 +893,6 @@ class Renderer { // - this._nodes.updateScene( sceneRef ); - - // - this._background.update( sceneRef, renderList, renderContext ); // process render lists @@ -393,6 +921,14 @@ class Renderer { } + /** + * Renders the scene in an async fashion. + * + * @async + * @param {Object3D} scene - The scene or 3D object to render. + * @param {Camera} camera - The camera. + * @return {Promise} A Promise that resolves when the render has been finished. + */ async renderAsync( scene, camera ) { if ( this._initialized === false ) await this.init(); @@ -403,12 +939,25 @@ class Renderer { } + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ async waitForGPU() { await this.backend.waitForGPU(); } + /** + * Sets the given MRT configuration. + * + * @param {MRTNode} mrt - The MRT node to set. + * @return {Renderer} A reference to this renderer. + */ setMRT( mrt ) { this._mrt = mrt; @@ -417,12 +966,23 @@ class Renderer { } + /** + * Returns the MRT configuration. + * + * @return {MRTNode} The MRT configuration. + */ getMRT() { return this._mrt; } + /** + * Default implementation of the device lost callback. + * + * @private + * @param {Object} info - Information about the context lost. + */ _onDeviceLost( info ) { let errorMessage = `THREE.WebGPURenderer: ${info.api} Device Lost:\n\nMessage: ${info.message}`; @@ -439,7 +999,14 @@ class Renderer { } - + /** + * Renders the given render bundle. + * + * @private + * @param {Object} bundle - Render bundle data. + * @param {Scene} sceneRef - The scene the render bundle belongs to. + * @param {LightsNode} lightsNode - The current lights node. + */ _renderBundle( bundle, sceneRef, lightsNode ) { const { bundleGroup, camera, renderList } = bundle; @@ -511,6 +1078,18 @@ class Renderer { } + /** + * Renders the scene or 3D object with the given camera. This method can only be called + * if the renderer has been initialized. + * + * The target of the method is the default framebuffer (meaning the canvas) + * or alternatively a render target when specified via `setRenderTarget()`. + * + * @param {Object3D} scene - The scene or 3D object to render. + * @param {Camera} camera - The camera to render the scene with. + * @return {Promise?} A Promise that resolve when the scene has been rendered. + * Only returned when the renderer has not been initialized. + */ render( scene, camera ) { if ( this._initialized === false ) { @@ -525,6 +1104,14 @@ class Renderer { } + /** + * Returns an internal render target which is used when computing the output tone mapping + * and color space conversion. Unlike in `WebGLRenderer`, this is done in a separate render + * pass and not inline to achieve more correct results. + * + * @private + * @return {RenderTarget?} The render target. The method returns `null` if no output conversion should be applied. + */ _getFrameBufferTarget() { const { currentToneMapping, currentColorSpace } = this; @@ -572,6 +1159,15 @@ class Renderer { } + /** + * Renders the scene or 3D object with the given camera. + * + * @private + * @param {Object3D} scene - The scene or 3D object to render. + * @param {Camera} camera - The camera to render the scene with. + * @param {Boolean} [useFrameBufferTarget=true] - Whether to use a framebuffer target or not. + * @return {RenderContext} The current render context. + */ _renderScene( scene, camera, useFrameBufferTarget = true ) { if ( this._isDeviceLost === true ) return; @@ -737,10 +1333,6 @@ class Renderer { // - this._nodes.updateScene( sceneRef ); - - // - this._background.update( sceneRef, renderList, renderContext ); // @@ -801,24 +1393,48 @@ class Renderer { } + /** + * Returns the maximum available anisotropy for texture filtering. + * + * @return {Number} The maximum available anisotropy. + */ getMaxAnisotropy() { return this.backend.getMaxAnisotropy(); } + /** + * Returns the active cube face. + * + * @return {Number} The active cube face. + */ getActiveCubeFace() { return this._activeCubeFace; } + /** + * Returns the active mipmap level. + * + * @return {Number} The active mipmap level. + */ getActiveMipmapLevel() { return this._activeMipmapLevel; } + /** + * Applications are advised to always define the animation loop + * with this method and not manually with `requestAnimationFrame()` + * for best compatibility. + * + * @async + * @param {Function} callback - The application's animation loop. + * @return {Promise} A Promise that resolves when the set has been executed. + */ async setAnimationLoop( callback ) { if ( this._initialized === false ) await this.init(); @@ -827,36 +1443,71 @@ class Renderer { } + /** + * Can be used to transfer buffer data from a storage buffer attribute + * from the GPU to the CPU in context of compute shaders. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { return await this.backend.getArrayBufferAsync( attribute ); } + /** + * Returns the rendering context. + * + * @return {GPUCanvasContext|WebGL2RenderingContext} The rendering context. + */ getContext() { return this.backend.getContext(); } + /** + * Returns the pixel ratio. + * + * @return {Number} The pixel ratio. + */ getPixelRatio() { return this._pixelRatio; } + /** + * Returns the drawing buffer size in physical pixels. This method honors the pixel ratio. + * + * @param {Vector2} target - The method writes the result in this target object. + * @return {Vector2} The drawing buffer size. + */ getDrawingBufferSize( target ) { return target.set( this._width * this._pixelRatio, this._height * this._pixelRatio ).floor(); } + /** + * Returns the renderer's size in logical pixels. This method does not honor the pixel ratio. + * + * @param {Vector2} target - The method writes the result in this target object. + * @return {Vector2} The drawing buffer size. + */ getSize( target ) { return target.set( this._width, this._height ); } + /** + * Sets the given pixel ration and resizes the canvas if necessary. + * + * @param {Number} [value=1] - The pixel ratio. + */ setPixelRatio( value = 1 ) { if ( this._pixelRatio === value ) return; @@ -867,6 +1518,19 @@ class Renderer { } + /** + * This method allows to define the drawing buffer size by specifying + * width, height and pixel ratio all at once. The size of the drawing + * buffer is computed with this formula: + * ```` + * size.x = width * pixelRatio; + * size.y = height * pixelRatio; + *``` + * + * @param {Number} width - The width in logical pixels. + * @param {Number} height - The height in logical pixels. + * @param {Number} pixelRatio - The pixel ratio. + */ setDrawingBufferSize( width, height, pixelRatio ) { this._width = width; @@ -883,6 +1547,13 @@ class Renderer { } + /** + * Sets the size of the renderer. + * + * @param {Number} width - The width in logical pixels. + * @param {Number} height - The height in logical pixels. + * @param {Boolean} [updateStyle=true] - Whether to update the `style` attribute of the canvas or not. + */ setSize( width, height, updateStyle = true ) { this._width = width; @@ -904,18 +1575,36 @@ class Renderer { } + /** + * Defines a manual sort function for the opaque render list. + * Pass `null` to use the default sort. + * + * @param {Function} method - The sort function. + */ setOpaqueSort( method ) { this._opaqueSort = method; } + /** + * Defines a manual sort function for the transparent render list. + * Pass `null` to use the default sort. + * + * @param {Function} method - The sort function. + */ setTransparentSort( method ) { this._transparentSort = method; } + /** + * Returns the scissor rectangle. + * + * @param {Vector4} target - The method writes the result in this target object. + * @return {Vector4} The scissor rectangle. + */ getScissor( target ) { const scissor = this._scissor; @@ -929,6 +1618,15 @@ class Renderer { } + /** + * Defines the scissor rectangle. + * + * @param {Number | Vector4} x - The horizontal coordinate for the lower left corner of the box in logical pixel unit. + * Instead of passing four arguments, the method also works with a single four-dimensional vector. + * @param {Number} y - The vertical coordinate for the lower left corner of the box in logical pixel unit. + * @param {Number} width - The width of the scissor box in logical pixel unit. + * @param {Number} height - The height of the scissor box in logical pixel unit. + */ setScissor( x, y, width, height ) { const scissor = this._scissor; @@ -945,12 +1643,22 @@ class Renderer { } + /** + * Returns the scissor test value. + * + * @return {Boolean} Whether the scissor test should be enabled or not. + */ getScissorTest() { return this._scissorTest; } + /** + * Defines the scissor test. + * + * @param {Boolean} boolean - Whether the scissor test should be enabled or not. + */ setScissorTest( boolean ) { this._scissorTest = boolean; @@ -959,12 +1667,28 @@ class Renderer { } + /** + * Returns the viewport definition. + * + * @param {Vector4} target - The method writes the result in this target object. + * @return {Vector4} The viewport definition. + */ getViewport( target ) { return target.copy( this._viewport ); } + /** + * Defines the viewport. + * + * @param {Number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit. + * @param {Number} y - The vertical coordinate for the lower left corner of the viewport origin in logical pixel unit. + * @param {Number} width - The width of the viewport in logical pixel unit. + * @param {Number} height - The height of the viewport in logical pixel unit. + * @param {Number} minDepth - The minimum depth value of the viewport. WebGPU only. + * @param {Number} maxDepth - The maximum depth value of the viewport. WebGPU only. + */ setViewport( x, y, width, height, minDepth = 0, maxDepth = 1 ) { const viewport = this._viewport; @@ -984,12 +1708,24 @@ class Renderer { } + /** + * Returns the clear color. + * + * @param {Color} target - The method writes the result in this target object. + * @return {Color} The clear color. + */ getClearColor( target ) { return target.copy( this._clearColor ); } + /** + * Defines the clear color and optionally the clear alpha. + * + * @param {Color} color - The clear color. + * @param {Number} [alpha=1] - The clear alpha. + */ setClearColor( color, alpha = 1 ) { this._clearColor.set( color ); @@ -997,42 +1733,80 @@ class Renderer { } + /** + * Returns the clear alpha. + * + * @return {Number} The clear alpha. + */ getClearAlpha() { return this._clearColor.a; } + /** + * Defines the clear alpha. + * + * @param {Number} alpha - The clear alpha. + */ setClearAlpha( alpha ) { this._clearColor.a = alpha; } + /** + * Returns the clear depth. + * + * @return {Number} The clear depth. + */ getClearDepth() { return this._clearDepth; } + /** + * Defines the clear depth. + * + * @param {Number} depth - The clear depth. + */ setClearDepth( depth ) { this._clearDepth = depth; } + /** + * Returns the clear stencil. + * + * @return {Number} The clear stencil. + */ getClearStencil() { return this._clearStencil; } + /** + * Defines the clear stencil. + * + * @param {Number} stencil - The clear stencil. + */ setClearStencil( stencil ) { this._clearStencil = stencil; } + /** + * This method performs an occlusion query for the given 3D object. + * It returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. + * + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ isOccluded( object ) { const renderContext = this._currentRenderContext; @@ -1041,6 +1815,15 @@ class Renderer { } + /** + * Performs a manual clear operation. This method ignores `autoClear` properties. + * + * @param {Boolean} [color=true] - Whether the color buffer should be cleared or not. + * @param {Boolean} [depth=true] - Whether the depth buffer should be cleared or not. + * @param {Boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clear( color = true, depth = true, stencil = true ) { if ( this._initialized === false ) { @@ -1053,17 +1836,26 @@ class Renderer { const renderTarget = this._renderTarget || this._getFrameBufferTarget(); - let renderTargetData = null; + let renderContext = null; if ( renderTarget !== null ) { this._textures.updateRenderTarget( renderTarget ); - renderTargetData = this._textures.get( renderTarget ); + const renderTargetData = this._textures.get( renderTarget ); + + renderContext = this._renderContexts.getForClear( 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; } - this.backend.clear( color, depth, stencil, renderTargetData ); + this.backend.clear( color, depth, stencil, renderContext ); if ( renderTarget !== null && this._renderTarget === null ) { @@ -1085,24 +1877,51 @@ class Renderer { } + /** + * Performs a manual clear operation of the color buffer. This method ignores `autoClear` properties. + * + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clearColor() { return this.clear( true, false, false ); } + /** + * Performs a manual clear operation of the depth buffer. This method ignores `autoClear` properties. + * + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clearDepth() { return this.clear( false, true, false ); } + /** + * Performs a manual clear operation of the stencil buffer. This method ignores `autoClear` properties. + * + * @return {Promise} A Promise that resolves when the clear operation has been executed. + * Only returned when the renderer has not been initialized. + */ clearStencil() { return this.clear( false, false, true ); } + /** + * Async version of {@link module:Renderer~Renderer#clear}. + * + * @async + * @param {Boolean} [color=true] - Whether the color buffer should be cleared or not. + * @param {Boolean} [depth=true] - Whether the depth buffer should be cleared or not. + * @param {Boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ async clearAsync( color = true, depth = true, stencil = true ) { if ( this._initialized === false ) await this.init(); @@ -1111,36 +1930,70 @@ class Renderer { } - clearColorAsync() { + /** + * Async version of {@link module:Renderer~Renderer#clearColor}. + * + * @async + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ + async clearColorAsync() { - return this.clearAsync( true, false, false ); + this.clearAsync( true, false, false ); } - clearDepthAsync() { + /** + * Async version of {@link module:Renderer~Renderer#clearDepth}. + * + * @async + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ + async clearDepthAsync() { - return this.clearAsync( false, true, false ); + this.clearAsync( false, true, false ); } - clearStencilAsync() { + /** + * Async version of {@link module:Renderer~Renderer#clearStencil}. + * + * @async + * @return {Promise} A Promise that resolves when the clear operation has been executed. + */ + async clearStencilAsync() { - return this.clearAsync( false, false, true ); + this.clearAsync( false, false, true ); } + /** + * The current output tone mapping of the renderer. When a render target is set, + * the output tone mapping is always `NoToneMapping`. + * + * @type {Number} + */ get currentToneMapping() { return this._renderTarget !== null ? NoToneMapping : this.toneMapping; } + /** + * The current output color space of the renderer. When a render target is set, + * the output color space is always `LinearSRGBColorSpace`. + * + * @type {String} + */ get currentColorSpace() { return this._renderTarget !== null ? LinearSRGBColorSpace : this.outputColorSpace; } + /** + * Frees all internal resources of the renderer. Call this method if the renderer + * is no longer in use by your app. + */ dispose() { this.info.dispose(); @@ -1160,6 +2013,15 @@ class Renderer { } + /** + * Sets the given render target. Calling this method means the renderer does not + * target the default framebuffer (meaning the canvas) anymore but a custom framebuffer. + * Use `null` as the first argument to reset the state. + * + * @param {RenderTarget?} renderTarget - The render target to set. + * @param {Number} [activeCubeFace=0] - The active cube face. + * @param {Number} [activeMipmapLevel=0] - The active mipmap level. + */ setRenderTarget( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { this._renderTarget = renderTarget; @@ -1168,27 +2030,70 @@ class Renderer { } + /** + * Returns the current render target. + * + * @return {RenderTarget?} The render target. Returns `null` if no render target is set. + */ getRenderTarget() { return this._renderTarget; } + /** + * Callback for {@link module:Renderer~Renderer#setRenderObjectFunction}. + * + * @callback renderObjectFunction + * @param {Object3D} object - The 3D object. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {BufferGeometry} geometry - The object's geometry. + * @param {Material} material - The object's material. + * @param {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {LightsNode} lightsNode - The current lights node. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ + + /** + * Sets the given render object function. Calling this method overwrites the default implementation + * which is {@link module:Renderer~Renderer#renderObject}. Defining a custom function can be useful + * if you want to modify the way objects are rendered. For example you can define things like "every + * object that has material of a certain type should perform a pre-pass with a special overwrite material". + * The custom function must always call `renderObject()` in its implementation. + * + * Use `null` as the first argument to reset the state. + * + * @param {module:Renderer~renderObjectFunction?} renderObjectFunction - The render object function. + */ setRenderObjectFunction( renderObjectFunction ) { this._renderObjectFunction = renderObjectFunction; } + /** + * Returns the current render object function. + * + * @return {Function?} The current render object function. Returns `null` if no function is set. + */ getRenderObjectFunction() { return this._renderObjectFunction; } + /** + * Execute a single or an array of compute nodes. This method can only be called + * if the renderer has been initialized. + * + * @param {Node|Array} computeNodes - The compute node(s). + * @return {Promise?} A Promise that resolve when the compute has finished. Only returned when the renderer has not been initialized. + */ compute( computeNodes ) { - if ( this.isDeviceLost === true ) return; + if ( this._isDeviceLost === true ) return; if ( this._initialized === false ) { @@ -1277,6 +2182,13 @@ class Renderer { } + /** + * Execute a single or an array of compute nodes. + * + * @async + * @param {Node|Array} computeNodes - The compute node(s). + * @return {Promise} A Promise that resolve when the compute has finished. + */ async computeAsync( computeNodes ) { if ( this._initialized === false ) await this.init(); @@ -1287,6 +2199,13 @@ class Renderer { } + /** + * Checks if the given feature is supported by the selected backend. + * + * @async + * @param {String} name - The feature's name. + * @return {Promise} A Promise that resolves with a bool that indicates whether the feature is supported or not. + */ async hasFeatureAsync( name ) { if ( this._initialized === false ) await this.init(); @@ -1295,6 +2214,13 @@ class Renderer { } + /** + * Checks if the given feature is supported by the selected backend. If the + * renderer has not been initialized, this method always returns `false`. + * + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ hasFeature( name ) { if ( this._initialized === false ) { @@ -1309,12 +2235,25 @@ class Renderer { } + /** + * Returns `true` when the renderer has been initialized. + * + * @return {Boolean} Whether the renderer has been initialized or not. + */ hasInitialized() { return this._initialized; } + /** + * Initializes the given textures. Useful for preloading a texture rather than waiting until first render + * (which can cause noticeable lags due to decode and GPU upload overhead). + * + * @async + * @param {Texture} texture - The texture. + * @return {Promise} A Promise that resolves when the texture has been initialized. + */ async initTextureAsync( texture ) { if ( this._initialized === false ) await this.init(); @@ -1323,20 +2262,32 @@ class Renderer { } + /** + * Initializes the given textures. Useful for preloading a texture rather than waiting until first render + * (which can cause noticeable lags due to decode and GPU upload overhead). + * + * This method can only be used if the renderer has been initialized. + * + * @param {Texture} texture - The texture. + */ initTexture( texture ) { if ( this._initialized === false ) { console.warn( 'THREE.Renderer: .initTexture() called before the backend is initialized. Try using .initTextureAsync() instead.' ); - return false; - } this._textures.updateTexture( texture ); } + /** + * Copies the current bound framebuffer into the given texture. + * + * @param {FramebufferTexture} framebufferTexture - The texture. + * @param {Vector2|Vector4} rectangle - A two or four dimensional vector that defines the rectangular portion of the framebuffer that should be copied. + */ copyFramebufferToTexture( framebufferTexture, rectangle = null ) { if ( rectangle !== null ) { @@ -1394,6 +2345,15 @@ class Renderer { } + /** + * Copies data of source texture into a destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Box2|Box3} [srcRegion=null] - A bounding box which describes the source region. Can be two or three-dimensional. + * @param {Vector2|Vector3} [dstPosition=null] - A vector that represents the origin of the destination region. Can be two or three-dimensional. + * @param {Number} level - The mipmap level to copy. + */ copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { this._textures.updateTexture( srcTexture ); @@ -1403,12 +2363,35 @@ class Renderer { } - readRenderTargetPixelsAsync( renderTarget, x, y, width, height, index = 0, faceIndex = 0 ) { - - return this.backend.copyTextureToBuffer( renderTarget.textures[ index ], x, y, width, height, faceIndex ); - - } - + /** + * Reads pixel data from the given render target. + * + * @async + * @param {RenderTarget} renderTarget - The render target to read from. + * @param {Number} x - The `x` coordinate of the copy region's origin. + * @param {Number} y - The `y` coordinate of the copy region's origin. + * @param {Number} width - The width of the copy region. + * @param {Number} height - The height of the copy region. + * @param {Number} [textureIndex=0] - The texture index of a MRT render target. + * @param {Number} [faceIndex=0] - The active cube face index. + * @return {Promise} A Promise that resolves when the read has been finished. The resolve provides the read data as a typed array. + */ + async readRenderTargetPixelsAsync( renderTarget, x, y, width, height, textureIndex = 0, faceIndex = 0 ) { + + return this.backend.copyTextureToBuffer( renderTarget.textures[ textureIndex ], x, y, width, height, faceIndex ); + + } + + /** + * Analyzes the given 3D object's hierarchy and builds render lists from the + * processed hierarchy. + * + * @param {Object3D} object - The 3D object to process (usually a scene). + * @param {Camera} camera - The camera the object is rendered with. + * @param {Number} groupOrder - The group order is derived from the `renderOrder` of groups and is used to group 3D objects within groups. + * @param {RenderList} renderList - The current render list. + * @param {ClippingContext} clippingContext - The current clipping context. + */ _projectObject( object, camera, groupOrder, renderList, clippingContext ) { if ( object.visible === false ) return; @@ -1530,6 +2513,14 @@ class Renderer { } + /** + * Renders the given render bundles. + * + * @private + * @param {Array} bundles - Array with render bundle data. + * @param {Scene} sceneRef - The scene the render bundles belong to. + * @param {LightsNode} lightsNode - The current lights node. + */ _renderBundles( bundles, sceneRef, lightsNode ) { for ( const bundle of bundles ) { @@ -1540,6 +2531,16 @@ class Renderer { } + /** + * Renders the transparent objects from the given render lists. + * + * @private + * @param {Array} renderList - The transparent render list. + * @param {Array} doublePassList - The list of transparent objects which require a double pass (e.g. because of transmission). + * @param {Camera} camera - The camera the render list should be rendered with. + * @param {Scene} scene - The scene the render list belongs to. + * @param {LightsNode} lightsNode - The current lights node. + */ _renderTransparents( renderList, doublePassList, camera, scene, lightsNode ) { if ( doublePassList.length > 0 ) { @@ -1580,6 +2581,16 @@ class Renderer { } + /** + * Renders the objects from the given render list. + * + * @private + * @param {Array} renderList - The render list. + * @param {Camera} camera - The camera the render list should be rendered with. + * @param {Scene} scene - The scene the render list belongs to. + * @param {LightsNode} lightsNode - The current lights node. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ _renderObjects( renderList, camera, scene, lightsNode, passId = null ) { // process renderable objects @@ -1588,9 +2599,6 @@ class Renderer { 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, clippingContext } = renderItem; if ( camera.isArrayCamera ) { @@ -1611,6 +2619,7 @@ class Renderer { viewportValue.copy( vp ).multiplyScalar( this._pixelRatio ).floor(); viewportValue.minDepth = minDepth; viewportValue.maxDepth = maxDepth; + this._currentRenderContext.viewport = true; this.backend.updateViewport( this._currentRenderContext ); @@ -1630,6 +2639,20 @@ class Renderer { } + /** + * This method represents the default render object function that manages the render lifecycle + * of the object. + * + * @param {Object3D} object - The 3D object. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {BufferGeometry} geometry - The object's geometry. + * @param {Material} material - The object's material. + * @param {Object?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {LightsNode} lightsNode - The current lights node. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ renderObject( object, scene, camera, geometry, material, group, lightsNode, clippingContext = null, passId = null ) { let overridePositionNode; @@ -1657,7 +2680,7 @@ class Renderer { overrideMaterial.alphaMap = material.alphaMap; overrideMaterial.transparent = material.transparent || material.transmission > 0; - if ( overrideMaterial.isShadowNodeMaterial ) { + if ( overrideMaterial.isShadowPassMaterial ) { overrideMaterial.side = material.shadowSide === null ? material.side : material.shadowSide; @@ -1725,6 +2748,20 @@ class Renderer { } + /** + * This method represents the default `_handleObjectFunction` implementation which creates + * a render object from the given data and performs the draw command with the selected backend. + * + * @private + * @param {Object3D} object - The 3D object. + * @param {Material} material - The object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The current lights node. + * @param {{start: Number, count: Number}?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ _renderObjectDirect( object, material, scene, camera, lightsNode, group, clippingContext, passId ) { const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId ); @@ -1756,7 +2793,7 @@ class Renderer { renderBundleData.renderObjects.push( renderObject ); - renderObject.bundle = this._currentRenderBundle.scene; + renderObject.bundle = this._currentRenderBundle.bundleGroup; } @@ -1766,6 +2803,20 @@ class Renderer { } + /** + * A different implementation for `_handleObjectFunction` which only makes sure the object is ready for rendering. + * Used in `compileAsync()`. + * + * @private + * @param {Object3D} object - The 3D object. + * @param {Material} material - The object's material. + * @param {Scene} scene - The scene the 3D object belongs to. + * @param {Camera} camera - The camera the object should be rendered with. + * @param {LightsNode} lightsNode - The current lights node. + * @param {{start: Number, count: Number}?} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`. + * @param {ClippingContext} clippingContext - The clipping context. + * @param {String?} [passId=null] - An optional ID for identifying the pass. + */ _createObjectPipeline( object, material, scene, camera, lightsNode, group, clippingContext, passId ) { const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, clippingContext, passId ); @@ -1787,6 +2838,15 @@ class Renderer { } + /** + * Alias for `compileAsync()`. + * + * @method + * @param {Object3D} scene - The scene or 3D object to precompile. + * @param {Camera} camera - The camera that is used to render the scene. + * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. + * @return {Promise} A Promise that resolves when the compile has been finished. + */ get compile() { return this.compileAsync; diff --git a/src/renderers/common/RendererUtils.js b/src/renderers/common/RendererUtils.js new file mode 100644 index 00000000000000..7de30175de4428 --- /dev/null +++ b/src/renderers/common/RendererUtils.js @@ -0,0 +1,193 @@ +import { Color } from '../../math/Color.js'; + +/** @module RendererUtils **/ + +/** + * Saves the state of the given renderer and stores it into the given state object. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +export function saveRendererState( renderer, state = {} ) { + + state.toneMapping = renderer.toneMapping; + state.toneMappingExposure = renderer.toneMappingExposure; + state.outputColorSpace = renderer.outputColorSpace; + state.renderTarget = renderer.getRenderTarget(); + state.activeCubeFace = renderer.getActiveCubeFace(); + state.activeMipmapLevel = renderer.getActiveMipmapLevel(); + state.renderObjectFunction = renderer.getRenderObjectFunction(); + state.pixelRatio = renderer.getPixelRatio(); + state.mrt = renderer.getMRT(); + state.clearColor = renderer.getClearColor( state.clearColor || new Color() ); + state.clearAlpha = renderer.getClearAlpha(); + state.autoClear = renderer.autoClear; + state.scissorTest = renderer.getScissorTest(); + + return state; + +} + +/** + * Saves the state of the given renderer and stores it into the given state object. + * Besides, the function also resets the state of the renderer to its default values. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +export function resetRendererState( renderer, state ) { + + state = saveRendererState( renderer, state ); + + renderer.setMRT( null ); + renderer.setRenderObjectFunction( null ); + renderer.setClearColor( 0x000000, 1 ); + renderer.autoClear = true; + + return state; + +} + +/** + * Restores the state of the given renderer from the given state object. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Object} state - The state to restore. + */ +export function restoreRendererState( renderer, state ) { + + renderer.toneMapping = state.toneMapping; + renderer.toneMappingExposure = state.toneMappingExposure; + renderer.outputColorSpace = state.outputColorSpace; + renderer.setRenderTarget( state.renderTarget, state.activeCubeFace, state.activeMipmapLevel ); + renderer.setRenderObjectFunction( state.renderObjectFunction ); + renderer.setPixelRatio( state.pixelRatio ); + renderer.setMRT( state.mrt ); + renderer.setClearColor( state.clearColor, state.clearAlpha ); + renderer.autoClear = state.autoClear; + renderer.setScissorTest( state.scissorTest ); + +} + +/** + * Saves the state of the given scene and stores it into the given state object. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +export function saveSceneState( scene, state = {} ) { + + state.background = scene.background; + state.backgroundNode = scene.backgroundNode; + state.overrideMaterial = scene.overrideMaterial; + + return state; + +} + +/** + * Saves the state of the given scene and stores it into the given state object. + * Besides, the function also resets the state of the scene to its default values. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +export function resetSceneState( scene, state ) { + + state = saveSceneState( scene, state ); + + scene.background = null; + scene.backgroundNode = null; + scene.overrideMaterial = null; + + return state; + +} + +/** + * Restores the state of the given scene from the given state object. + * + * @function + * @param {Scene} scene - The scene. + * @param {Object} state - The state to restore. + */ +export function restoreSceneState( scene, state ) { + + scene.background = state.background; + scene.backgroundNode = state.backgroundNode; + scene.overrideMaterial = state.overrideMaterial; + +} + +/** + * Saves the state of the given renderer and scene and stores it into the given state object. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +export function saveRendererAndSceneState( renderer, scene, state = {} ) { + + state = saveRendererState( renderer, state ); + state = saveSceneState( scene, state ); + + return state; + +} + +/** + * Saves the state of the given renderer and scene and stores it into the given state object. + * Besides, the function also resets the state of the renderer and scene to its default values. + * + * If not state object is provided, the function creates one. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Scene} scene - The scene. + * @param {Object} [state={}] - The state. + * @return {Object} The state. + */ +export function resetRendererAndSceneState( renderer, scene, state ) { + + state = resetRendererState( renderer, state ); + state = resetSceneState( scene, state ); + + return state; + +} + +/** + * Restores the state of the given renderer and scene from the given state object. + * + * @function + * @param {Renderer} renderer - The renderer. + * @param {Scene} scene - The scene. + * @param {Object} state - The state to restore. + */ +export function restoreRendererAndSceneState( renderer, scene, state ) { + + restoreRendererState( renderer, state ); + restoreSceneState( scene, state ); + +} diff --git a/src/renderers/common/SampledTexture.js b/src/renderers/common/SampledTexture.js index 6e4ff0c92201e9..3d54b9f3ab173a 100644 --- a/src/renderers/common/SampledTexture.js +++ b/src/renderers/common/SampledTexture.js @@ -2,23 +2,80 @@ import Binding from './Binding.js'; let _id = 0; +/** + * Represents a sampled texture binding type. + * + * @private + * @augments Binding + */ class SampledTexture extends Binding { + /** + * Constructs a new sampled texture. + * + * @param {String} name - The sampled texture's name. + * @param {Texture?} texture - The texture this binding is referring to. + */ constructor( name, texture ) { super( name ); + /** + * This identifier. + * + * @type {Number} + */ this.id = _id ++; + /** + * The texture this binding is referring to. + * + * @type {Texture?} + */ this.texture = texture; + + /** + * The binding's version. + * + * @type {Number} + */ this.version = texture ? texture.version : 0; + + /** + * Whether the texture is a storage texture or not. + * + * @type {Boolean} + * @default false + */ this.store = false; + + /** + * The binding's generation which is an additional version + * qualifier. + * + * @type {Number?} + * @default null + */ this.generation = null; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledTexture = true; } + /** + * Returns `true` whether this binding requires an update for the + * given generation. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether an update is required or not. + */ needsBindingsUpdate( generation ) { const { texture } = this; @@ -35,6 +92,12 @@ class SampledTexture extends Binding { } + /** + * Updates the binding. + * + * @return {Boolean} Whether the texture has been updated and must be + * uploaded to the GPU. + */ update() { const { texture, version } = this; @@ -53,36 +116,93 @@ class SampledTexture extends Binding { } +/** + * Represents a sampled array texture binding type. + * + * @private + * @augments SampledTexture + */ class SampledArrayTexture extends SampledTexture { + /** + * Constructs a new sampled array texture. + * + * @param {String} name - The sampled array texture's name. + * @param {(DataArrayTexture|CompressedArrayTexture)?} texture - The texture this binding is referring to. + */ constructor( name, texture ) { super( name, texture ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledArrayTexture = true; } } +/** + * Represents a sampled 3D texture binding type. + * + * @private + * @augments SampledTexture + */ class Sampled3DTexture extends SampledTexture { + /** + * Constructs a new sampled 3D texture. + * + * @param {String} name - The sampled 3D texture's name. + * @param {Data3DTexture?} texture - The texture this binding is referring to. + */ constructor( name, texture ) { super( name, texture ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampled3DTexture = true; } } +/** + * Represents a sampled cube texture binding type. + * + * @private + * @augments SampledTexture + */ class SampledCubeTexture extends SampledTexture { + /** + * Constructs a new sampled cube texture. + * + * @param {String} name - The sampled cube texture's name. + * @param {(CubeTexture|CompressedCubeTexture)?} texture - The texture this binding is referring to. + */ constructor( name, texture ) { super( name, texture ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledCubeTexture = true; } diff --git a/src/renderers/common/Sampler.js b/src/renderers/common/Sampler.js index ccbdd0e5544bd2..82e86ae3daef8c 100644 --- a/src/renderers/common/Sampler.js +++ b/src/renderers/common/Sampler.js @@ -1,14 +1,44 @@ import Binding from './Binding.js'; +/** + * Represents a sampler binding type. + * + * @private + * @augments Binding + */ class Sampler extends Binding { + /** + * Constructs a new sampler. + * + * @param {String} name - The samplers's name. + * @param {Texture?} texture - The texture this binding is referring to. + */ constructor( name, texture ) { super( name ); + /** + * The texture the sampler is referring to. + * + * @type {Texture?} + */ this.texture = texture; + + /** + * The binding's version. + * + * @type {Number} + */ this.version = texture ? texture.version : 0; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampler = true; } diff --git a/src/renderers/common/StorageBuffer.js b/src/renderers/common/StorageBuffer.js index 8c353e78a4fefd..1411c15941912a 100644 --- a/src/renderers/common/StorageBuffer.js +++ b/src/renderers/common/StorageBuffer.js @@ -1,13 +1,37 @@ import Buffer from './Buffer.js'; +/** + * Represents a storage buffer binding type. + * + * @private + * @augments Buffer + */ class StorageBuffer extends Buffer { + /** + * Constructs a new uniform buffer. + * + * @param {String} name - The buffer's name. + * @param {BufferAttribute} attribute - The buffer attribute. + */ constructor( name, attribute ) { super( name, attribute ? attribute.array : null ); + /** + * This flag can be used for type testing. + * + * @type {BufferAttribute} + */ this.attribute = attribute; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageBuffer = true; } diff --git a/src/renderers/common/StorageBufferAttribute.js b/src/renderers/common/StorageBufferAttribute.js index 0ce8fb0485c5fc..f978041afbdb5c 100644 --- a/src/renderers/common/StorageBufferAttribute.js +++ b/src/renderers/common/StorageBufferAttribute.js @@ -1,13 +1,42 @@ import { BufferAttribute } from '../../core/BufferAttribute.js'; +/** + * This special type of buffer attribute is intended for compute shaders. + * In earlier three.js versions it was only possible to update attribute data + * on the CPU via JavaScript and then upload the data to the GPU. With the + * new material system and renderer it is now possible to use compute shaders + * to compute the data for an attribute more efficiently on the GPU. + * + * The idea is to create an instance of this class and provide it as an input + * to {@link module:StorageBufferNode}. + * + * Note: This type of buffer attribute can only be used with `WebGPURenderer`. + * + * @augments BufferAttribute + */ class StorageBufferAttribute extends BufferAttribute { - constructor( array, itemSize, typeClass = Float32Array ) { + /** + * Constructs a new storage buffer attribute. + * + * @param {Number|TypedArray} count - The item count. It is also valid to pass a typed array as an argument. + * The subsequent parameters are then obsolete. + * @param {Number} itemSize - The item size. + * @param {TypedArray.constructor} [typeClass=Float32Array] - A typed array constructor. + */ + constructor( count, itemSize, typeClass = Float32Array ) { - if ( ArrayBuffer.isView( array ) === false ) array = new typeClass( array * itemSize ); + const array = ArrayBuffer.isView( count ) ? count : new typeClass( count * itemSize ); super( array, itemSize ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageBufferAttribute = true; } diff --git a/src/renderers/common/StorageInstancedBufferAttribute.js b/src/renderers/common/StorageInstancedBufferAttribute.js index 8ccbaae56274ac..b3e484ddaadc46 100644 --- a/src/renderers/common/StorageInstancedBufferAttribute.js +++ b/src/renderers/common/StorageInstancedBufferAttribute.js @@ -1,13 +1,42 @@ import { InstancedBufferAttribute } from '../../core/InstancedBufferAttribute.js'; +/** + * This special type of instanced buffer attribute is intended for compute shaders. + * In earlier three.js versions it was only possible to update attribute data + * on the CPU via JavaScript and then upload the data to the GPU. With the + * new material system and renderer it is now possible to use compute shaders + * to compute the data for an attribute more efficiently on the GPU. + * + * The idea is to create an instance of this class and provide it as an input + * to {@link module:StorageBufferNode}. + * + * Note: This type of buffer attribute can only be used with `WebGPURenderer`. + * + * @augments InstancedBufferAttribute + */ class StorageInstancedBufferAttribute extends InstancedBufferAttribute { - constructor( array, itemSize, typeClass = Float32Array ) { + /** + * Constructs a new storage instanced buffer attribute. + * + * @param {Number|TypedArray} count - The item count. It is also valid to pass a typed array as an argument. + * The subsequent parameters are then obsolete. + * @param {Number} itemSize - The item size. + * @param {TypedArray.constructor} [typeClass=Float32Array] - A typed array constructor. + */ + constructor( count, itemSize, typeClass = Float32Array ) { - if ( ArrayBuffer.isView( array ) === false ) array = new typeClass( array * itemSize ); + const array = ArrayBuffer.isView( count ) ? count : new typeClass( count * itemSize ); super( array, itemSize ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageInstancedBufferAttribute = true; } diff --git a/src/renderers/common/StorageTexture.js b/src/renderers/common/StorageTexture.js index d5a2742c99e0c8..ff63bd07d60c15 100644 --- a/src/renderers/common/StorageTexture.js +++ b/src/renderers/common/StorageTexture.js @@ -1,17 +1,55 @@ import { Texture } from '../../textures/Texture.js'; import { LinearFilter } from '../../constants.js'; +/** + * This special type of texture is intended for compute shaders. + * It can be used to compute the data of a texture with a compute shader. + * + * Note: This type of texture can only be used with `WebGPURenderer` + * and a WebGPU backend. + * + * @augments Texture + */ class StorageTexture extends Texture { + /** + * Constructs a new storage texture. + * + * @param {Number} [width=1] - The storage texture's width. + * @param {Number} [height=1] - The storage texture's height. + */ constructor( width = 1, height = 1 ) { super(); + /** + * The image object which just represents the texture's dimension. + * + * @type {{width: Number, height: Number}} + */ this.image = { width, height }; + /** + * The default `magFilter` for storage textures is `THREE.LinearFilter`. + * + * @type {Number} + */ this.magFilter = LinearFilter; + + /** + * The default `minFilter` for storage textures is `THREE.LinearFilter`. + * + * @type {Number} + */ this.minFilter = LinearFilter; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isStorageTexture = true; } diff --git a/src/renderers/common/Textures.js b/src/renderers/common/Textures.js index 84635f0f95abfe..907c9c325bf940 100644 --- a/src/renderers/common/Textures.js +++ b/src/renderers/common/Textures.js @@ -6,18 +6,55 @@ import { DepthStencilFormat, DepthFormat, UnsignedIntType, UnsignedInt248Type, E const _size = /*@__PURE__*/ new Vector3(); +/** + * This module manages the textures of the renderer. + * + * @private + * @augments DataMap + */ class Textures extends DataMap { + /** + * Constructs a new texture management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Backend} backend - The renderer's backend. + * @param {Info} info - Renderer component for managing metrics and monitoring data. + */ constructor( renderer, backend, info ) { super(); + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * The backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * Renderer component for managing metrics and monitoring data. + * + * @type {Info} + */ this.info = info; } + /** + * Updates the given render target. Based on the given render target configuration, + * it updates the texture states representing the attachments of the framebuffer. + * + * @param {RenderTarget} renderTarget - The render target to update. + * @param {Number} [activeMipmapLevel=0] - The active mipmap level. + */ updateRenderTarget( renderTarget, activeMipmapLevel = 0 ) { const renderTargetData = this.get( renderTarget ); @@ -139,6 +176,14 @@ class Textures extends DataMap { } + /** + * Updates the given texture. Depending on the texture state, this method + * triggers the upload of texture data to the GPU memory. If the texture data are + * not yet ready for the upload, it uses default texture data for as a placeholder. + * + * @param {Texture} texture - The texture to update. + * @param {Object} [options={}] - The options. + */ updateTexture( texture, options = {} ) { const textureData = this.get( texture ); @@ -292,6 +337,18 @@ class Textures extends DataMap { } + /** + * Computes the size of the given texture and writes the result + * into the target vector. This vector is also returned by the + * method. + * + * If no texture data are available for the compute yet, the method + * returns default size values. + * + * @param {Texture} texture - The texture to compute the size for. + * @param {Vector3} target - The target vector. + * @return {Vector3} The target vector. + */ getSize( texture, target = _size ) { let image = texture.images ? texture.images[ 0 ] : texture.image; @@ -314,6 +371,14 @@ class Textures extends DataMap { } + /** + * Computes the number of mipmap levels for the given texture. + * + * @param {Texture} texture - The texture. + * @param {Number} width - The texture's width. + * @param {Number} height - The texture's height. + * @return {Number} The number of mipmap levels. + */ getMipLevels( texture, width, height ) { let mipLevelCount; @@ -340,12 +405,24 @@ class Textures extends DataMap { } + /** + * Returns `true` if the given texture requires mipmaps. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether mipmaps are required or not. + */ needsMipmaps( texture ) { return this.isEnvironmentTexture( texture ) || texture.isCompressedTexture === true || texture.generateMipmaps; } + /** + * Returns `true` if the given texture is an environment map. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the given texture is an environment map or not. + */ isEnvironmentTexture( texture ) { const mapping = texture.mapping; @@ -354,6 +431,12 @@ class Textures extends DataMap { } + /** + * Frees internal resource when the given texture isn't + * required anymore. + * + * @param {Texture} texture - The texture to destroy. + */ _destroyTexture( texture ) { this.backend.destroySampler( texture ); diff --git a/src/renderers/common/Uniform.js b/src/renderers/common/Uniform.js index cff9e684eae977..3a6229c15a0259 100644 --- a/src/renderers/common/Uniform.js +++ b/src/renderers/common/Uniform.js @@ -5,26 +5,79 @@ import { Vector2 } from '../../math/Vector2.js'; import { Vector3 } from '../../math/Vector3.js'; import { Vector4 } from '../../math/Vector4.js'; +/** + * Abstract base class for uniforms. + * + * @abstract + * @private + */ class Uniform { + /** + * Constructs a new uniform. + * + * @param {String} name - The uniform's name. + * @param {Any} value - The uniform's value. + */ constructor( name, value ) { + /** + * The uniform's name. + * + * @type {String} + */ this.name = name; + + /** + * The uniform's value. + * + * @type {Any} + */ this.value = value; - this.boundary = 0; // used to build the uniform buffer according to the STD140 layout + /** + * Used to build the uniform buffer according to the STD140 layout. + * Derived uniforms will set this property to a data type specific + * value. + * + * @type {Number} + */ + this.boundary = 0; + + /** + * The item size. Derived uniforms will set this property to a data + * type specific value. + * + * @type {Number} + */ this.itemSize = 0; - this.offset = 0; // this property is set by WebGPUUniformsGroup and marks the start position in the uniform buffer + /** + * This property is set by {@link UniformsGroup} and marks + * the start position in the uniform buffer. + * + * @type {Number} + */ + this.offset = 0; } + /** + * Sets the uniform's value. + * + * @param {Any} value - The value to set. + */ setValue( value ) { this.value = value; } + /** + * Returns the uniform's value. + * + * @return {Any} The value. + */ getValue() { return this.value; @@ -33,12 +86,31 @@ class Uniform { } +/** + * Represents a Number uniform. + * + * @private + * @augments Uniform + */ class NumberUniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Number} value - The uniform's value. + */ constructor( name, value = 0 ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isNumberUniform = true; this.boundary = 4; @@ -48,12 +120,31 @@ class NumberUniform extends Uniform { } +/** + * Represents a Vector2 uniform. + * + * @private + * @augments Uniform + */ class Vector2Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Vector2} value - The uniform's value. + */ constructor( name, value = new Vector2() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVector2Uniform = true; this.boundary = 8; @@ -63,12 +154,31 @@ class Vector2Uniform extends Uniform { } +/** + * Represents a Vector3 uniform. + * + * @private + * @augments Uniform + */ class Vector3Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Vector3} value - The uniform's value. + */ constructor( name, value = new Vector3() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVector3Uniform = true; this.boundary = 16; @@ -78,12 +188,31 @@ class Vector3Uniform extends Uniform { } +/** + * Represents a Vector4 uniform. + * + * @private + * @augments Uniform + */ class Vector4Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Vector4} value - The uniform's value. + */ constructor( name, value = new Vector4() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isVector4Uniform = true; this.boundary = 16; @@ -93,12 +222,31 @@ class Vector4Uniform extends Uniform { } +/** + * Represents a Color uniform. + * + * @private + * @augments Uniform + */ class ColorUniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Color} value - The uniform's value. + */ constructor( name, value = new Color() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isColorUniform = true; this.boundary = 16; @@ -108,12 +256,31 @@ class ColorUniform extends Uniform { } +/** + * Represents a Matrix3 uniform. + * + * @private + * @augments Uniform + */ class Matrix3Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Matrix3} value - The uniform's value. + */ constructor( name, value = new Matrix3() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMatrix3Uniform = true; this.boundary = 48; @@ -123,12 +290,31 @@ class Matrix3Uniform extends Uniform { } +/** + * Represents a Matrix4 uniform. + * + * @private + * @augments Uniform + */ class Matrix4Uniform extends Uniform { + /** + * Constructs a new Number uniform. + * + * @param {String} name - The uniform's name. + * @param {Matrix4} value - The uniform's value. + */ constructor( name, value = new Matrix4() ) { super( name, value ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isMatrix4Uniform = true; this.boundary = 64; diff --git a/src/renderers/common/UniformBuffer.js b/src/renderers/common/UniformBuffer.js index 4edd9f8f8e6be4..4262c774743823 100644 --- a/src/renderers/common/UniformBuffer.js +++ b/src/renderers/common/UniformBuffer.js @@ -1,11 +1,30 @@ import Buffer from './Buffer.js'; +/** + * Represents a uniform buffer binding type. + * + * @private + * @augments Buffer + */ class UniformBuffer extends Buffer { + /** + * Constructs a new uniform buffer. + * + * @param {String} name - The buffer's name. + * @param {TypedArray} [buffer=null] - The buffer. + */ constructor( name, buffer = null ) { super( name, buffer ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isUniformBuffer = true; } diff --git a/src/renderers/common/UniformsGroup.js b/src/renderers/common/UniformsGroup.js index 10d7466da375d8..70a973d9d0316a 100644 --- a/src/renderers/common/UniformsGroup.js +++ b/src/renderers/common/UniformsGroup.js @@ -1,22 +1,59 @@ import UniformBuffer from './UniformBuffer.js'; import { GPU_CHUNK_BYTES } from './Constants.js'; +/** + * This class represents a uniform buffer binding but with + * an API that allows to maintain individual uniform objects. + * + * @private + * @augments UniformBuffer + */ class UniformsGroup extends UniformBuffer { + /** + * Constructs a new uniforms group. + * + * @param {String} name - The group's name. + */ constructor( name ) { super( name ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isUniformsGroup = true; + /** + * An array with the raw uniform values. + * + * @private + * @type {Array?} + * @default null + */ this._values = null; - // the order of uniforms in this array must match the order of uniforms in the shader - + /** + * An array of uniform objects. + * + * The order of uniforms in this array must match the order of uniforms in the shader. + * + * @type {Array} + */ this.uniforms = []; } + /** + * Adds a uniform to this group. + * + * @param {Uniform} uniform - The uniform to add. + * @return {UniformsGroup} A reference to this group. + */ addUniform( uniform ) { this.uniforms.push( uniform ); @@ -25,6 +62,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Removes a uniform from this group. + * + * @param {Uniform} uniform - The uniform to remove. + * @return {UniformsGroup} A reference to this group. + */ removeUniform( uniform ) { const index = this.uniforms.indexOf( uniform ); @@ -39,6 +82,11 @@ class UniformsGroup extends UniformBuffer { } + /** + * An array with the raw uniform values. + * + * @type {Array} + */ get values() { if ( this._values === null ) { @@ -51,6 +99,11 @@ class UniformsGroup extends UniformBuffer { } + /** + * A Float32 array buffer with the uniform values. + * + * @type {Float32Array} + */ get buffer() { let buffer = this._buffer; @@ -69,6 +122,11 @@ class UniformsGroup extends UniformBuffer { } + /** + * The byte length of the buffer with correct buffer alignment. + * + * @type {Number} + */ get byteLength() { let offset = 0; // global buffer offset in bytes @@ -110,6 +168,15 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates this group by updating each uniform object of + * the internal uniform list. The uniform objects check if their + * values has actually changed so this method only returns + * `true` if there is a real value change. + * + * @return {Boolean} Whether the uniforms have been updated and + * must be uploaded to the GPU. + */ update() { let updated = false; @@ -128,6 +195,13 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given uniform by calling an update method matching + * the uniforms type. + * + * @param {Uniform} uniform - The uniform to update. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateByType( uniform ) { if ( uniform.isNumberUniform ) return this.updateNumber( uniform ); @@ -142,6 +216,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Number uniform. + * + * @param {NumberUniform} uniform - The Number uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateNumber( uniform ) { let updated = false; @@ -164,6 +244,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Vector2 uniform. + * + * @param {Vector2Uniform} uniform - The Vector2 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateVector2( uniform ) { let updated = false; @@ -188,6 +274,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Vector3 uniform. + * + * @param {Vector3Uniform} uniform - The Vector3 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateVector3( uniform ) { let updated = false; @@ -213,6 +305,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Vector4 uniform. + * + * @param {Vector4Uniform} uniform - The Vector4 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateVector4( uniform ) { let updated = false; @@ -239,6 +337,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Color uniform. + * + * @param {ColorUniform} uniform - The Color uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateColor( uniform ) { let updated = false; @@ -263,6 +367,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Matrix3 uniform. + * + * @param {Matrix3Uniform} uniform - The Matrix3 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateMatrix3( uniform ) { let updated = false; @@ -295,6 +405,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Updates a given Matrix4 uniform. + * + * @param {Matrix4Uniform} uniform - The Matrix4 uniform. + * @return {Boolean} Whether the uniform has been updated or not. + */ updateMatrix4( uniform ) { let updated = false; @@ -316,6 +432,12 @@ class UniformsGroup extends UniformBuffer { } + /** + * Returns a typed array that matches the given data type. + * + * @param {String} type - The data type. + * @return {TypedArray} The typed array. + */ _getBufferForType( type ) { if ( type === 'int' || type === 'ivec2' || type === 'ivec3' || type === 'ivec4' ) return new Int32Array( this.buffer.buffer ); @@ -326,6 +448,14 @@ class UniformsGroup extends UniformBuffer { } +/** + * Sets the values of the second array to the first array. + * + * @private + * @param {TypedArray} a - The first array. + * @param {TypedArray} b - The second array. + * @param {Number} offset - An index offset for the first array. + */ function setArray( a, b, offset ) { for ( let i = 0, l = b.length; i < l; i ++ ) { @@ -336,6 +466,15 @@ function setArray( a, b, offset ) { } +/** + * Returns `true` if the given arrays are equal. + * + * @private + * @param {TypedArray} a - The first array. + * @param {TypedArray} b - The second array. + * @param {Number} offset - An index offset for the first array. + * @return {Boolean} Whether the given arrays are equal or not. + */ function arraysEqual( a, b, offset ) { for ( let i = 0, l = b.length; i < l; i ++ ) { diff --git a/src/renderers/common/extras/PMREMGenerator.js b/src/renderers/common/extras/PMREMGenerator.js index 1f9d70a5b4e303..2a164bdbd40608 100644 --- a/src/renderers/common/extras/PMREMGenerator.js +++ b/src/renderers/common/extras/PMREMGenerator.js @@ -69,7 +69,9 @@ const _axisDirections = [ /*@__PURE__*/ new Vector3( 1, 1, 1 ) ]; -// +// maps blur materials to their uniforms dictionary + +const _uniformsMap = new WeakMap(); // WebGPU Face indices const _faceLib = [ @@ -77,8 +79,8 @@ const _faceLib = [ 0, 4, 2 ]; -const direction = getDirection( uv(), attribute( 'faceIndex' ) ).normalize(); -const outputDirection = vec3( direction.x, direction.y, direction.z ); +const _direction = /*@__PURE__*/ getDirection( uv(), attribute( 'faceIndex' ) ).normalize(); +const _outputDirection = /*@__PURE__*/ vec3( _direction.x, _direction.y, _direction.z ); /** * This class generates a Prefiltered, Mipmapped Radiance Environment Map @@ -135,6 +137,7 @@ class PMREMGenerator { * @param {Number} [far=100] - The far plane distance. * @param {RenderTarget?} [renderTarget=null] - The render target to use. * @return {RenderTarget} The resulting PMREM. + * @see fromSceneAsync */ fromScene( scene, sigma = 0, near = 0.1, far = 100, renderTarget = null ) { @@ -175,6 +178,21 @@ class PMREMGenerator { } + /** + * 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). + * + * @param {Scene} scene - The scene to be captured. + * @param {Number} [sigma=0] - The blur radius in radians. + * @param {Number} [near=0.1] - The near plane distance. + * @param {Number} [far=100] - The far plane distance. + * @param {RenderTarget?} [renderTarget=null] - The render target to use. + * @return {Promise} The resulting PMREM. + * @see fromScene + */ async fromSceneAsync( scene, sigma = 0, near = 0.1, far = 100, renderTarget = null ) { if ( this._hasInitialized === false ) await this._renderer.init(); @@ -191,6 +209,7 @@ class PMREMGenerator { * @param {Texture} equirectangular - The equirectangular texture to be converted. * @param {RenderTarget?} [renderTarget=null] - The render target to use. * @return {RenderTarget} The resulting PMREM. + * @see fromEquirectangularAsync */ fromEquirectangular( equirectangular, renderTarget = null ) { @@ -212,6 +231,16 @@ class PMREMGenerator { } + /** + * 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. + * + * @param {Texture} equirectangular - The equirectangular texture to be converted. + * @param {RenderTarget?} [renderTarget=null] - The render target to use. + * @return {Promise} The resulting PMREM. + * @see fromEquirectangular + */ async fromEquirectangularAsync( equirectangular, renderTarget = null ) { if ( this._hasInitialized === false ) await this._renderer.init(); @@ -228,6 +257,7 @@ class PMREMGenerator { * @param {Texture} cubemap - The cubemap texture to be converted. * @param {RenderTarget?} [renderTarget=null] - The render target to use. * @return {RenderTarget} The resulting PMREM. + * @see fromCubemapAsync */ fromCubemap( cubemap, renderTarget = null ) { @@ -249,6 +279,16 @@ class PMREMGenerator { } + /** + * Generates a PMREM from an cubemap texture, which can be either LDR + * or HDR. The ideal input cube size is 256 x 256, + * with the 256 x 256 cubemap output. + * + * @param {Texture} cubemap - The cubemap texture to be converted. + * @param {RenderTarget?} [renderTarget=null] - The render target to use. + * @return {Promise} The resulting PMREM. + * @see fromCubemap + */ async fromCubemapAsync( cubemap, renderTarget = null ) { if ( this._hasInitialized === false ) await this._renderer.init(); @@ -260,6 +300,8 @@ class PMREMGenerator { /** * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during * your texture's network fetch for increased concurrency. + * + * @returns {Promise} */ async compileCubemapShader() { @@ -275,6 +317,8 @@ class PMREMGenerator { /** * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during * your texture's network fetch for increased concurrency. + * + * @returns {Promise} */ async compileEquirectangularShader() { @@ -625,7 +669,7 @@ class PMREMGenerator { const blurMesh = this._lodMeshes[ lodOut ]; blurMesh.material = blurMaterial; - const blurUniforms = blurMaterial.uniforms; + const blurUniforms = _uniformsMap.get( blurMaterial ); const pixels = this._sizeLods[ lodIn ] - 1; const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); @@ -829,7 +873,7 @@ function _getBlurShader( lodMax, width, height ) { latitudinal, weights, poleAxis, - outputDirection, + outputDirection: _outputDirection, dTheta, samples, envMap, @@ -840,9 +884,10 @@ function _getBlurShader( lodMax, width, height ) { }; const material = _getMaterial( 'blur' ); - material.uniforms = materialUniforms; // TODO: Move to outside of the material material.fragmentNode = blur( { ...materialUniforms, latitudinal: latitudinal.equal( 1 ) } ); + _uniformsMap.set( material, materialUniforms ); + return material; } @@ -850,7 +895,7 @@ function _getBlurShader( lodMax, width, height ) { function _getCubemapMaterial( envTexture ) { const material = _getMaterial( 'cubemap' ); - material.fragmentNode = cubeTexture( envTexture, outputDirection ); + material.fragmentNode = cubeTexture( envTexture, _outputDirection ); return material; @@ -859,7 +904,7 @@ function _getCubemapMaterial( envTexture ) { function _getEquirectMaterial( envTexture ) { const material = _getMaterial( 'equirect' ); - material.fragmentNode = texture( envTexture, equirectUV( outputDirection ), 0 ); + material.fragmentNode = texture( envTexture, equirectUV( _outputDirection ), 0 ); return material; diff --git a/src/renderers/common/nodes/NodeBuilderState.js b/src/renderers/common/nodes/NodeBuilderState.js index dcdc2aaffda631..e6c1ef8441999e 100644 --- a/src/renderers/common/nodes/NodeBuilderState.js +++ b/src/renderers/common/nodes/NodeBuilderState.js @@ -1,34 +1,128 @@ import BindGroup from '../BindGroup.js'; +/** + * This module represents the state of a node builder after it was + * used to build the nodes for a render object. The state holds the + * results of the build for further processing in the renderer. + * + * Render objects with identical cache keys share the same node builder state. + * + * @private + */ class NodeBuilderState { + /** + * Constructs a new node builder state. + * + * @param {String?} vertexShader - The native vertex shader code. + * @param {String?} fragmentShader - The native fragment shader code. + * @param {String?} computeShader - The native compute shader code. + * @param {Array} nodeAttributes - An array of node attributes. + * @param {Array} bindings - An array of bind groups. + * @param {Array} updateNodes - An array of nodes that implement their `update()` method. + * @param {Array} updateBeforeNodes - An array of nodes that implement their `updateBefore()` method. + * @param {Array} updateAfterNodes - An array of nodes that implement their `updateAfter()` method. + * @param {NodeMaterialObserver} monitor - A node material observer. + * @param {Array} transforms - An array with transform attribute objects. Only relevant when using compute shaders with WebGL 2. + */ constructor( vertexShader, fragmentShader, computeShader, nodeAttributes, bindings, updateNodes, updateBeforeNodes, updateAfterNodes, monitor, transforms = [] ) { + /** + * The native vertex shader code. + * + * @type {String} + */ this.vertexShader = vertexShader; + + /** + * The native fragment shader code. + * + * @type {String} + */ this.fragmentShader = fragmentShader; + + /** + * The native compute shader code. + * + * @type {String} + */ this.computeShader = computeShader; + + /** + * An array with transform attribute objects. + * Only relevant when using compute shaders with WebGL 2. + * + * @type {Array} + */ this.transforms = transforms; + /** + * An array of node attributes representing + * the attributes of the shaders. + * + * @type {Array} + */ this.nodeAttributes = nodeAttributes; + + /** + * An array of bind groups representing the uniform or storage + * buffers, texture or samplers of the shader. + * + * @type {Array} + */ this.bindings = bindings; + /** + * An array of nodes that implement their `update()` method. + * + * @type {Array} + */ this.updateNodes = updateNodes; + + /** + * An array of nodes that implement their `updateBefore()` method. + * + * @type {Array} + */ this.updateBeforeNodes = updateBeforeNodes; + + /** + * An array of nodes that implement their `updateAfter()` method. + * + * @type {Array} + */ this.updateAfterNodes = updateAfterNodes; + /** + * A node material observer. + * + * @type {NodeMaterialObserver} + */ this.monitor = monitor; + /** + * How often this state is used by render objects. + * + * @type {Number} + */ this.usedTimes = 0; } + /** + * This method is used to create a array of bind groups based + * on the existing bind groups of this state. Shared groups are + * not cloned. + * + * @return {Array} A array of bind groups. + */ createBindings() { const bindings = []; for ( const instanceGroup of this.bindings ) { - const shared = instanceGroup.bindings[ 0 ].groupNode.shared; + const shared = instanceGroup.bindings[ 0 ].groupNode.shared; // TODO: Is it safe to always check the first binding in the group? if ( shared !== true ) { diff --git a/src/renderers/common/nodes/NodeLibrary.js b/src/renderers/common/nodes/NodeLibrary.js index eb1e7281b1fc7f..24db01bb85dd36 100644 --- a/src/renderers/common/nodes/NodeLibrary.js +++ b/src/renderers/common/nodes/NodeLibrary.js @@ -1,13 +1,52 @@ +/** + * The purpose of a node library is to assign node implementations + * to existing library features. In `WebGPURenderer` lights, materials + * which are not based on `NodeMaterial` as well as tone mapping techniques + * are implemented with node-based modules. + * + * @private + */ class NodeLibrary { + /** + * Constructs a new node library. + */ constructor() { + /** + * A weak map that maps lights to light nodes. + * + * @type {WeakMap} + */ this.lightNodes = new WeakMap(); + + /** + * A map that maps materials to node materials. + * + * @type {Map} + */ this.materialNodes = new Map(); + + /** + * A map that maps tone mapping techniques (constants) + * to tone mapping node functions. + * + * @type {Map} + */ this.toneMappingNodes = new Map(); } + /** + * Returns a matching node material instance for the given material object. + * + * This method also assigns/copies the properties of the given material object + * to the node material. This is done to make sure the current material + * configuration carries over to the node version. + * + * @param {Material} material - A material. + * @return {NodeMaterial} The corresponding node material. + */ fromMaterial( material ) { if ( material.isNodeMaterial ) return material; @@ -32,42 +71,85 @@ class NodeLibrary { } + /** + * Adds a tone mapping node function for a tone mapping technique (constant). + * + * @param {Function} toneMappingNode - The tone mapping node function. + * @param {Number} toneMapping - The tone mapping. + */ addToneMapping( toneMappingNode, toneMapping ) { this.addType( toneMappingNode, toneMapping, this.toneMappingNodes ); } + /** + * Returns a tone mapping node function for a tone mapping technique (constant). + * + * @param {Number} toneMapping - The tone mapping. + * @return {Function?} The tone mapping node function. Returns `null` if no node function is found. + */ getToneMappingFunction( toneMapping ) { return this.toneMappingNodes.get( toneMapping ) || null; } + /** + * Returns a node material class definition for a material type. + * + * @param {String} materialType - The material type. + * @return {NodeMaterial.constructor?} The node material class definition. Returns `null` if no node material is found. + */ getMaterialNodeClass( materialType ) { return this.materialNodes.get( materialType ) || null; } + /** + * Adds a node material class definition for a given material type. + * + * @param {NodeMaterial.constructor} materialNodeClass - The node material class definition. + * @param {String} materialClassType - The material type. + */ addMaterial( materialNodeClass, materialClassType ) { this.addType( materialNodeClass, materialClassType, this.materialNodes ); } + /** + * Returns a light node class definition for a light class definition. + * + * @param {Light.constructor} light - The light class definition. + * @return {AnalyticLightNode.constructor?} The light node class definition. Returns `null` if no light node is found. + */ getLightNodeClass( light ) { return this.lightNodes.get( light ) || null; } + /** + * Adds a light node class definition for a given light class definition. + * + * @param {AnalyticLightNode.constructor} lightNodeClass - The light node class definition. + * @param {Light.constructor} lightClass - The light class definition. + */ addLight( lightNodeClass, lightClass ) { this.addClass( lightNodeClass, lightClass, this.lightNodes ); } + /** + * Adds a node class definition for the given type to the provided type library. + * + * @param {Any} nodeClass - The node class definition. + * @param {Number|String} type - The object type. + * @param {Map} library - The type library. + */ addType( nodeClass, type, library ) { if ( library.has( type ) ) { @@ -84,6 +166,13 @@ class NodeLibrary { } + /** + * Adds a node class definition for the given class definition to the provided type library. + * + * @param {Any} nodeClass - The node class definition. + * @param {Any} baseClass - The class definition. + * @param {WeakMap} library - The type library. + */ addClass( nodeClass, baseClass, library ) { if ( library.has( baseClass ) ) { diff --git a/src/renderers/common/nodes/NodeSampledTexture.js b/src/renderers/common/nodes/NodeSampledTexture.js index b23b165d00b928..2776ce585dc5a7 100644 --- a/src/renderers/common/nodes/NodeSampledTexture.js +++ b/src/renderers/common/nodes/NodeSampledTexture.js @@ -1,24 +1,68 @@ import { SampledTexture } from '../SampledTexture.js'; +/** + * A special form of sampled texture binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments SampledTexture + */ class NodeSampledTexture extends SampledTexture { + /** + * Constructs a new node-based sampled texture. + * + * @param {String} name - The textures's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + * @param {String?} [access=null] - The access type. + */ constructor( name, textureNode, groupNode, access = null ) { super( name, textureNode ? textureNode.value : null ); + /** + * The texture node. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; + /** + * The access type. + * + * @type {String?} + * @default null + */ this.access = access; } + /** + * Overwrites the default to additionally check if the node value has changed. + * + * @param {Number} generation - The generation. + * @return {Boolean} Whether an update is required or not. + */ needsBindingsUpdate( generation ) { return this.textureNode.value !== this.texture || super.needsBindingsUpdate( generation ); } + /** + * Updates the binding. + * + * @return {Boolean} Whether the texture has been updated and must be + * uploaded to the GPU. + */ update() { const { textureNode } = this; @@ -37,24 +81,68 @@ class NodeSampledTexture extends SampledTexture { } +/** + * A special form of sampled cube texture binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments NodeSampledTexture + */ class NodeSampledCubeTexture extends NodeSampledTexture { - constructor( name, textureNode, groupNode, access ) { + /** + * Constructs a new node-based sampled cube texture. + * + * @param {String} name - The textures's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + * @param {String?} [access=null] - The access type. + */ + constructor( name, textureNode, groupNode, access = null ) { super( name, textureNode, groupNode, access ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledCubeTexture = true; } } +/** + * A special form of sampled 3D texture binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments NodeSampledTexture + */ class NodeSampledTexture3D extends NodeSampledTexture { - constructor( name, textureNode, groupNode, access ) { + /** + * Constructs a new node-based sampled 3D texture. + * + * @param {String} name - The textures's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + * @param {String?} [access=null] - The access type. + */ + constructor( name, textureNode, groupNode, access = null ) { super( name, textureNode, groupNode, access ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isSampledTexture3D = true; } diff --git a/src/renderers/common/nodes/NodeSampler.js b/src/renderers/common/nodes/NodeSampler.js index 7c4dbf3202388f..2a2f11ee38ce5f 100644 --- a/src/renderers/common/nodes/NodeSampler.js +++ b/src/renderers/common/nodes/NodeSampler.js @@ -1,16 +1,44 @@ import Sampler from '../Sampler.js'; +/** + * A special form of sampler binding type. + * It's texture value is managed by a node object. + * + * @private + * @augments Sampler + */ class NodeSampler extends Sampler { + /** + * Constructs a new node-based sampler. + * + * @param {String} name - The samplers's name. + * @param {TextureNode} textureNode - The texture node. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( name, textureNode, groupNode ) { super( name, textureNode ? textureNode.value : null ); + /** + * The texture node. + * + * @type {TextureNode} + */ this.textureNode = textureNode; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; } + /** + * Updates the texture value of this sampler. + */ update() { this.texture = this.textureNode.value; diff --git a/src/renderers/common/nodes/NodeStorageBuffer.js b/src/renderers/common/nodes/NodeStorageBuffer.js index 0a5da2607d8f1d..daf82a1ed0123c 100644 --- a/src/renderers/common/nodes/NodeStorageBuffer.js +++ b/src/renderers/common/nodes/NodeStorageBuffer.js @@ -3,18 +3,53 @@ import { NodeAccess } from '../../../nodes/core/constants.js'; let _id = 0; +/** + * A special form of storage buffer binding type. + * It's buffer value is managed by a node object. + * + * @private + * @augments StorageBuffer + */ class NodeStorageBuffer extends StorageBuffer { + /** + * Constructs a new node-based storage buffer. + * + * @param {StorageBufferNode} nodeUniform - The storage buffer node. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( nodeUniform, groupNode ) { super( 'StorageBuffer_' + _id ++, nodeUniform ? nodeUniform.value : null ); + /** + * The node uniform. + * + * @type {StorageBufferNode} + */ this.nodeUniform = nodeUniform; + + /** + * The access type. + * + * @type {String} + */ this.access = nodeUniform ? nodeUniform.access : NodeAccess.READ_WRITE; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; } + /** + * The storage buffer. + * + * @type {BufferAttribute} + */ get buffer() { return this.nodeUniform.value; diff --git a/src/renderers/common/nodes/NodeUniform.js b/src/renderers/common/nodes/NodeUniform.js index 384d4335f50437..9043e539f309a1 100644 --- a/src/renderers/common/nodes/NodeUniform.js +++ b/src/renderers/common/nodes/NodeUniform.js @@ -3,22 +3,49 @@ import { ColorUniform, Matrix3Uniform, Matrix4Uniform } from '../Uniform.js'; +/** + * A special form of Number uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments NumberUniform + */ class NumberNodeUniform extends NumberUniform { + /** + * Constructs a new node-based Number uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Number} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -27,22 +54,49 @@ class NumberNodeUniform extends NumberUniform { } +/** + * A special form of Vector2 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Vector2Uniform + */ class Vector2NodeUniform extends Vector2Uniform { + /** + * Constructs a new node-based Vector2 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Vector2} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -51,22 +105,49 @@ class Vector2NodeUniform extends Vector2Uniform { } +/** + * A special form of Vector3 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Vector3Uniform + */ class Vector3NodeUniform extends Vector3Uniform { + /** + * Constructs a new node-based Vector3 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Vector3} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -75,22 +156,49 @@ class Vector3NodeUniform extends Vector3Uniform { } +/** + * A special form of Vector4 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Vector4Uniform + */ class Vector4NodeUniform extends Vector4Uniform { + /** + * Constructs a new node-based Vector4 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Vector4} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -99,22 +207,49 @@ class Vector4NodeUniform extends Vector4Uniform { } +/** + * A special form of Color uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments ColorUniform + */ class ColorNodeUniform extends ColorUniform { + /** + * Constructs a new node-based Color uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Color} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -123,22 +258,49 @@ class ColorNodeUniform extends ColorUniform { } +/** + * A special form of Matrix3 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Matrix3Uniform + */ class Matrix3NodeUniform extends Matrix3Uniform { + /** + * Constructs a new node-based Matrix3 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Matrix3} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; @@ -147,22 +309,49 @@ class Matrix3NodeUniform extends Matrix3Uniform { } +/** + * A special form of Matrix4 uniform binding type. + * It's value is managed by a node object. + * + * @private + * @augments Matrix4Uniform + */ class Matrix4NodeUniform extends Matrix4Uniform { + /** + * Constructs a new node-based Matrix4 uniform. + * + * @param {NodeUniform} nodeUniform - The node uniform. + */ constructor( nodeUniform ) { super( nodeUniform.name, nodeUniform.value ); + /** + * The node uniform. + * + * @type {NodeUniform} + */ this.nodeUniform = nodeUniform; } + /** + * Overwritten to return the value of the node uniform. + * + * @return {Matrix4} The value. + */ getValue() { return this.nodeUniform.value; } + /** + * Returns the node uniform data type. + * + * @return {String} The data type. + */ getType() { return this.nodeUniform.type; diff --git a/src/renderers/common/nodes/NodeUniformBuffer.js b/src/renderers/common/nodes/NodeUniformBuffer.js index a323bb1c71fb90..d33c6f885c276e 100644 --- a/src/renderers/common/nodes/NodeUniformBuffer.js +++ b/src/renderers/common/nodes/NodeUniformBuffer.js @@ -2,17 +2,46 @@ import UniformBuffer from '../UniformBuffer.js'; let _id = 0; +/** + * A special form of uniform buffer binding type. + * It's buffer value is managed by a node object. + * + * @private + * @augments UniformBuffer + */ class NodeUniformBuffer extends UniformBuffer { + /** + * Constructs a new node-based uniform buffer. + * + * @param {BufferNode} nodeUniform - The uniform buffer node. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( nodeUniform, groupNode ) { super( 'UniformBuffer_' + _id ++, nodeUniform ? nodeUniform.value : null ); + /** + * The uniform buffer node. + * + * @type {BufferNode} + */ this.nodeUniform = nodeUniform; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; } + /** + * The uniform buffer. + * + * @type {Float32Array} + */ get buffer() { return this.nodeUniform.value; diff --git a/src/renderers/common/nodes/NodeUniformsGroup.js b/src/renderers/common/nodes/NodeUniformsGroup.js index be2b7839f95ed0..cbdea97b97b636 100644 --- a/src/renderers/common/nodes/NodeUniformsGroup.js +++ b/src/renderers/common/nodes/NodeUniformsGroup.js @@ -2,37 +2,50 @@ import UniformsGroup from '../UniformsGroup.js'; let _id = 0; +/** + * A special form of uniforms group that represents + * the individual uniforms as node-based uniforms. + * + * @private + * @augments UniformsGroup + */ class NodeUniformsGroup extends UniformsGroup { + /** + * Constructs a new node-based uniforms group. + * + * @param {String} name - The group's name. + * @param {UniformGroupNode} groupNode - The uniform group node. + */ constructor( name, groupNode ) { super( name ); + /** + * The group's ID. + * + * @type {Number} + */ this.id = _id ++; + + /** + * The uniform group node. + * + * @type {UniformGroupNode} + */ this.groupNode = groupNode; + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ 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; - - } - } export default NodeUniformsGroup; diff --git a/src/renderers/common/nodes/Nodes.js b/src/renderers/common/nodes/Nodes.js index a061ad9d700584..acdcc0d23304da 100644 --- a/src/renderers/common/nodes/Nodes.js +++ b/src/renderers/common/nodes/Nodes.js @@ -8,29 +8,93 @@ import { objectGroup, renderGroup, frameGroup, cubeTexture, texture, fog, rangeF import { CubeUVReflectionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping } from '../../../constants.js'; import { hashArray } from '../../../nodes/core/NodeUtils.js'; -const outputNodeMap = new WeakMap(); - +const _outputNodeMap = new WeakMap(); +const _chainKeys = []; +const _cacheKeyValues = []; + +/** + * This renderer module manages node-related objects and is the + * primary interface between the renderer and the node system. + * + * @private + * @augments DataMap + */ class Nodes extends DataMap { + /** + * Constructs a new nodes management component. + * + * @param {Renderer} renderer - The renderer. + * @param {Backend} backend - The renderer's backend. + */ constructor( renderer, backend ) { super(); + /** + * The renderer. + * + * @type {Renderer} + */ this.renderer = renderer; + + /** + * The renderer's backend. + * + * @type {Backend} + */ this.backend = backend; + + /** + * The node frame. + * + * @type {Renderer} + */ this.nodeFrame = new NodeFrame(); + + /** + * A cache for managing node builder states. + * + * @type {Map} + */ this.nodeBuilderCache = new Map(); + + /** + * A cache for managing data cache key data. + * + * @type {ChainMap} + */ this.callHashCache = new ChainMap(); + + /** + * A cache for managing node uniforms group data. + * + * @type {ChainMap} + */ this.groupsData = new ChainMap(); + /** + * A cache for managing node objects of + * scene properties like fog or environments. + * + * @type {Object} + */ + this.cacheLib = {}; + } + /** + * Returns `true` if the given node uniforms group must be updated or not. + * + * @param {NodeUniformsGroup} nodeUniformsGroup - The node uniforms group. + * @return {Boolean} Whether the node uniforms group requires an update or not. + */ updateGroup( nodeUniformsGroup ) { const groupNode = nodeUniformsGroup.groupNode; const name = groupNode.name; - // objectGroup is every updated + // objectGroup is always updated if ( name === objectGroup.name ) return true; @@ -74,10 +138,13 @@ class Nodes extends DataMap { // other groups are updated just when groupNode.needsUpdate is true - const groupChain = [ groupNode, nodeUniformsGroup ]; + _chainKeys[ 0 ] = groupNode; + _chainKeys[ 1 ] = nodeUniformsGroup; - let groupData = this.groupsData.get( groupChain ); - if ( groupData === undefined ) this.groupsData.set( groupChain, groupData = {} ); + let groupData = this.groupsData.get( _chainKeys ); + if ( groupData === undefined ) this.groupsData.set( _chainKeys, groupData = {} ); + + _chainKeys.length = 0; if ( groupData.version !== groupNode.version ) { @@ -91,12 +158,24 @@ class Nodes extends DataMap { } + /** + * Returns the cache key for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Number} The cache key. + */ getForRenderCacheKey( renderObject ) { return renderObject.initialCacheKey; } + /** + * Returns a node builder state for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {NodeBuilderState} The node builder state. + */ getForRender( renderObject ) { const renderObjectData = this.get( renderObject ); @@ -140,6 +219,12 @@ class Nodes extends DataMap { } + /** + * Deletes the given object from the internal data map + * + * @param {Any} object - The object to delete. + * @return {Object?} The deleted dictionary. + */ delete( object ) { if ( object.isRenderObject ) { @@ -159,6 +244,12 @@ class Nodes extends DataMap { } + /** + * Returns a node builder state for the given compute node. + * + * @param {Node} computeNode - The compute node. + * @return {NodeBuilderState} The node builder state. + */ getForCompute( computeNode ) { const computeData = this.get( computeNode ); @@ -180,6 +271,13 @@ class Nodes extends DataMap { } + /** + * Creates a node builder state for the given node builder. + * + * @private + * @param {NodeBuilder} nodeBuilder - The node builder. + * @return {NodeBuilderState} The node builder state. + */ _createNodeBuilderState( nodeBuilder ) { return new NodeBuilderState( @@ -197,71 +295,149 @@ class Nodes extends DataMap { } + /** + * Returns an environment node for the current configured + * scene environment. + * + * @param {Scene} scene - The scene. + * @return {Node} A node representing the current scene environment. + */ getEnvironmentNode( scene ) { - return scene.environmentNode || this.get( scene ).environmentNode || null; + this.updateEnvironment( scene ); + + let environmentNode = null; + + if ( scene.environmentNode && scene.environmentNode.isNode ) { + + environmentNode = scene.environmentNode; + + } else { + + const sceneData = this.get( scene ); + + if ( sceneData.environmentNode ) { + + environmentNode = sceneData.environmentNode; + + } + + } + + return environmentNode; } + /** + * Returns a background node for the current configured + * scene background. + * + * @param {Scene} scene - The scene. + * @return {Node} A node representing the current scene background. + */ getBackgroundNode( scene ) { - return scene.backgroundNode || this.get( scene ).backgroundNode || null; + this.updateBackground( scene ); + + let backgroundNode = null; + + if ( scene.backgroundNode && scene.backgroundNode.isNode ) { + + backgroundNode = scene.backgroundNode; + + } else { + + const sceneData = this.get( scene ); + + if ( sceneData.backgroundNode ) { + + backgroundNode = sceneData.backgroundNode; + + } + + } + + return backgroundNode; } + /** + * Returns a fog node for the current configured scene fog. + * + * @param {Scene} scene - The scene. + * @return {Node} A node representing the current scene fog. + */ getFogNode( scene ) { + this.updateFog( scene ); + return scene.fogNode || this.get( scene ).fogNode || null; } + /** + * Returns a cache key for the given scene and lights node. + * This key is used by `RenderObject` as a part of the dynamic + * cache key (a key that must be checked every time the render + * objects is drawn). + * + * @param {Scene} scene - The scene. + * @param {LightsNode} lightsNode - The lights node. + * @return {Number} The cache key. + */ getCacheKey( scene, lightsNode ) { - const chain = [ scene, lightsNode ]; + _chainKeys[ 0 ] = scene; + _chainKeys[ 1 ] = lightsNode; + const callId = this.renderer.info.calls; - let cacheKeyData = this.callHashCache.get( chain ); + const cacheKeyData = this.callHashCache.get( _chainKeys ) || {}; - if ( cacheKeyData === undefined || cacheKeyData.callId !== callId ) { + if ( cacheKeyData.callId !== callId ) { const environmentNode = this.getEnvironmentNode( scene ); const fogNode = this.getFogNode( scene ); - const values = []; + if ( lightsNode ) _cacheKeyValues.push( lightsNode.getCacheKey( true ) ); + if ( environmentNode ) _cacheKeyValues.push( environmentNode.getCacheKey() ); + if ( fogNode ) _cacheKeyValues.push( fogNode.getCacheKey() ); - if ( lightsNode ) values.push( lightsNode.getCacheKey( true ) ); - if ( environmentNode ) values.push( environmentNode.getCacheKey() ); - if ( fogNode ) values.push( fogNode.getCacheKey() ); + _cacheKeyValues.push( this.renderer.shadowMap.enabled ? 1 : 0 ); - values.push( this.renderer.shadowMap.enabled ? 1 : 0 ); + cacheKeyData.callId = callId; + cacheKeyData.cacheKey = hashArray( _cacheKeyValues ); - cacheKeyData = { - callId, - cacheKey: hashArray( values ) - }; + this.callHashCache.set( _chainKeys, cacheKeyData ); - this.callHashCache.set( chain, cacheKeyData ); + _cacheKeyValues.length = 0; } - return cacheKeyData.cacheKey; + _chainKeys.length = 0; - } - - updateScene( scene ) { - - this.updateEnvironment( scene ); - this.updateFog( scene ); - this.updateBackground( scene ); + return cacheKeyData.cacheKey; } + /** + * A boolean that indicates whether tone mapping should be enabled + * or not. + * + * @type {Boolean} + */ get isToneMappingState() { return this.renderer.getRenderTarget() ? false : true; } + /** + * If a scene background is configured, this method makes sure to + * represent the background with a corresponding node-based implementation. + * + * @param {Scene} scene - The scene. + */ updateBackground( scene ) { const sceneData = this.get( scene ); @@ -273,41 +449,43 @@ class Nodes extends DataMap { if ( sceneData.background !== background || forceUpdate ) { - let backgroundNode = null; + const backgroundNode = this.getCacheNode( 'background', background, () => { - if ( background.isCubeTexture === true || ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping || background.mapping === CubeUVReflectionMapping ) ) { + if ( background.isCubeTexture === true || ( background.mapping === EquirectangularReflectionMapping || background.mapping === EquirectangularRefractionMapping || background.mapping === CubeUVReflectionMapping ) ) { - if ( scene.backgroundBlurriness > 0 || background.mapping === CubeUVReflectionMapping ) { + if ( scene.backgroundBlurriness > 0 || background.mapping === CubeUVReflectionMapping ) { - backgroundNode = pmremTexture( background ); + return pmremTexture( background ); - } else { + } else { - let envMap; + let envMap; - if ( background.isCubeTexture === true ) { + if ( background.isCubeTexture === true ) { - envMap = cubeTexture( background ); + envMap = cubeTexture( background ); - } else { + } else { - envMap = texture( background ); + envMap = texture( background ); - } + } - backgroundNode = cubeMapNode( envMap ); + return cubeMapNode( envMap ); - } + } - } else if ( background.isTexture === true ) { + } else if ( background.isTexture === true ) { - backgroundNode = texture( background, screenUV.flipY() ).setUpdateMatrix( true ); + return texture( background, screenUV.flipY() ).setUpdateMatrix( true ); - } else if ( background.isColor !== true ) { + } else if ( background.isColor !== true ) { - console.error( 'WebGPUNodes: Unsupported background configuration.', background ); + console.error( 'WebGPUNodes: Unsupported background configuration.', background ); - } + } + + }, forceUpdate ); sceneData.backgroundNode = backgroundNode; sceneData.background = background; @@ -324,6 +502,39 @@ class Nodes extends DataMap { } + /** + * This method is part of the caching of nodes which are used to represents the + * scene's background, fog or environment. + * + * @param {String} type - The type of object to cache. + * @param {Object} object - The object. + * @param {Function} callback - A callback that produces a node representation for the given object. + * @param {Boolean} [forceUpdate=false] - Whether an update should be enforced or not. + * @return {Node} The node representation. + */ + getCacheNode( type, object, callback, forceUpdate = false ) { + + const nodeCache = this.cacheLib[ type ] || ( this.cacheLib[ type ] = new WeakMap() ); + + let node = nodeCache.get( object ); + + if ( node === undefined || forceUpdate ) { + + node = callback(); + nodeCache.set( object, node ); + + } + + return node; + + } + + /** + * If a scene fog is configured, this method makes sure to + * represent the fog with a corresponding node-based implementation. + * + * @param {Scene} scene - The scene. + */ updateFog( scene ) { const sceneData = this.get( scene ); @@ -333,28 +544,30 @@ class Nodes extends DataMap { if ( sceneData.fog !== sceneFog ) { - let fogNode = null; + const fogNode = this.getCacheNode( 'fog', sceneFog, () => { - if ( sceneFog.isFogExp2 ) { + if ( sceneFog.isFogExp2 ) { - const color = reference( 'color', 'color', sceneFog ).setGroup( renderGroup ); - const density = reference( 'density', 'float', sceneFog ).setGroup( renderGroup ); + const color = reference( 'color', 'color', sceneFog ).setGroup( renderGroup ); + const density = reference( 'density', 'float', sceneFog ).setGroup( renderGroup ); - fogNode = fog( color, densityFogFactor( density ) ); + return fog( color, densityFogFactor( density ) ); - } else if ( sceneFog.isFog ) { + } else if ( sceneFog.isFog ) { - const color = reference( 'color', 'color', sceneFog ).setGroup( renderGroup ); - const near = reference( 'near', 'float', sceneFog ).setGroup( renderGroup ); - const far = reference( 'far', 'float', sceneFog ).setGroup( renderGroup ); + const color = reference( 'color', 'color', sceneFog ).setGroup( renderGroup ); + const near = reference( 'near', 'float', sceneFog ).setGroup( renderGroup ); + const far = reference( 'far', 'float', sceneFog ).setGroup( renderGroup ); - fogNode = fog( color, rangeFogFactor( near, far ) ); + return fog( color, rangeFogFactor( near, far ) ); + + } else { - } else { + console.error( 'THREE.Renderer: Unsupported fog configuration.', sceneFog ); - console.error( 'WebGPUNodes: Unsupported fog configuration.', sceneFog ); + } - } + } ); sceneData.fogNode = fogNode; sceneData.fog = sceneFog; @@ -370,6 +583,12 @@ class Nodes extends DataMap { } + /** + * If a scene environment is configured, this method makes sure to + * represent the environment with a corresponding node-based implementation. + * + * @param {Scene} scene - The scene. + */ updateEnvironment( scene ) { const sceneData = this.get( scene ); @@ -379,21 +598,23 @@ class Nodes extends DataMap { if ( sceneData.environment !== environment ) { - let environmentNode = null; + const environmentNode = this.getCacheNode( 'environment', environment, () => { + + if ( environment.isCubeTexture === true ) { - if ( environment.isCubeTexture === true ) { + return cubeTexture( environment ); - environmentNode = cubeTexture( environment ); + } else if ( environment.isTexture === true ) { - } else if ( environment.isTexture === true ) { + return texture( environment ); - environmentNode = texture( environment ); + } else { - } else { + console.error( 'Nodes: Unsupported environment configuration.', environment ); - console.error( 'Nodes: Unsupported environment configuration.', environment ); + } - } + } ); sceneData.environmentNode = environmentNode; sceneData.environment = environment; @@ -428,6 +649,11 @@ class Nodes extends DataMap { } + /** + * Returns the current output cache key. + * + * @return {String} The output cache key. + */ getOutputCacheKey() { const renderer = this.renderer; @@ -436,27 +662,47 @@ class Nodes extends DataMap { } + /** + * Checks if the output configuration (tone mapping and color space) for + * the given target has changed. + * + * @param {Texture} outputTarget - The output target. + * @return {Boolean} Whether the output configuration has changed or not. + */ hasOutputChange( outputTarget ) { - const cacheKey = outputNodeMap.get( outputTarget ); + const cacheKey = _outputNodeMap.get( outputTarget ); return cacheKey !== this.getOutputCacheKey(); } - getOutputNode( outputTexture ) { + /** + * Returns a node that represents the output configuration (tone mapping and + * color space) for the current target. + * + * @param {Texture} outputTarget - The output target. + * @return {Node} The output node. + */ + getOutputNode( outputTarget ) { const renderer = this.renderer; const cacheKey = this.getOutputCacheKey(); - const output = texture( outputTexture, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); + const output = texture( outputTarget, screenUV ).renderOutput( renderer.toneMapping, renderer.currentColorSpace ); - outputNodeMap.set( outputTexture, cacheKey ); + _outputNodeMap.set( outputTarget, cacheKey ); return output; } + /** + * Triggers the call of `updateBefore()` methods + * for all nodes of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateBefore( renderObject ) { const nodeBuilder = renderObject.getNodeBuilderState(); @@ -471,6 +717,12 @@ class Nodes extends DataMap { } + /** + * Triggers the call of `updateAfter()` methods + * for all nodes of the given render object. + * + * @param {RenderObject} renderObject - The render object. + */ updateAfter( renderObject ) { const nodeBuilder = renderObject.getNodeBuilderState(); @@ -485,6 +737,12 @@ class Nodes extends DataMap { } + /** + * Triggers the call of `update()` methods + * for all nodes of the given compute node. + * + * @param {Node} computeNode - The compute node. + */ updateForCompute( computeNode ) { const nodeFrame = this.getNodeFrame(); @@ -498,6 +756,12 @@ class Nodes extends DataMap { } + /** + * Triggers the call of `update()` methods + * for all nodes of the given compute node. + * + * @param {RenderObject} renderObject - The render object. + */ updateForRender( renderObject ) { const nodeFrame = this.getNodeFrameForRender( renderObject ); @@ -511,6 +775,12 @@ class Nodes extends DataMap { } + /** + * Returns `true` if the given render object requires a refresh. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the given render object requires a refresh or not. + */ needsRefresh( renderObject ) { const nodeFrame = this.getNodeFrameForRender( renderObject ); @@ -520,12 +790,16 @@ class Nodes extends DataMap { } + /** + * Frees the internal resources. + */ dispose() { super.dispose(); this.nodeFrame = new NodeFrame(); this.nodeBuilderCache = new Map(); + this.cacheLib = {}; } diff --git a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js index f591dd0e178c5b..e07e890e5775d2 100644 --- a/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js @@ -286,7 +286,7 @@ vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in m float result = LTC_ClippedSphereFormFactor( vectorFormFactor ); /* - // alternate method of adjusting for horizon clipping (see referece) + // alternate method of adjusting for horizon clipping (see reference) // refactoring required float len = length( vectorFormFactor ); float z = vectorFormFactor.z / len; @@ -351,7 +351,7 @@ vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 no #endif -// This is a curve-fit approxmation to the "Charlie sheen" BRDF integrated over the hemisphere from +// This is a curve-fit approximation 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 float IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { diff --git a/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js b/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js index 53e4c21f29a301..15e48682ea408f 100644 --- a/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js +++ b/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js @@ -123,7 +123,7 @@ export default /* glsl */` // Direction of refracted light. vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior ); - // Compute rotation-independant scaling of the model matrix. + // Compute rotation-independent scaling of the model matrix. vec3 modelScale; modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) ); modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) ); @@ -184,13 +184,13 @@ export default /* glsl */` vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix ); vec3 refractedRayExit = position + transmissionRay; - + // Project refracted vector on the framebuffer, while mapping to normalized device coordinates. vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); vec2 refractionCoords = ndcPos.xy / ndcPos.w; refractionCoords += 1.0; refractionCoords /= 2.0; - + // Sample framebuffer to get pixel the refracted ray hits. vec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] ); transmittedLight[ i ] = transmissionSample[ i ]; @@ -201,9 +201,9 @@ export default /* glsl */` } transmittedLight.a /= 3.0; - + #else - + vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); vec3 refractedRayExit = position + transmissionRay; @@ -216,7 +216,7 @@ export default /* glsl */` // Sample framebuffer to get pixel the refracted ray hits. transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ); - + #endif vec3 attenuatedColor = transmittance * transmittedLight.rgb; @@ -224,7 +224,7 @@ export default /* glsl */` // Get the specular component. vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness ); - // As less light is transmitted, the opacity should be increased. This simple approximation does a decent job + // 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. float transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0; diff --git a/src/renderers/webgl-fallback/WebGLBackend.js b/src/renderers/webgl-fallback/WebGLBackend.js index a7e775991f1ca2..53924bc581f7e2 100644 --- a/src/renderers/webgl-fallback/WebGLBackend.js +++ b/src/renderers/webgl-fallback/WebGLBackend.js @@ -14,18 +14,184 @@ import { WebGLBufferRenderer } from './WebGLBufferRenderer.js'; import { warnOnce } from '../../utils.js'; import { WebGLCoordinateSystem } from '../../constants.js'; -// - +/** + * A backend implementation targeting WebGL 2. + * + * @private + * @augments Backend + */ class WebGLBackend extends Backend { + /** + * Constructs a new WebGPU backend. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. + * @param {WebGL2RenderingContext} [parameters.context=undefined] - A WebGL 2 rendering context. + */ constructor( parameters = {} ) { super( parameters ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGLBackend = true; + /** + * A reference to a backend module holding shader attribute-related + * utility functions. + * + * @type {WebGLAttributeUtils?} + * @default null + */ + this.attributeUtils = null; + + /** + * A reference to a backend module holding extension-related + * utility functions. + * + * @type {WebGLExtensions?} + * @default null + */ + this.extensions = null; + + /** + * A reference to a backend module holding capability-related + * utility functions. + * + * @type {WebGLCapabilities?} + * @default null + */ + this.capabilities = null; + + /** + * A reference to a backend module holding texture-related + * utility functions. + * + * @type {WebGLTextureUtils?} + * @default null + */ + this.textureUtils = null; + + /** + * A reference to a backend module holding renderer-related + * utility functions. + * + * @type {WebGLBufferRenderer?} + * @default null + */ + this.bufferRenderer = null; + + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext?} + * @default null + */ + this.gl = null; + + /** + * A reference to a backend module holding state-related + * utility functions. + * + * @type {WebGLState?} + * @default null + */ + this.state = null; + + /** + * A reference to a backend module holding common + * utility functions. + * + * @type {WebGLUtils?} + * @default null + */ + this.utils = null; + + /** + * Dictionary for caching VAOs. + * + * @type {Object} + */ + this.vaoCache = {}; + + /** + * Dictionary for caching transform feedback objects. + * + * @type {Object} + */ + this.transformFeedbackCache = {}; + + /** + * Controls if `gl.RASTERIZER_DISCARD` should be enabled or not. + * Only relevant when using compute shaders. + * + * @type {Boolean} + * @default false + */ + this.discard = false; + + /** + * A reference to the `EXT_disjoint_timer_query_webgl2` extension. `null` if the + * device does not support the extension. + * + * @type {EXTDisjointTimerQueryWebGL2?} + * @default null + */ + this.disjoint = null; + + /** + * A reference to the `KHR_parallel_shader_compile` extension. `null` if the + * device does not support the extension. + * + * @type {KHRParallelShaderCompile?} + * @default null + */ + this.parallel = null; + + /** + * Whether to track timestamps with a Timestamp Query API or not. + * + * @type {Boolean} + * @default false + */ + this.trackTimestamp = ( parameters.trackTimestamp === true ); + + /** + * A reference to the current render context. + * + * @private + * @type {RenderContext} + * @default null + */ + this._currentContext = null; + + /** + * A unique collection of bindings. + * + * @private + * @type {WeakSet} + */ + this._knownBindings = new WeakSet(); + } + /** + * Initializes the backend so it is ready for usage. + * + * @param {Renderer} renderer - The renderer. + */ init( renderer ) { super.init( renderer ); @@ -66,11 +232,6 @@ class WebGLBackend extends Backend { 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' ); @@ -82,30 +243,52 @@ class WebGLBackend extends Backend { this.disjoint = this.extensions.get( 'EXT_disjoint_timer_query_webgl2' ); this.parallel = this.extensions.get( 'KHR_parallel_shader_compile' ); - this._knownBindings = new WeakSet(); - - this._currentContext = null; - } + /** + * The coordinate system of the backend. + * + * @type {Number} + * @readonly + */ get coordinateSystem() { return WebGLCoordinateSystem; } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { return await this.attributeUtils.getArrayBufferAsync( attribute ); } + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ async waitForGPU() { await this.utils._clientWaitAsync(); } + /** + * Inits a time stamp query for the given render context. + * + * @param {RenderContext} renderContext - The render context. + */ initTimestampQuery( renderContext ) { if ( ! this.disjoint || ! this.trackTimestamp ) return; @@ -140,6 +323,11 @@ class WebGLBackend extends Backend { // timestamp utils + /** + * Prepares the timestamp buffer. + * + * @param {RenderContext} renderContext - The render context. + */ prepareTimestampBuffer( renderContext ) { if ( ! this.disjoint || ! this.trackTimestamp ) return; @@ -166,6 +354,14 @@ class WebGLBackend extends Backend { } + /** + * Resolves the time stamp for the given render context and type. + * + * @async + * @param {RenderContext} renderContext - The render context. + * @param {String} type - The render context. + * @return {Promise} A Promise that resolves when the time stamp has been computed. + */ async resolveTimestampAsync( renderContext, type = 'render' ) { if ( ! this.disjoint || ! this.trackTimestamp ) return; @@ -195,12 +391,23 @@ class WebGLBackend extends Backend { } + /** + * Returns the backend's rendering context. + * + * @return {WebGL2RenderingContext} The rendering context. + */ getContext() { return this.gl; } + /** + * This method is executed at the beginning of a render call and prepares + * the WebGL state for upcoming render calls + * + * @param {RenderContext} renderContext - The render context. + */ beginRender( renderContext ) { const { gl } = this; @@ -256,6 +463,12 @@ class WebGLBackend extends Backend { } + /** + * This method is executed at the end of a render call and finalizes work + * after draw calls. + * + * @param {RenderContext} renderContext - The render context. + */ finishRender( renderContext ) { const { gl, state } = this; @@ -362,6 +575,13 @@ class WebGLBackend extends Backend { } + /** + * This method processes the result of occlusion queries and writes it + * into render context data. + * + * @async + * @param {RenderContext} renderContext - The render context. + */ resolveOccludedAsync( renderContext ) { const renderContextData = this.get( renderContext ); @@ -391,7 +611,7 @@ class WebGLBackend extends Backend { if ( gl.getQueryParameter( query, gl.QUERY_RESULT_AVAILABLE ) ) { - if ( gl.getQueryParameter( query, gl.QUERY_RESULT ) > 0 ) occluded.add( currentOcclusionQueryObjects[ i ] ); + if ( gl.getQueryParameter( query, gl.QUERY_RESULT ) === 0 ) occluded.add( currentOcclusionQueryObjects[ i ] ); currentOcclusionQueries[ i ] = null; gl.deleteQuery( query ); @@ -420,6 +640,14 @@ class WebGLBackend extends Backend { } + /** + * Returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ isOccluded( renderContext, object ) { const renderContextData = this.get( renderContext ); @@ -428,6 +656,11 @@ class WebGLBackend extends Backend { } + /** + * Updates the viewport with the values from the given render context. + * + * @param {RenderContext} renderContext - The render context. + */ updateViewport( renderContext ) { const gl = this.gl; @@ -437,6 +670,11 @@ class WebGLBackend extends Backend { } + /** + * Defines the scissor test. + * + * @param {Boolean} boolean - Whether the scissor test should be enabled or not. + */ setScissorTest( boolean ) { const gl = this.gl; @@ -453,6 +691,15 @@ class WebGLBackend extends Backend { } + /** + * Performs a clear operation. + * + * @param {Boolean} color - Whether the color buffer should be cleared or not. + * @param {Boolean} depth - Whether the depth buffer should be cleared or not. + * @param {Boolean} stencil - Whether the stencil buffer should be cleared or not. + * @param {Object?} [descriptor=null] - The render context of the current set render target. + * @param {Boolean} [setFrameBuffer=true] - TODO. + */ clear( color, depth, stencil, descriptor = null, setFrameBuffer = true ) { const { gl } = this; @@ -543,6 +790,12 @@ class WebGLBackend extends Backend { } + /** + * This method is executed at the beginning of a compute call and + * prepares the state for upcoming compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ beginCompute( computeGroup ) { const { state, gl } = this; @@ -552,11 +805,19 @@ class WebGLBackend extends Backend { } + /** + * Executes a compute command for the given compute node. + * + * @param {Node|Array} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @param {ComputePipeline} pipeline - The compute pipeline. + */ compute( computeGroup, computeNode, bindings, pipeline ) { const { state, gl } = this; - if ( ! this.discard ) { + if ( this.discard === false ) { // required here to handle async behaviour of render.compute() gl.enable( gl.RASTERIZER_DISCARD ); @@ -621,6 +882,12 @@ class WebGLBackend extends Backend { } + /** + * This method is executed at the end of a compute call and + * finalizes work after compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ finishCompute( computeGroup ) { const gl = this.gl; @@ -639,6 +906,12 @@ class WebGLBackend extends Backend { } + /** + * Executes a draw command for the given render object. + * + * @param {RenderObject} renderObject - The render object to draw. + * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. + */ draw( renderObject/*, info*/ ) { const { object, pipeline, material, context, hardwareClippingPlanes } = renderObject; @@ -801,12 +1074,24 @@ class WebGLBackend extends Backend { } + /** + * Explain why always null is returned. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render pipeline requires an update or not. + */ needsRenderUpdate( /*renderObject*/ ) { return false; } + /** + * Explain why no cache key is computed. + * + * @param {RenderObject} renderObject - The render object. + * @return {String} The cache key. + */ getRenderCacheKey( /*renderObject*/ ) { return ''; @@ -815,53 +1100,109 @@ class WebGLBackend extends Backend { // textures + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { this.textureUtils.createDefaultTexture( texture ); } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ createTexture( texture, options ) { this.textureUtils.createTexture( texture, options ); } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { this.textureUtils.updateTexture( texture, options ); } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { this.textureUtils.generateMipmaps( texture ); } - + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { this.textureUtils.destroyTexture( texture ); } - copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); } + /** + * This method does nothing since WebGL 2 has no concept of samplers. + * + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( /*texture*/ ) { //console.warn( 'Abstract class.' ); } - destroySampler() {} + /** + * This method does nothing since WebGL 2 has no concept of samplers. + * + * @param {Texture} texture - The texture to destroy the sampler for. + */ + destroySampler( /*texture*/ ) {} // node builder + /** + * Returns a node builder for the given render object. + * + * @param {RenderObject} object - The render object. + * @param {Renderer} renderer - The renderer. + * @return {GLSLNodeBuilder} The node builder. + */ createNodeBuilder( object, renderer ) { return new GLSLNodeBuilder( object, renderer ); @@ -870,6 +1211,11 @@ class WebGLBackend extends Backend { // program + /** + * Creates a shader program from the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ createProgram( program ) { const gl = this.gl; @@ -886,12 +1232,23 @@ class WebGLBackend extends Backend { } - destroyProgram( /*program*/ ) { + /** + * Destroys the shader program of the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ + destroyProgram( program ) { - console.warn( 'Abstract class.' ); + this.delete( program ); } + /** + * Creates a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ createRenderPipeline( renderObject, promises ) { const gl = this.gl; @@ -950,6 +1307,14 @@ class WebGLBackend extends Backend { } + /** + * Formats the source code of error messages. + * + * @private + * @param {String} string - The code. + * @param {Number} errorLine - The error line. + * @return {String} The formatted code. + */ _handleSource( string, errorLine ) { const lines = string.split( '\n' ); @@ -969,6 +1334,15 @@ class WebGLBackend extends Backend { } + /** + * Gets the shader compilation errors from the info log. + * + * @private + * @param {WebGL2RenderingContext} gl - The rendering context. + * @param {WebGLShader} shader - The WebGL shader object. + * @param {String} type - The shader type. + * @return {String} The shader errors. + */ _getShaderErrors( gl, shader, type ) { const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); @@ -990,6 +1364,14 @@ class WebGLBackend extends Backend { } + /** + * Logs shader compilation errors. + * + * @private + * @param {WebGLProgram} programGPU - The WebGL program. + * @param {WebGLShader} glFragmentShader - The fragment shader as a native WebGL shader object. + * @param {WebGLShader} glVertexShader - The vertex shader as a native WebGL shader object. + */ _logProgramError( programGPU, glFragmentShader, glVertexShader ) { if ( this.renderer.debug.checkShaderErrors ) { @@ -1032,6 +1414,13 @@ class WebGLBackend extends Backend { } + /** + * Completes the shader program setup for the given render object. + * + * @private + * @param {RenderObject} renderObject - The render object. + * @param {RenderPipeline} pipeline - The render pipeline. + */ _completeCompile( renderObject, pipeline ) { const { state, gl } = this; @@ -1060,6 +1449,12 @@ class WebGLBackend extends Backend { } + /** + * Creates a compute pipeline for the given compute node. + * + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ createComputePipeline( computePipeline, bindings ) { const { state, gl } = this; @@ -1154,7 +1549,15 @@ class WebGLBackend extends Backend { } - createBindings( bindGroup, bindings ) { + /** + * Creates bindings from the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + createBindings( bindGroup, bindings /*, cacheIndex, version*/ ) { if ( this._knownBindings.has( bindings ) === false ) { @@ -1185,7 +1588,15 @@ class WebGLBackend extends Backend { } - updateBindings( bindGroup /*, bindings*/ ) { + /** + * Updates the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ + updateBindings( bindGroup /*, bindings, cacheIndex, version*/ ) { const { gl } = this; @@ -1225,6 +1636,11 @@ class WebGLBackend extends Backend { } + /** + * Updates a buffer binding. + * + * @param {Buffer} binding - The buffer binding to update. + */ updateBinding( binding ) { const gl = this.gl; @@ -1244,6 +1660,11 @@ class WebGLBackend extends Backend { // attributes + /** + * Creates the GPU buffer of an indexed shader attribute. + * + * @param {BufferAttribute} attribute - The indexed buffer attribute. + */ createIndexAttribute( attribute ) { const gl = this.gl; @@ -1252,6 +1673,11 @@ class WebGLBackend extends Backend { } + /** + * Creates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createAttribute( attribute ) { if ( this.has( attribute ) ) return; @@ -1262,6 +1688,11 @@ class WebGLBackend extends Backend { } + /** + * Creates the GPU buffer of a storage attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createStorageAttribute( attribute ) { if ( this.has( attribute ) ) return; @@ -1272,24 +1703,34 @@ class WebGLBackend extends Backend { } + /** + * Updates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to update. + */ updateAttribute( attribute ) { this.attributeUtils.updateAttribute( attribute ); } + /** + * Destroys the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to destroy. + */ destroyAttribute( attribute ) { this.attributeUtils.destroyAttribute( attribute ); } - updateSize() { - - //console.warn( 'Abstract class.' ); - - } - + /** + * Checks if the given feature is supported by the backend. + * + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ hasFeature( name ) { const keysMatching = Object.keys( GLFeatureName ).filter( key => GLFeatureName[ key ] === name ); @@ -1306,24 +1747,51 @@ class WebGLBackend extends Backend { } + /** + * Returns the maximum anisotropy texture filtering value. + * + * @return {Number} The maximum anisotropy texture filtering value. + */ getMaxAnisotropy() { return this.capabilities.getMaxAnisotropy(); } - copyTextureToTexture( srcTexture, dstTexture, srcRegion, dstPosition, level ) { + /** + * Copies data of the given source texture to the given destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ + copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { this.textureUtils.copyTextureToTexture( srcTexture, dstTexture, srcRegion, dstPosition, level ); } + /** + * Copies the current bound framebuffer to the given texture. + * + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ copyFramebufferToTexture( texture, renderContext, rectangle ) { this.textureUtils.copyFramebufferToTexture( texture, renderContext, rectangle ); } + /** + * Configures the active framebuffer from the given render context. + * + * @private + * @param {RenderContext} descriptor - The render context. + */ _setFramebuffer( descriptor ) { const { gl, state } = this; @@ -1337,6 +1805,8 @@ class WebGLBackend extends Backend { const { samples, depthBuffer, stencilBuffer } = renderTarget; const isCube = renderTarget.isWebGLCubeRenderTarget === true; + const isRenderTarget3D = renderTarget.isRenderTarget3D === true; + const isRenderTargetArray = renderTarget.isRenderTargetArray === true; let msaaFb = renderTargetContextData.msaaFrameBuffer; let depthRenderbuffer = renderTargetContextData.depthRenderbuffer; @@ -1390,7 +1860,19 @@ class WebGLBackend extends Backend { const attachment = gl.COLOR_ATTACHMENT0 + i; - gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0 ); + if ( isRenderTarget3D || isRenderTargetArray ) { + + const layer = this.renderer._activeCubeFace; + + gl.framebufferTextureLayer( gl.FRAMEBUFFER, attachment, textureData.textureGPU, 0, layer ); + + } else { + + gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0 ); + + } + + } @@ -1482,10 +1964,17 @@ class WebGLBackend extends Backend { } - + /** + * Computes the VAO key for the given index and attributes. + * + * @private + * @param {BufferAttribute?} index - The index. `null` for non-indexed geometries. + * @param {Array} attributes - An array of buffer attributes. + * @return {String} The VAO key. + */ _getVaoKey( index, attributes ) { - let key = []; + let key = ''; if ( index !== null ) { @@ -1507,6 +1996,14 @@ class WebGLBackend extends Backend { } + /** + * Creates a VAO from the index and attributes. + * + * @private + * @param {BufferAttribute?} index - The index. `null` for non-indexed geometries. + * @param {Array} attributes - An array of buffer attributes. + * @return {Object} The VAO data. + */ _createVao( index, attributes ) { const { gl } = this; @@ -1584,6 +2081,13 @@ class WebGLBackend extends Backend { } + /** + * Creates a transform feedback from the given transform buffers. + * + * @private + * @param {Array} transformBuffers - The transform buffers. + * @return {WebGLTransformFeedback} The transform feedback. + */ _getTransformFeedback( transformBuffers ) { let key = ''; @@ -1624,7 +2128,13 @@ class WebGLBackend extends Backend { } - + /** + * Setups the given bindings. + * + * @private + * @param {Array} bindings - The bindings. + * @param {WebGLProgram} programGPU - The WebGL program. + */ _setupBindings( bindings, programGPU ) { const gl = this.gl; @@ -1654,6 +2164,12 @@ class WebGLBackend extends Backend { } + /** + * Binds the given uniforms. + * + * @private + * @param {Array} bindings - The bindings. + */ _bindUniforms( bindings ) { const { gl, state } = this; @@ -1682,6 +2198,9 @@ class WebGLBackend extends Backend { } + /** + * Frees internal resources. + */ dispose() { this.renderer.domElement.removeEventListener( 'webglcontextlost', this._onContextLost ); diff --git a/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js b/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js index c9918a4cc08361..597a3be33e4f3f 100644 --- a/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +++ b/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js @@ -9,7 +9,6 @@ import { NoColorSpace, ByteType, ShortType, RGBAIntegerFormat, RGBIntegerFormat, import { DataTexture } from '../../../textures/DataTexture.js'; const glslMethods = { - atan2: 'atan', textureDimensions: 'textureSize', equals: 'equal' }; @@ -46,39 +45,109 @@ precision highp isampler2DArray; precision lowp sampler2DShadow; `; +/** + * A node builder targeting GLSL. + * + * This module generates GLSL shader code from node materials and also + * generates the respective bindings and vertex buffer definitions. These + * data are later used by the renderer to create render and compute pipelines + * for render objects. + * + * @augments NodeBuilder + */ class GLSLNodeBuilder extends NodeBuilder { + /** + * Constructs a new GLSL node builder renderer. + * + * @param {Object3D} object - The 3D object. + * @param {Renderer} renderer - The renderer. + */ constructor( object, renderer ) { super( object, renderer, new GLSLNodeParser() ); + /** + * A dictionary holds for each shader stage ('vertex', 'fragment', 'compute') + * another dictionary which manages UBOs per group ('render','frame','object'). + * + * @type {Object>} + */ this.uniformGroups = {}; + + /** + * An array that holds objects defining the varying and attribute data in + * context of Transform Feedback. + * + * @type {Object>} + */ this.transforms = []; + + /** + * A dictionary that holds for each shader stage a Map of used extensions. + * + * @type {Object>} + */ this.extensions = {}; + + /** + * A dictionary that holds for each shader stage an Array of used builtins. + * + * @type {Object>} + */ this.builtins = { vertex: [], fragment: [], compute: [] }; + /** + * Whether comparison in shader code are generated with methods or not. + * + * @type {Boolean} + * @default true + */ this.useComparisonMethod = true; } + /** + * Checks if the given texture requires a manual conversion to the working color space. + * + * @param {Texture} texture - The texture to check. + * @return {Boolean} Whether the given texture requires a conversion to working color space or not. + */ needsToWorkingColorSpace( texture ) { return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace; } + /** + * Returns the native shader method name for a given generic name. + * + * @param {String} method - The method name to resolve. + * @return {String} The resolved GLSL method name. + */ getMethod( method ) { return glslMethods[ method ] || method; } + /** + * Returns the output struct name. Not relevant for GLSL. + * + * @return {String} + */ getOutputStructName() { return ''; } + /** + * Builds the given shader node. + * + * @param {ShaderNodeInternal} shaderNode - The shader node. + * @return {String} The GLSL function code. + */ buildFunctionCode( shaderNode ) { const layout = shaderNode.layout; @@ -109,6 +178,12 @@ ${ flowData.code } } + /** + * Setups the Pixel Buffer Object (PBO) for the given storage + * buffer node. + * + * @param {StorageBufferNode} storageBufferNode - The storage buffer node. + */ setupPBO( storageBufferNode ) { const attribute = storageBufferNode.value; @@ -177,6 +252,13 @@ ${ flowData.code } } + /** + * Returns a GLSL snippet that represents the property name of the given node. + * + * @param {Node} node - The node. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The property name. + */ getPropertyName( node, shaderStage = this.shaderStage ) { if ( node.isNodeUniform && node.node.isTextureNode !== true && node.node.isBufferNode !== true ) { @@ -189,6 +271,13 @@ ${ flowData.code } } + /** + * Setups the Pixel Buffer Object (PBO) for the given storage + * buffer node. + * + * @param {StorageArrayElementNode} storageArrayElementNode - The storage array element node. + * @return {String} The property name. + */ generatePBO( storageArrayElementNode ) { const { node, indexNode } = storageArrayElementNode; @@ -271,6 +360,16 @@ ${ flowData.code } } + /** + * Generates the GLSL snippet that reads a single texel from a texture without sampling or filtering. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvIndexSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. + * @param {String} [levelSnippet='0u'] - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The GLSL snippet. + */ generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0' ) { if ( depthSnippet ) { @@ -285,6 +384,15 @@ ${ flowData.code } } + /** + * Generates the GLSL snippet for sampling/loading the given texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A GLSL snippet that represents the 0-based texture array index to sample. + * @return {String} The GLSL snippet. + */ generateTexture( texture, textureProperty, uvSnippet, depthSnippet ) { if ( texture.isDepthTexture ) { @@ -301,24 +409,63 @@ ${ flowData.code } } + /** + * Generates the GLSL snippet when sampling textures with explicit mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A GLSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The GLSL snippet. + */ generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet ) { return `textureLod( ${ textureProperty }, ${ uvSnippet }, ${ levelSnippet } )`; } + /** + * Generates the GLSL snippet when sampling textures with a bias to the mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String} biasSnippet - A GLSL snippet that represents the bias to apply to the mip level before sampling. + * @return {String} The GLSL snippet. + */ generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet ) { return `texture( ${ textureProperty }, ${ uvSnippet }, ${ biasSnippet } )`; } + /** + * Generates the GLSL snippet for sampling/loading the given texture using explicit gradients. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {Array} gradSnippet - An array holding both gradient GLSL snippets. + * @return {String} The GLSL snippet. + */ generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet ) { return `textureGrad( ${ textureProperty }, ${ uvSnippet }, ${ gradSnippet[ 0 ] }, ${ gradSnippet[ 1 ] } )`; } + /** + * Generates the GLSL snippet for sampling a depth texture and comparing the sampled depth values + * against a reference value. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A GLSL snippet that represents texture coordinates used for sampling. + * @param {String} compareSnippet - A GLSL snippet that represents the reference value. + * @param {String?} depthSnippet - A GLSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The GLSL snippet. + */ generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -333,6 +480,12 @@ ${ flowData.code } } + /** + * Returns the variables of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the variables. + */ getVars( shaderStage ) { const snippets = []; @@ -353,6 +506,12 @@ ${ flowData.code } } + /** + * Returns the uniforms of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the uniforms. + */ getUniforms( shaderStage ) { const uniforms = this.uniforms[ shaderStage ]; @@ -470,6 +629,12 @@ ${ flowData.code } } + /** + * Returns the type for a given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + * @return {String} The type. + */ getTypeFromAttribute( attribute ) { let nodeType = super.getTypeFromAttribute( attribute ); @@ -494,6 +659,12 @@ ${ flowData.code } } + /** + * Returns the shader attributes of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the shader attributes. + */ getAttributes( shaderStage ) { let snippet = ''; @@ -516,6 +687,12 @@ ${ flowData.code } } + /** + * Returns the members of the given struct type node as a GLSL string. + * + * @param {StructTypeNode} struct - The struct type node. + * @return {String} The GLSL snippet that defines the struct members. + */ getStructMembers( struct ) { const snippets = []; @@ -532,6 +709,12 @@ ${ flowData.code } } + /** + * Returns the structs of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the structs. + */ getStructs( shaderStage ) { const snippets = []; @@ -559,6 +742,12 @@ ${ flowData.code } } + /** + * Returns the varyings of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the varyings. + */ getVaryings( shaderStage ) { let snippet = ''; @@ -604,18 +793,33 @@ ${ flowData.code } } + /** + * Returns the vertex index builtin. + * + * @return {String} The vertex index. + */ getVertexIndex() { return 'uint( gl_VertexID )'; } + /** + * Returns the instance index builtin. + * + * @return {String} The instance index. + */ getInstanceIndex() { return 'uint( gl_InstanceID )'; } + /** + * Returns the invocation local index builtin. + * + * @return {String} The invocation local index. + */ getInvocationLocalIndex() { const workgroupSize = this.object.workgroupSize; @@ -626,6 +830,11 @@ ${ flowData.code } } + /** + * Returns the draw index builtin. + * + * @return {String?} The drawIndex shader string. Returns `null` if `WEBGL_multi_draw` isn't supported by the device. + */ getDrawIndex() { const extensions = this.renderer.backend.extensions; @@ -640,24 +849,46 @@ ${ flowData.code } } + /** + * Returns the front facing builtin. + * + * @return {String} The front facing builtin. + */ getFrontFacing() { return 'gl_FrontFacing'; } + /** + * Returns the frag coord builtin. + * + * @return {String} The frag coord builtin. + */ getFragCoord() { return 'gl_FragCoord.xy'; } + /** + * Returns the frag depth builtin. + * + * @return {String} The frag depth builtin. + */ getFragDepth() { return 'gl_FragDepth'; } + /** + * Enables the given extension. + * + * @param {String} name - The extension name. + * @param {String} behavior - The extension behavior. + * @param {String} [shaderStage=this.shaderStage] - The shader stage. + */ enableExtension( name, behavior, shaderStage = this.shaderStage ) { const map = this.extensions[ shaderStage ] || ( this.extensions[ shaderStage ] = new Map() ); @@ -673,6 +904,12 @@ ${ flowData.code } } + /** + * Returns the enabled extensions of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the enabled extensions. + */ getExtensions( shaderStage ) { const snippets = []; @@ -706,12 +943,23 @@ ${ flowData.code } } + /** + * Returns the clip distances builtin. + * + * @return {String} The clip distances builtin. + */ getClipDistance() { return 'gl_ClipDistance'; } + /** + * Whether the requested feature is available or not. + * + * @param {String} name - The requested feature. + * @return {Boolean} Whether the requested feature is supported or not. + */ isAvailable( name ) { let result = supports[ name ]; @@ -755,12 +1003,22 @@ ${ flowData.code } } + /** + * Whether to flip texture data along its vertical axis or not. + * + * @return {Boolean} Returns always `true` in context of GLSL. + */ isFlipY() { return true; } + /** + * Enables hardware clipping. + * + * @param {String} planeCount - The clipping plane count. + */ enableHardwareClipping( planeCount ) { this.enableExtension( 'GL_ANGLE_clip_cull_distance', 'require' ); @@ -769,12 +1027,24 @@ ${ flowData.code } } + /** + * Registers a transform in context of Transform Feedback. + * + * @param {String} varyingName - The varying name. + * @param {AttributeNode} attributeNode - The attribute node. + */ registerTransform( varyingName, attributeNode ) { this.transforms.push( { varyingName, attributeNode } ); } + /** + * Returns the transforms of the given shader stage as a GLSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The GLSL snippet that defines the transforms. + */ getTransforms( /* shaderStage */ ) { const transforms = this.transforms; @@ -795,6 +1065,14 @@ ${ flowData.code } } + /** + * Returns a GLSL struct based on the given name and variables. + * + * @private + * @param {String} name - The struct name. + * @param {String} vars - The struct variables. + * @return {String} The GLSL snippet representing a struct. + */ _getGLSLUniformStruct( name, vars ) { return ` @@ -804,6 +1082,13 @@ ${vars} } + /** + * Returns a GLSL vertex shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getGLSLVertexCode( shaderData ) { return `#version 300 es @@ -846,6 +1131,13 @@ void main() { } + /** + * Returns a GLSL fragment shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getGLSLFragmentCode( shaderData ) { return `#version 300 es @@ -879,6 +1171,9 @@ void main() { } + /** + * Controls the code build of the shader stages. + */ buildCode() { const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; @@ -959,6 +1254,19 @@ void main() { } + /** + * This method is one of the more important ones since it's responsible + * for generating a matching binding instance for the given uniform node. + * + * These bindings are later used in the renderer to create bind groups + * and layouts. + * + * @param {UniformNode} node - The uniform node. + * @param {String} type - The node data type. + * @param {String} shaderStage - The shader stage. + * @param {String?} [name=null] - An optional uniform name. + * @return {NodeUniform} The node uniform object. + */ getUniformFromNode( node, type, shaderStage, name = null ) { const uniformNode = super.getUniformFromNode( node, type, shaderStage, name ); diff --git a/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js b/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js index b11888cbb9186b..4082a9d5aefb44 100644 --- a/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +++ b/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js @@ -2,6 +2,14 @@ import { IntType } from '../../../constants.js'; let _id = 0; +/** + * This module is internally used in context of compute shaders. + * This type of shader is not natively supported in WebGL 2 and + * thus implemented via Transform Feedback. `DualAttributeData` + * manages the related data. + * + * @private + */ class DualAttributeData { constructor( attributeData, dualBuffer ) { @@ -46,14 +54,35 @@ class DualAttributeData { } +/** + * A WebGL 2 backend utility module for managing shader attributes. + * + * @private + */ class WebGLAttributeUtils { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; } + /** + * Creates the GPU buffer for the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + * @param {GLenum } bufferType - A flag that indicates the buffer type and thus binding point target. + */ createAttribute( attribute, bufferType ) { const backend = this.backend; @@ -141,7 +170,7 @@ class WebGLAttributeUtils { if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) { - // create buffer for tranform feedback use + // create buffer for transform feedback use const bufferGPUDual = this._createBuffer( gl, bufferType, array, usage ); attributeData = new DualAttributeData( attributeData, bufferGPUDual ); @@ -151,6 +180,11 @@ class WebGLAttributeUtils { } + /** + * Updates the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ updateAttribute( attribute ) { const backend = this.backend; @@ -190,6 +224,11 @@ class WebGLAttributeUtils { } + /** + * Destroys the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ destroyAttribute( attribute ) { const backend = this.backend; @@ -209,6 +248,14 @@ class WebGLAttributeUtils { } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { const backend = this.backend; @@ -247,6 +294,16 @@ class WebGLAttributeUtils { } + /** + * Creates a WebGL buffer with the given data. + * + * @private + * @param {WebGL2RenderingContext} gl - The rendering context. + * @param {GLenum } bufferType - A flag that indicates the buffer type and thus binding point target. + * @param {TypedArray} array - The array of the buffer attribute. + * @param {GLenum} usage - The usage. + * @return {WebGLBuffer} The WebGL buffer. + */ _createBuffer( gl, bufferType, array, usage ) { const bufferGPU = gl.createBuffer(); diff --git a/src/renderers/webgl-fallback/utils/WebGLCapabilities.js b/src/renderers/webgl-fallback/utils/WebGLCapabilities.js index 52f0df44684050..8aff47cd3654ea 100644 --- a/src/renderers/webgl-fallback/utils/WebGLCapabilities.js +++ b/src/renderers/webgl-fallback/utils/WebGLCapabilities.js @@ -1,13 +1,41 @@ +/** + * A WebGL 2 backend utility module for managing the device's capabilities. + * + * @private + */ class WebGLCapabilities { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * This value holds the cached max anisotropy value. + * + * @type {Number?} + * @default null + */ this.maxAnisotropy = null; } + /** + * Returns the maximum anisotropy texture filtering value. This value + * depends on the device and is reported by the `EXT_texture_filter_anisotropic` + * WebGL extension. + * + * @return {Number} The maximum anisotropy texture filtering value. + */ getMaxAnisotropy() { if ( this.maxAnisotropy !== null ) return this.maxAnisotropy; diff --git a/src/renderers/webgl-fallback/utils/WebGLExtensions.js b/src/renderers/webgl-fallback/utils/WebGLExtensions.js index dfb0e5740f9043..ee5d2a33898a2c 100644 --- a/src/renderers/webgl-fallback/utils/WebGLExtensions.js +++ b/src/renderers/webgl-fallback/utils/WebGLExtensions.js @@ -1,16 +1,55 @@ +/** + * A WebGL 2 backend utility module for managing extensions. + * + * @private + */ class WebGLExtensions { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = this.backend.gl; + + /** + * A list with all the supported WebGL extensions. + * + * @type {Array} + */ this.availableExtensions = this.gl.getSupportedExtensions(); + /** + * A dictionary with requested WebGL extensions. + * The key is the name of the extension, the value + * the requested extension object. + * + * @type {Object} + */ this.extensions = {}; } + /** + * Returns the extension object for the given extension name. + * + * @param {String} name - The extension name. + * @return {Object} The extension object. + */ get( name ) { let extension = this.extensions[ name ]; @@ -27,6 +66,12 @@ class WebGLExtensions { } + /** + * Returns `true` if the requested extension is available. + * + * @param {String} name - The extension name. + * @return {Boolean} Whether the given extension is available or not. + */ has( name ) { return this.availableExtensions.includes( name ); diff --git a/src/renderers/webgl-fallback/utils/WebGLState.js b/src/renderers/webgl-fallback/utils/WebGLState.js index 3e0569eca35e44..c623c82c072e04 100644 --- a/src/renderers/webgl-fallback/utils/WebGLState.js +++ b/src/renderers/webgl-fallback/utils/WebGLState.js @@ -9,14 +9,43 @@ import { let initialized = false, equationToGL, factorToGL; +/** + * A WebGL 2 backend utility module for managing the WebGL state. + * + * The major goal of this module is to reduce the number of state changes + * by caching the WEbGL state with a series of variables. In this way, the + * renderer only executes state change commands when necessary which + * improves the overall performance. + * + * @private + */ class WebGLState { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = this.backend.gl; + // Below properties are intended to cache + // the WebGL state and are not explicitly + // documented for convenience reasons. + this.enabled = {}; this.currentFlipSided = null; this.currentCullFace = null; @@ -53,7 +82,7 @@ class WebGLState { if ( initialized === false ) { - this._init( this.gl ); + this._init(); initialized = true; @@ -61,7 +90,14 @@ class WebGLState { } - _init( gl ) { + /** + * Inits the state of the utility. + * + * @private + */ + _init() { + + const gl = this.gl; // Store only WebGL constants here. @@ -87,6 +123,14 @@ class WebGLState { } + /** + * Enables the given WebGL capability. + * + * This method caches the capability state so + * `gl.enable()` is only called when necessary. + * + * @param {GLenum} id - The capability to enable. + */ enable( id ) { const { enabled } = this; @@ -100,6 +144,14 @@ class WebGLState { } + /** + * Disables the given WebGL capability. + * + * This method caches the capability state so + * `gl.disable()` is only called when necessary. + * + * @param {GLenum} id - The capability to enable. + */ disable( id ) { const { enabled } = this; @@ -113,6 +165,15 @@ class WebGLState { } + /** + * Specifies whether polygons are front- or back-facing + * by setting the winding orientation. + * + * This method caches the state so `gl.frontFace()` is only + * called when necessary. + * + * @param {Boolean} flipSided - Whether triangles flipped their sides or not. + */ setFlipSided( flipSided ) { if ( this.currentFlipSided !== flipSided ) { @@ -135,6 +196,15 @@ class WebGLState { } + /** + * Specifies whether or not front- and/or back-facing + * polygons can be culled. + * + * This method caches the state so `gl.cullFace()` is only + * called when necessary. + * + * @param {Number} cullFace - Defines which polygons are candidates for culling. + */ setCullFace( cullFace ) { const { gl } = this; @@ -171,6 +241,14 @@ class WebGLState { } + /** + * Specifies the width of line primitives. + * + * This method caches the state so `gl.lineWidth()` is only + * called when necessary. + * + * @param {Number} width - The line width. + */ setLineWidth( width ) { const { currentLineWidth, gl } = this; @@ -185,7 +263,21 @@ class WebGLState { } - + /** + * Defines the blending. + * + * This method caches the state so `gl.blendEquation()`, `gl.blendEquationSeparate()`, + * `gl.blendFunc()` and `gl.blendFuncSeparate()` are only called when necessary. + * + * @param {Number} blending - The blending type. + * @param {Number} blendEquation - The blending equation. + * @param {Number} blendSrc - Only relevant for custom blending. The RGB source blending factor. + * @param {Number} blendDst - Only relevant for custom blending. The RGB destination blending factor. + * @param {Number} blendEquationAlpha - Only relevant for custom blending. The blending equation for alpha. + * @param {Number} blendSrcAlpha - Only relevant for custom blending. The alpha source blending factor. + * @param {Number} blendDstAlpha - Only relevant for custom blending. The alpha destination blending factor. + * @param {Boolean} premultipliedAlpha - Whether premultiplied alpha is enabled or not. + */ setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { const { gl } = this; @@ -322,6 +414,15 @@ class WebGLState { } + /** + * Specifies whether colors can be written when rendering + * into a framebuffer or not. + * + * This method caches the state so `gl.colorMask()` is only + * called when necessary. + * + * @param {Boolean} colorMask - The color mask. + */ setColorMask( colorMask ) { if ( this.currentColorMask !== colorMask ) { @@ -333,6 +434,11 @@ class WebGLState { } + /** + * Specifies whether the depth test is enabled or not. + * + * @param {Boolean} depthTest - Whether the depth test is enabled or not. + */ setDepthTest( depthTest ) { const { gl } = this; @@ -349,6 +455,15 @@ class WebGLState { } + /** + * Specifies whether depth values can be written when rendering + * into a framebuffer or not. + * + * This method caches the state so `gl.depthMask()` is only + * called when necessary. + * + * @param {Boolean} depthMask - The depth mask. + */ setDepthMask( depthMask ) { if ( this.currentDepthMask !== depthMask ) { @@ -360,6 +475,14 @@ class WebGLState { } + /** + * Specifies the depth compare function. + * + * This method caches the state so `gl.depthFunc()` is only + * called when necessary. + * + * @param {Number} depthFunc - The depth compare function. + */ setDepthFunc( depthFunc ) { if ( this.currentDepthFunc !== depthFunc ) { @@ -420,6 +543,11 @@ class WebGLState { } + /** + * Specifies whether the stencil test is enabled or not. + * + * @param {Boolean} stencilTest - Whether the stencil test is enabled or not. + */ setStencilTest( stencilTest ) { const { gl } = this; @@ -436,6 +564,15 @@ class WebGLState { } + /** + * Specifies whether stencil values can be written when rendering + * into a framebuffer or not. + * + * This method caches the state so `gl.stencilMask()` is only + * called when necessary. + * + * @param {Boolean} stencilMask - The stencil mask. + */ setStencilMask( stencilMask ) { if ( this.currentStencilMask !== stencilMask ) { @@ -447,6 +584,16 @@ class WebGLState { } + /** + * Specifies whether the stencil test functions. + * + * This method caches the state so `gl.stencilFunc()` is only + * called when necessary. + * + * @param {Number} stencilFunc - The stencil compare function. + * @param {Number} stencilRef - The reference value for the stencil test. + * @param {Number} stencilMask - A bit-wise mask that is used to AND the reference value and the stored stencil value when the test is done. + */ setStencilFunc( stencilFunc, stencilRef, stencilMask ) { if ( this.currentStencilFunc !== stencilFunc || @@ -463,6 +610,17 @@ class WebGLState { } + /** + * Specifies whether the stencil test operation. + * + * This method caches the state so `gl.stencilOp()` is only + * called when necessary. + * + * @param {Number} stencilFail - The function to use when the stencil test fails. + * @param {Number} stencilZFail - The function to use when the stencil test passes, but the depth test fail. + * @param {Number} stencilZPass - The function to use when both the stencil test and the depth test pass, + * or when the stencil test passes and there is no depth buffer or depth testing is disabled. + */ setStencilOp( stencilFail, stencilZFail, stencilZPass ) { if ( this.currentStencilFail !== stencilFail || @@ -479,6 +637,13 @@ class WebGLState { } + /** + * Configures the WebGL state for the given material. + * + * @param {Material} material - The material to configure the state for. + * @param {Number} frontFaceCW - Whether the front faces are counter-clockwise or not. + * @param {Number} hardwareClippingPlanes - The number of hardware clipping planes. + */ setMaterial( material, frontFaceCW, hardwareClippingPlanes ) { const { gl } = this; @@ -543,6 +708,16 @@ class WebGLState { } + /** + * Specifies the polygon offset. + * + * This method caches the state so `gl.polygonOffset()` is only + * called when necessary. + * + * @param {Boolean} polygonOffset - Whether polygon offset is enabled or not. + * @param {Number} factor - The scale factor for the variable depth offset for each polygon. + * @param {Number} units - The multiplier by which an implementation-specific value is multiplied with to create a constant depth offset. + */ setPolygonOffset( polygonOffset, factor, units ) { const { gl } = this; @@ -568,6 +743,15 @@ class WebGLState { } + /** + * Defines the usage of the given WebGL program. + * + * This method caches the state so `gl.useProgram()` is only + * called when necessary. + * + * @param {WebGLProgram} program - The WebGL program to use. + * @return {Boolean} Whether a program change has been executed or not. + */ useProgram( program ) { if ( this.currentProgram !== program ) { @@ -587,6 +771,16 @@ class WebGLState { // framebuffer + /** + * Binds the given framebuffer. + * + * This method caches the state so `gl.bindFramebuffer()` is only + * called when necessary. + * + * @param {Number} target - The binding point (target). + * @param {WebGLFramebuffer} framebuffer - The WebGL framebuffer to bind. + * @return {Boolean} Whether a bind has been executed or not. + */ bindFramebuffer( target, framebuffer ) { const { gl, currentBoundFramebuffers } = this; @@ -619,6 +813,16 @@ class WebGLState { } + /** + * Defines draw buffers to which fragment colors are written into. + * Configures the MRT setup of custom framebuffers. + * + * This method caches the state so `gl.drawBuffers()` is only + * called when necessary. + * + * @param {RenderContext} renderContext - The render context. + * @param {WebGLFramebuffer} framebuffer - The WebGL framebuffer. + */ drawBuffers( renderContext, framebuffer ) { const { gl } = this; @@ -679,6 +883,14 @@ class WebGLState { // texture + /** + * Makes the given texture unit active. + * + * This method caches the state so `gl.activeTexture()` is only + * called when necessary. + * + * @param {Number} webglSlot - The texture unit to make active. + */ activeTexture( webglSlot ) { const { gl, currentTextureSlot, maxTextures } = this; @@ -694,6 +906,16 @@ class WebGLState { } + /** + * Binds the given WebGL texture to a target. + * + * This method caches the state so `gl.bindTexture()` is only + * called when necessary. + * + * @param {Number} webglType - The binding point (target). + * @param {WebGLTexture} webglTexture - The WebGL texture to bind. + * @param {Number} webglSlot - The texture. + */ bindTexture( webglType, webglTexture, webglSlot ) { const { gl, currentTextureSlot, currentBoundTextures, maxTextures } = this; @@ -739,6 +961,17 @@ class WebGLState { } + /** + * Binds a given WebGL buffer to a given binding point (target) at a given index. + * + * This method caches the state so `gl.bindBufferBase()` is only + * called when necessary. + * + * @param {Number} target - The target for the bind operation. + * @param {Number} index - The index of the target. + * @param {WebGLBuffer} buffer - The WebGL buffer. + * @return {Boolean} Whether a bind has been executed or not. + */ bindBufferBase( target, index, buffer ) { const { gl } = this; @@ -759,6 +992,12 @@ class WebGLState { } + /** + * Unbinds the current bound texture. + * + * This method caches the state so `gl.bindTexture()` is only + * called when necessary. + */ unbindTexture() { const { gl, currentTextureSlot, currentBoundTextures } = this; diff --git a/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js b/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js index c20a4a733ae6c1..85c8f75921722e 100644 --- a/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +++ b/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js @@ -2,19 +2,53 @@ import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Near let initialized = false, wrappingToGL, filterToGL, compareToGL; +/** + * A WebGL 2 backend utility module for managing textures. + * + * @private + */ class WebGLTextureUtils { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = backend.gl; + + /** + * A reference to a backend module holding extension-related + * utility functions. + * + * @type {WebGLExtensions} + */ this.extensions = backend.extensions; + + /** + * A dictionary for managing default textures. The key + * is the binding point (target), the value the WEbGL texture object. + * + * @type {Object} + */ this.defaultTextures = {}; if ( initialized === false ) { - this._init( this.gl ); + this._init(); initialized = true; @@ -22,7 +56,14 @@ class WebGLTextureUtils { } - _init( gl ) { + /** + * Inits the state of the utility. + * + * @private + */ + _init() { + + const gl = this.gl; // Store only WebGL constants here. @@ -55,20 +96,12 @@ class WebGLTextureUtils { } - filterFallback( f ) { - - const { gl } = this; - - if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - - return gl.NEAREST; - - } - - return gl.LINEAR; - - } - + /** + * Returns the native texture type for the given texture. + * + * @param {Texture} texture - The texture. + * @return {GLenum} The native texture type. + */ getGLTextureType( texture ) { const { gl } = this; @@ -98,6 +131,16 @@ class WebGLTextureUtils { } + /** + * Returns the native texture type for the given texture. + * + * @param {String?} internalFormatName - The internal format name. When `null`, the internal format is derived from the subsequent parameters. + * @param {GLenum} glFormat - The WebGL format. + * @param {GLenum} glType - The WebGL type. + * @param {String} colorSpace - The texture's color space. + * @param {Boolean} [forceLinearTransfer=false] - Whether to force a linear transfer or not. + * @return {GLenum} The internal format. + */ getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { const { gl, extensions } = this; @@ -241,6 +284,12 @@ class WebGLTextureUtils { } + /** + * Sets the texture parameters for the given texture. + * + * @param {GLenum} textureType - The texture type. + * @param {Texture} texture - The texture. + */ setTextureParameters( textureType, texture ) { const { gl, extensions, backend } = this; @@ -294,6 +343,12 @@ class WebGLTextureUtils { } + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { const { gl, backend, defaultTextures } = this; @@ -325,6 +380,13 @@ class WebGLTextureUtils { } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + * @return {undefined} + */ createTexture( texture, options ) { const { gl, backend } = this; @@ -365,6 +427,12 @@ class WebGLTextureUtils { } + /** + * Uploads texture buffer data to the GPU memory. + * + * @param {WebGLBuffer} buffer - The buffer data. + * @param {Texture} texture - The texture, + */ copyBufferToTexture( buffer, texture ) { const { gl, backend } = this; @@ -400,6 +468,12 @@ class WebGLTextureUtils { } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { const { gl } = this; @@ -520,6 +594,11 @@ class WebGLTextureUtils { } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { const { gl, backend } = this; @@ -530,6 +609,11 @@ class WebGLTextureUtils { } + /** + * Deallocates the render buffers of the given render target. + * + * @param {RenderTarget} renderTarget - The render target. + */ deallocateRenderBuffers( renderTarget ) { const { gl, backend } = this; @@ -590,6 +674,11 @@ class WebGLTextureUtils { } + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { const { gl, backend } = this; @@ -602,6 +691,15 @@ class WebGLTextureUtils { } + /** + * Copies data of the given source texture to the given destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { const { gl, backend } = this; @@ -720,6 +818,13 @@ class WebGLTextureUtils { } + /** + * Copies the current bound framebuffer to the given texture. + * + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ copyFramebufferToTexture( texture, renderContext, rectangle ) { const { gl } = this; @@ -731,7 +836,7 @@ class WebGLTextureUtils { const requireDrawFrameBuffer = texture.isDepthTexture === true || ( renderContext.renderTarget && renderContext.renderTarget.samples > 0 ); - const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.gerDrawingBufferSize().y; + const srcHeight = renderContext.renderTarget ? renderContext.renderTarget.height : this.backend.getDrawingBufferSize().y; if ( requireDrawFrameBuffer ) { @@ -807,7 +912,12 @@ class WebGLTextureUtils { } - // Setup storage for internal depth/stencil buffers and bind to correct framebuffer + /** + * SetupS storage for internal depth/stencil buffers and bind to correct framebuffer. + * + * @param {WebGLRenderbuffer} renderbuffer - The render buffer. + * @param {RenderContext} renderContext - The render context. + */ setupRenderBufferStorage( renderbuffer, renderContext ) { const { gl } = this; @@ -862,6 +972,18 @@ class WebGLTextureUtils { } + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { const { backend, gl } = this; @@ -903,6 +1025,13 @@ class WebGLTextureUtils { } + /** + * Returns the corresponding typed array type for the given WebGL data type. + * + * @private + * @param {GLenum} glType - The WebGL data type. + * @return {TypedArray.constructor} The typed array type. + */ _getTypedArrayType( glType ) { const { gl } = this; @@ -922,6 +1051,14 @@ class WebGLTextureUtils { } + /** + * Returns the bytes-per-texel value for the given WebGL data type and texture format. + * + * @private + * @param {GLenum} glType - The WebGL data type. + * @param {GLenum} glFormat - The WebGL texture format. + * @return {Number} The bytes-per-texel. + */ _getBytesPerTexel( glType, glFormat ) { const { gl } = this; diff --git a/src/renderers/webgl-fallback/utils/WebGLUtils.js b/src/renderers/webgl-fallback/utils/WebGLUtils.js index 170fdd00977647..16c9589ffb9d05 100644 --- a/src/renderers/webgl-fallback/utils/WebGLUtils.js +++ b/src/renderers/webgl-fallback/utils/WebGLUtils.js @@ -1,16 +1,52 @@ import { 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_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT5_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT1_Format, RGB_S3TC_DXT1_Format, DepthFormat, DepthStencilFormat, LuminanceAlphaFormat, LuminanceFormat, RedFormat, RGBFormat, RGBAFormat, AlphaFormat, RedIntegerFormat, RGFormat, RGIntegerFormat, RGBAIntegerFormat, HalfFloatType, FloatType, UnsignedIntType, IntType, UnsignedShortType, ShortType, ByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedShort5551Type, UnsignedShort4444Type, UnsignedByteType, RGBA_BPTC_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, RED_GREEN_RGTC2_Format, SIGNED_RED_GREEN_RGTC2_Format, SRGBColorSpace, NoColorSpace } from '../../../constants.js'; +/** + * A WebGL 2 backend utility module with common helpers. + * + * @private + */ class WebGLUtils { + /** + * Constructs a new utility object. + * + * @param {WebGLBackend} backend - The WebGL 2 backend. + */ constructor( backend ) { + /** + * A reference to the WebGL 2 backend. + * + * @type {WebGLBackend} + */ this.backend = backend; + /** + * A reference to the rendering context. + * + * @type {WebGL2RenderingContext} + */ this.gl = this.backend.gl; + + /** + * A reference to a backend module holding extension-related + * utility functions. + * + * @type {WebGLExtensions} + */ this.extensions = backend.extensions; } + /** + * Converts the given three.js constant into a WebGL constant. + * The method currently supports the conversion of texture formats + * and types. + * + * @param {Number} p - The three.js constant. + * @param {String} [colorSpace=NoColorSpace] - The color space. + * @return {Number} The corresponding WebGL constant. + */ convert( p, colorSpace = NoColorSpace ) { const { gl, extensions } = this; @@ -221,6 +257,13 @@ class WebGLUtils { } + /** + * This method can be used to synchronize the CPU with the GPU by waiting until + * ongoing GPU commands have been completed. + * + * @private + * @return {Promise} A promise that resolves when all ongoing GPU commands have been completed. + */ _clientWaitAsync() { const { gl } = this; diff --git a/src/renderers/webgl/WebGLBackground.js b/src/renderers/webgl/WebGLBackground.js index 1344ac8ac4f8db..9abfdb09a4a155 100644 --- a/src/renderers/webgl/WebGLBackground.js +++ b/src/renderers/webgl/WebGLBackground.js @@ -249,6 +249,8 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, boxMesh.geometry.dispose(); boxMesh.material.dispose(); + boxMesh = undefined; + } if ( planeMesh !== undefined ) { @@ -256,6 +258,8 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, planeMesh.geometry.dispose(); planeMesh.material.dispose(); + planeMesh = undefined; + } } diff --git a/src/renderers/webgpu/WebGPUBackend.js b/src/renderers/webgpu/WebGPUBackend.js index 795d4717c10d0f..ef50aa11962fad 100644 --- a/src/renderers/webgpu/WebGPUBackend.js +++ b/src/renderers/webgpu/WebGPUBackend.js @@ -15,14 +15,42 @@ import WebGPUTextureUtils from './utils/WebGPUTextureUtils.js'; import { WebGPUCoordinateSystem } from '../../constants.js'; -// - +/** + * A backend implementation targeting WebGPU. + * + * @private + * @augments Backend + */ class WebGPUBackend extends Backend { + /** + * Constructs a new WebGPU backend. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. + * @param {Boolean} [parameters.trackTimestamp=false] - Whether to track timestamps with a Timestamp Query API or not. + * @param {String} [parameters.powerPreference=undefined] - The power preference. + * @param {Object} [parameters.requiredLimits=undefined] - Specifies the limits that are required by the device request. The request will fail if the adapter cannot provide these limits. + * @param {GPUDevice} [parameters.device=undefined] - If there is an existing GPU device on app level, it can be passed to the renderer as a parameter. + * @param {Number} [parameters.outputType=undefined] - Texture type for output to canvas. By default, device's preferred format is used; other formats may incur overhead. + */ constructor( parameters = {} ) { super( parameters ); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGPUBackend = true; // some parameters require default values other than "undefined" @@ -30,22 +58,101 @@ class WebGPUBackend extends Backend { this.parameters.requiredLimits = ( parameters.requiredLimits === undefined ) ? {} : parameters.requiredLimits; + /** + * Whether to track timestamps with a Timestamp Query API or not. + * + * @type {Boolean} + * @default false + */ this.trackTimestamp = ( parameters.trackTimestamp === true ); + /** + * A reference to the device. + * + * @type {GPUDevice?} + * @default null + */ this.device = null; + + /** + * A reference to the context. + * + * @type {GPUCanvasContext?} + * @default null + */ this.context = null; + + /** + * A reference to the color attachment of the default framebuffer. + * + * @type {GPUTexture?} + * @default null + */ this.colorBuffer = null; + + /** + * A reference to the default render pass descriptor. + * + * @type {Object?} + * @default null + */ this.defaultRenderPassdescriptor = null; + /** + * A reference to a backend module holding common utility functions. + * + * @type {WebGPUUtils} + */ this.utils = new WebGPUUtils( this ); + + /** + * A reference to a backend module holding shader attribute-related + * utility functions. + * + * @type {WebGPUAttributeUtils} + */ this.attributeUtils = new WebGPUAttributeUtils( this ); + + /** + * A reference to a backend module holding shader binding-related + * utility functions. + * + * @type {WebGPUBindingUtils} + */ this.bindingUtils = new WebGPUBindingUtils( this ); + + /** + * A reference to a backend module holding shader pipeline-related + * utility functions. + * + * @type {WebGPUPipelineUtils} + */ this.pipelineUtils = new WebGPUPipelineUtils( this ); + + /** + * A reference to a backend module holding shader texture-related + * utility functions. + * + * @type {WebGPUTextureUtils} + */ this.textureUtils = new WebGPUTextureUtils( this ); + + /** + * A map that manages the resolve buffers for occlusion queries. + * + * @type {Map} + */ this.occludedResolveCache = new Map(); } + /** + * Initializes the backend so it is ready for usage. + * + * @async + * @param {Renderer} renderer - The renderer. + * @return {Promise} A Promise that resolves when the backend has been initialized. + */ async init( renderer ) { await super.init( renderer ); @@ -134,24 +241,53 @@ class WebGPUBackend extends Backend { } + /** + * The coordinate system of the backend. + * + * @type {Number} + * @readonly + */ get coordinateSystem() { return WebGPUCoordinateSystem; } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ async getArrayBufferAsync( attribute ) { return await this.attributeUtils.getArrayBufferAsync( attribute ); } + /** + * Returns the backend's rendering context. + * + * @return {GPUCanvasContext} The rendering context. + */ getContext() { return this.context; } + /** + * Returns the default render pass descriptor. + * + * In WebGPU, the default framebuffer must be configured + * like custom framebuffers so the backend needs a render + * pass descriptor even when rendering directly to screen. + * + * @private + * @return {Object} The render pass descriptor. + */ _getDefaultRenderPassDescriptor() { let descriptor = this.defaultRenderPassdescriptor; @@ -206,7 +342,15 @@ class WebGPUBackend extends Backend { } - _getRenderPassDescriptor( renderContext ) { + /** + * Returns the render pass descriptor for the given render context. + * + * @private + * @param {RenderContext} renderContext - The render context. + * @param {Object} colorAttachmentsConfig - Configuration object for the color attachments. + * @return {Object} The render pass descriptor. + */ + _getRenderPassDescriptor( renderContext, colorAttachmentsConfig = {} ) { const renderTarget = renderContext.renderTarget; const renderTargetData = this.get( renderTarget ); @@ -216,8 +360,11 @@ class WebGPUBackend extends Backend { if ( descriptors === undefined || renderTargetData.width !== renderTarget.width || renderTargetData.height !== renderTarget.height || + renderTargetData.dimensions !== renderTarget.dimensions || renderTargetData.activeMipmapLevel !== renderTarget.activeMipmapLevel || - renderTargetData.samples !== renderTarget.samples + renderTargetData.activeCubeFace !== renderContext.activeCubeFace || + renderTargetData.samples !== renderTarget.samples || + renderTargetData.loadOp !== colorAttachmentsConfig.loadOp ) { descriptors = {}; @@ -247,16 +394,37 @@ class WebGPUBackend extends Backend { const textures = renderContext.textures; const colorAttachments = []; + let sliceIndex; + for ( let i = 0; i < textures.length; i ++ ) { const textureData = this.get( textures[ i ] ); - const textureView = textureData.texture.createView( { + const viewDescriptor = { + label: `colorAttachment_${ i }`, baseMipLevel: renderContext.activeMipmapLevel, mipLevelCount: 1, baseArrayLayer: renderContext.activeCubeFace, + arrayLayerCount: 1, dimension: GPUTextureViewDimension.TwoD - } ); + }; + + if ( renderTarget.isRenderTarget3D ) { + + sliceIndex = renderContext.activeCubeFace; + + viewDescriptor.baseArrayLayer = 0; + viewDescriptor.dimension = GPUTextureViewDimension.ThreeD; + viewDescriptor.depthOrArrayLayers = textures[ i ].image.depth; + + } else if ( renderTarget.isRenderTargetArray ) { + + viewDescriptor.dimension = GPUTextureViewDimension.TwoDArray; + viewDescriptor.depthOrArrayLayers = textures[ i ].image.depth; + + } + + const textureView = textureData.texture.createView( viewDescriptor ); let view, resolveTarget; @@ -274,9 +442,11 @@ class WebGPUBackend extends Backend { colorAttachments.push( { view, + depthSlice: sliceIndex, resolveTarget, loadOp: GPULoadOp.Load, - storeOp: GPUStoreOp.Store + storeOp: GPUStoreOp.Store, + ...colorAttachmentsConfig } ); } @@ -302,7 +472,11 @@ class WebGPUBackend extends Backend { renderTargetData.width = renderTarget.width; renderTargetData.height = renderTarget.height; renderTargetData.samples = renderTarget.samples; - renderTargetData.activeMipmapLevel = renderTarget.activeMipmapLevel; + renderTargetData.activeMipmapLevel = renderContext.activeMipmapLevel; + renderTargetData.activeCubeFace = renderContext.activeCubeFace; + renderTargetData.dimensions = renderTarget.dimensions; + renderTargetData.depthSlice = sliceIndex; + renderTargetData.loadOp = colorAttachments[ 0 ].loadOp; } @@ -310,6 +484,12 @@ class WebGPUBackend extends Backend { } + /** + * This method is executed at the beginning of a render call and prepares + * the WebGPU state for upcoming render calls + * + * @param {RenderContext} renderContext - The render context. + */ beginRender( renderContext ) { const renderContextData = this.get( renderContext ); @@ -350,7 +530,7 @@ class WebGPUBackend extends Backend { } else { - descriptor = this._getRenderPassDescriptor( renderContext ); + descriptor = this._getRenderPassDescriptor( renderContext, { loadOp: GPULoadOp.Load } ); } @@ -469,6 +649,12 @@ class WebGPUBackend extends Backend { } + /** + * This method is executed at the end of a render call and finalizes work + * after draw calls. + * + * @param {RenderContext} renderContext - The render context. + */ finishRender( renderContext ) { const renderContextData = this.get( renderContext ); @@ -557,6 +743,14 @@ class WebGPUBackend extends Backend { } + /** + * Returns `true` if the given 3D object is fully occluded by other + * 3D objects in the scene. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object3D} object - The 3D object to test. + * @return {Boolean} Whether the 3D object is fully occluded or not. + */ isOccluded( renderContext, object ) { const renderContextData = this.get( renderContext ); @@ -565,6 +759,14 @@ class WebGPUBackend extends Backend { } + /** + * This method processes the result of occlusion queries and writes it + * into render context data. + * + * @async + * @param {RenderContext} renderContext - The render context. + * @return {Promise} A Promise that resolves when the occlusion query results have been processed. + */ async resolveOccludedAsync( renderContext ) { const renderContextData = this.get( renderContext ); @@ -587,7 +789,7 @@ class WebGPUBackend extends Backend { for ( let i = 0; i < currentOcclusionQueryObjects.length; i ++ ) { - if ( results[ i ] !== BigInt( 0 ) ) { + if ( results[ i ] === BigInt( 0 ) ) { occluded.add( currentOcclusionQueryObjects[ i ] ); @@ -603,6 +805,11 @@ class WebGPUBackend extends Backend { } + /** + * Updates the viewport with the values from the given render context. + * + * @param {RenderContext} renderContext - The render context. + */ updateViewport( renderContext ) { const { currentPass } = this.get( renderContext ); @@ -612,7 +819,15 @@ class WebGPUBackend extends Backend { } - clear( color, depth, stencil, renderTargetData = null ) { + /** + * Performs a clear operation. + * + * @param {Boolean} color - Whether the color buffer should be cleared or not. + * @param {Boolean} depth - Whether the depth buffer should be cleared or not. + * @param {Boolean} stencil - Whether the stencil buffer should be cleared or not. + * @param {RenderContext?} [renderTargetContext=null] - The render context of the current set render target. + */ + clear( color, depth, stencil, renderTargetContext = null ) { const device = this.device; const renderer = this.renderer; @@ -645,7 +860,7 @@ class WebGPUBackend extends Backend { } - if ( renderTargetData === null ) { + if ( renderTargetContext === null ) { supportsDepth = renderer.depth; supportsStencil = renderer.stencil; @@ -672,45 +887,20 @@ class WebGPUBackend extends Backend { } else { - supportsDepth = renderTargetData.depth; - supportsStencil = renderTargetData.stencil; + supportsDepth = renderTargetContext.depth; + supportsStencil = renderTargetContext.stencil; if ( color ) { - for ( const texture of renderTargetData.textures ) { + const descriptor = this._getRenderPassDescriptor( renderTargetContext, { loadOp: GPULoadOp.Clear, clearValue } ); - 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 - } ); - - } + colorAttachments = descriptor.colorAttachments; } if ( supportsDepth || supportsStencil ) { - const depthTextureData = this.get( renderTargetData.depthTexture ); + const depthTextureData = this.get( renderTargetContext.depthTexture ); depthStencilAttachment = { view: depthTextureData.texture.createView() @@ -760,7 +950,7 @@ class WebGPUBackend extends Backend { // - const encoder = device.createCommandEncoder( {} ); + const encoder = device.createCommandEncoder( { label: 'clear' } ); const currentPass = encoder.beginRenderPass( { colorAttachments, depthStencilAttachment @@ -774,21 +964,37 @@ class WebGPUBackend extends Backend { // compute + /** + * This method is executed at the beginning of a compute call and + * prepares the state for upcoming compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ beginCompute( computeGroup ) { const groupGPU = this.get( computeGroup ); - const descriptor = {}; + const descriptor = { + label: 'computeGroup_' + computeGroup.id + }; this.initTimestampQuery( computeGroup, descriptor ); - groupGPU.cmdEncoderGPU = this.device.createCommandEncoder(); + groupGPU.cmdEncoderGPU = this.device.createCommandEncoder( { label: 'computeGroup_' + computeGroup.id } ); groupGPU.passEncoderGPU = groupGPU.cmdEncoderGPU.beginComputePass( descriptor ); } + /** + * Executes a compute command for the given compute node. + * + * @param {Node|Array} computeGroup - The group of compute nodes of a compute call. Can be a single compute node. + * @param {Node} computeNode - The compute node. + * @param {Array} bindings - The bindings. + * @param {ComputePipeline} pipeline - The compute pipeline. + */ compute( computeGroup, computeNode, bindings, pipeline ) { const { passEncoderGPU } = this.get( computeGroup ); @@ -836,6 +1042,12 @@ class WebGPUBackend extends Backend { } + /** + * This method is executed at the end of a compute call and + * finalizes work after compute tasks. + * + * @param {Node|Array} computeGroup - The compute node(s). + */ finishCompute( computeGroup ) { const groupData = this.get( computeGroup ); @@ -848,6 +1060,13 @@ class WebGPUBackend extends Backend { } + /** + * Can be used to synchronize CPU operations with GPU tasks. So when this method is called, + * the CPU waits for the GPU to complete its operation (e.g. a compute task). + * + * @async + * @return {Promise} A Promise that resolves when synchronization has been finished. + */ async waitForGPU() { await this.device.queue.onSubmittedWorkDone(); @@ -856,6 +1075,12 @@ class WebGPUBackend extends Backend { // render object + /** + * Executes a draw command for the given render object. + * + * @param {RenderObject} renderObject - The render object to draw. + * @param {Info} info - Holds a series of statistical information about the GPU memory and the rendering process. + */ draw( renderObject, info ) { const { object, context, pipeline } = renderObject; @@ -1039,6 +1264,12 @@ class WebGPUBackend extends Backend { // cache key + /** + * Returns `true` if the render pipeline requires an update. + * + * @param {RenderObject} renderObject - The render object. + * @return {Boolean} Whether the render pipeline requires an update or not. + */ needsRenderUpdate( renderObject ) { const data = this.get( renderObject ); @@ -1095,6 +1326,12 @@ class WebGPUBackend extends Backend { } + /** + * Returns a cache key that is used to identify render pipelines. + * + * @param {RenderObject} renderObject - The render object. + * @return {String} The cache key. + */ getRenderCacheKey( renderObject ) { const { object, material } = renderObject; @@ -1123,83 +1360,142 @@ class WebGPUBackend extends Backend { // textures + /** + * Creates a GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( texture ) { this.textureUtils.createSampler( texture ); } + /** + * Destroys the GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to destroy the sampler for. + */ destroySampler( texture ) { this.textureUtils.destroySampler( texture ); } + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { this.textureUtils.createDefaultTexture( texture ); } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ createTexture( texture, options ) { this.textureUtils.createTexture( texture, options ); } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { this.textureUtils.updateTexture( texture, options ); } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { this.textureUtils.generateMipmaps( texture ); } + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { this.textureUtils.destroyTexture( texture ); } - copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ + async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height, faceIndex ); } - + /** + * Inits a time stamp query for the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object} descriptor - The query descriptor. + */ initTimestampQuery( renderContext, descriptor ) { if ( ! this.trackTimestamp ) return; const renderContextData = this.get( renderContext ); - if ( ! renderContextData.timeStampQuerySet ) { + // init query set if not exists + if ( ! renderContextData.timestampQuerySet ) { const type = renderContext.isComputeNode ? 'compute' : 'render'; - const timeStampQuerySet = this.device.createQuerySet( { type: 'timestamp', count: 2, label: `timestamp_${type}_${renderContext.id}` } ); - const timestampWrites = { - querySet: timeStampQuerySet, - beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins. - endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends. - }; + renderContextData.timestampQuerySet = this.device.createQuerySet( { type: 'timestamp', count: 2, label: `timestamp_${type}_${renderContext.id}` } ); - Object.assign( descriptor, { timestampWrites } ); + } - renderContextData.timeStampQuerySet = timeStampQuerySet; + // augment descriptor - } + descriptor.timestampWrites = { + querySet: renderContextData.timestampQuerySet, + beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins. + endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends. + }; } - // timestamp utils - + /** + * Prepares the timestamp buffer. + * + * @param {RenderContext} renderContext - The render context. + * @param {GPUCommandEncoder} encoder - The command encoder. + */ prepareTimestampBuffer( renderContext, encoder ) { if ( ! this.trackTimestamp ) return; @@ -1207,7 +1503,7 @@ class WebGPUBackend extends Backend { const renderContextData = this.get( renderContext ); - const size = 2 * BigInt64Array.BYTES_PER_ELEMENT; + const size = 2 * BigUint64Array.BYTES_PER_ELEMENT; if ( renderContextData.currentTimestampQueryBuffers === undefined ) { @@ -1229,7 +1525,7 @@ class WebGPUBackend extends Backend { const { resolveBuffer, resultBuffer } = renderContextData.currentTimestampQueryBuffers; - encoder.resolveQuerySet( renderContextData.timeStampQuerySet, 0, 2, resolveBuffer, 0 ); + encoder.resolveQuerySet( renderContextData.timestampQuerySet, 0, 2, resolveBuffer, 0 ); if ( resultBuffer.mapState === 'unmapped' ) { @@ -1239,6 +1535,14 @@ class WebGPUBackend extends Backend { } + /** + * Resolves the time stamp for the given render context and type. + * + * @async + * @param {RenderContext} renderContext - The render context. + * @param {String} type - The render context. + * @return {Promise} A Promise that resolves when the time stamp has been computed. + */ async resolveTimestampAsync( renderContext, type = 'render' ) { if ( ! this.trackTimestamp ) return; @@ -1251,18 +1555,15 @@ class WebGPUBackend extends Backend { if ( resultBuffer.mapState === 'unmapped' ) { - resultBuffer.mapAsync( GPUMapMode.READ ).then( () => { - - const times = new BigUint64Array( resultBuffer.getMappedRange() ); - const duration = Number( times[ 1 ] - times[ 0 ] ) / 1000000; - + await resultBuffer.mapAsync( GPUMapMode.READ ); - this.renderer.info.updateTimestamp( type, duration ); + const times = new BigUint64Array( resultBuffer.getMappedRange() ); + const duration = Number( times[ 1 ] - times[ 0 ] ) / 1000000; - resultBuffer.unmap(); + this.renderer.info.updateTimestamp( type, duration ); - } ); + resultBuffer.unmap(); } @@ -1270,6 +1571,13 @@ class WebGPUBackend extends Backend { // node builder + /** + * Returns a node builder for the given render object. + * + * @param {RenderObject} object - The render object. + * @param {Renderer} renderer - The renderer. + * @return {WGSLNodeBuilder} The node builder. + */ createNodeBuilder( object, renderer ) { return new WGSLNodeBuilder( object, renderer ); @@ -1278,17 +1586,27 @@ class WebGPUBackend extends Backend { // program + /** + * Creates a shader program from the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ createProgram( program ) { const programGPU = this.get( program ); programGPU.module = { - module: this.device.createShaderModule( { code: program.code, label: program.stage } ), + module: this.device.createShaderModule( { code: program.code, label: program.stage + ( program.name !== '' ? `_${ program.name }` : '' ) } ), entryPoint: 'main' }; } + /** + * Destroys the shader program of the given programmable stage. + * + * @param {ProgrammableStage} program - The programmable stage. + */ destroyProgram( program ) { this.delete( program ); @@ -1297,18 +1615,35 @@ class WebGPUBackend extends Backend { // pipelines + /** + * Creates a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ createRenderPipeline( renderObject, promises ) { this.pipelineUtils.createRenderPipeline( renderObject, promises ); } + /** + * Creates a compute pipeline for the given compute node. + * + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ createComputePipeline( computePipeline, bindings ) { this.pipelineUtils.createComputePipeline( computePipeline, bindings ); } + /** + * Prepares the state for encoding render bundles. + * + * @param {RenderContext} renderContext - The render context. + */ beginBundle( renderContext ) { const renderContextData = this.get( renderContext ); @@ -1321,6 +1656,12 @@ class WebGPUBackend extends Backend { } + /** + * After processing render bundles this method finalizes related work. + * + * @param {RenderContext} renderContext - The render context. + * @param {RenderBundle} bundle - The render bundle. + */ finishBundle( renderContext, bundle ) { const renderContextData = this.get( renderContext ); @@ -1337,6 +1678,12 @@ class WebGPUBackend extends Backend { } + /** + * Adds a render bundle to the render context data. + * + * @param {RenderContext} renderContext - The render context. + * @param {RenderBundle} bundle - The render bundle to add. + */ addBundle( renderContext, bundle ) { const renderContextData = this.get( renderContext ); @@ -1347,18 +1694,39 @@ class WebGPUBackend extends Backend { // bindings + /** + * Creates bindings from the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ createBindings( bindGroup, bindings, cacheIndex, version ) { this.bindingUtils.createBindings( bindGroup, bindings, cacheIndex, version ); } + /** + * Updates the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ updateBindings( bindGroup, bindings, cacheIndex, version ) { this.bindingUtils.createBindings( bindGroup, bindings, cacheIndex, version ); } + /** + * Updates a buffer binding. + * + * @param {Buffer} binding - The buffer binding to update. + */ updateBinding( binding ) { this.bindingUtils.updateBinding( binding ); @@ -1367,36 +1735,66 @@ class WebGPUBackend extends Backend { // attributes + /** + * Creates the buffer of an indexed shader attribute. + * + * @param {BufferAttribute} attribute - The indexed buffer attribute. + */ createIndexAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Creates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Creates the GPU buffer of a storage attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createStorageAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Creates the GPU buffer of an indirect storage attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ createIndirectStorageAttribute( attribute ) { this.attributeUtils.createAttribute( attribute, GPUBufferUsage.STORAGE | GPUBufferUsage.INDIRECT | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST ); } + /** + * Updates the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to update. + */ updateAttribute( attribute ) { this.attributeUtils.updateAttribute( attribute ); } + /** + * Destroys the GPU buffer of a shader attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute to destroy. + */ destroyAttribute( attribute ) { this.attributeUtils.destroyAttribute( attribute ); @@ -1405,6 +1803,9 @@ class WebGPUBackend extends Backend { // canvas + /** + * Triggers an update of the default render pass descriptor. + */ updateSize() { this.colorBuffer = this.textureUtils.getColorBuffer(); @@ -1414,18 +1815,38 @@ class WebGPUBackend extends Backend { // utils public + /** + * Returns the maximum anisotropy texture filtering value. + * + * @return {Number} The maximum anisotropy texture filtering value. + */ getMaxAnisotropy() { return 16; } + /** + * Checks if the given feature is supported by the backend. + * + * @param {String} name - The feature's name. + * @return {Boolean} Whether the feature is supported or not. + */ hasFeature( name ) { return this.device.features.has( name ); } + /** + * Copies data of the given source texture to the given destination texture. + * + * @param {Texture} srcTexture - The source texture. + * @param {Texture} dstTexture - The destination texture. + * @param {Vector4?} [srcRegion=null] - The region of the source texture to copy. + * @param {(Vector2|Vector3)?} [dstPosition=null] - The destination position of the copy. + * @param {Number} [level=0] - The mip level to copy. + */ copyTextureToTexture( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) { let dstX = 0; @@ -1484,6 +1905,13 @@ class WebGPUBackend extends Backend { } + /** + * Copies the current bound framebuffer to the given texture. + * + * @param {Texture} texture - The destination texture. + * @param {RenderContext} renderContext - The render context. + * @param {Vector4} rectangle - A four dimensional vector defining the origin and dimension of the copy. + */ copyFramebufferToTexture( texture, renderContext, rectangle ) { const renderContextData = this.get( renderContext ); diff --git a/src/renderers/webgpu/WebGPURenderer.Nodes.js b/src/renderers/webgpu/WebGPURenderer.Nodes.js index 2f2dae57f561af..d5c7c18a69e499 100644 --- a/src/renderers/webgpu/WebGPURenderer.Nodes.js +++ b/src/renderers/webgpu/WebGPURenderer.Nodes.js @@ -3,8 +3,28 @@ import WebGLBackend from '../webgl-fallback/WebGLBackend.js'; import WebGPUBackend from './WebGPUBackend.js'; import BasicNodeLibrary from './nodes/BasicNodeLibrary.js'; +/** + * This alternative version of {@link WebGPURenderer} only supports node materials. + * So classes like `MeshBasicMaterial` are not compatible. + * + * @augments module:Renderer~Renderer + */ class WebGPURenderer extends Renderer { + /** + * Constructs a new WebGPU renderer. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 + * to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses it + * WebGL 2 backend no matter if WebGPU is supported or not. + */ constructor( parameters = {} ) { let BackendClass; @@ -31,8 +51,22 @@ class WebGPURenderer extends Renderer { super( backend, parameters ); + /** + * The generic default value is overwritten with the + * standard node library for type mapping. Material + * mapping is not supported with this version. + * + * @type {BasicNodeLibrary} + */ this.library = new BasicNodeLibrary(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGPURenderer = true; } diff --git a/src/renderers/webgpu/WebGPURenderer.js b/src/renderers/webgpu/WebGPURenderer.js index c8ddb67cf638be..2f73348b11ad94 100644 --- a/src/renderers/webgpu/WebGPURenderer.js +++ b/src/renderers/webgpu/WebGPURenderer.js @@ -16,8 +16,29 @@ const debugHandler = { }; */ + +/** + * This renderer is the new alternative of `WebGLRenderer`. `WebGPURenderer` has the ability + * to target different backends. By default, the renderer tries to use a WebGPU backend if the + * browser supports WebGPU. If not, `WebGPURenderer` falls backs to a WebGL 2 backend. + * + * @augments module:Renderer~Renderer + */ class WebGPURenderer extends Renderer { + /** + * Constructs a new WebGPU renderer. + * + * @param {Object} parameters - The configuration parameter. + * @param {Boolean} [parameters.logarithmicDepthBuffer=false] - Whether logarithmic depth buffer is enabled or not. + * @param {Boolean} [parameters.alpha=true] - Whether the default framebuffer (which represents the final contents of the canvas) should be transparent or opaque. + * @param {Boolean} [parameters.depth=true] - Whether the default framebuffer should have a depth buffer or not. + * @param {Boolean} [parameters.stencil=false] - Whether the default framebuffer should have a stencil buffer or not. + * @param {Boolean} [parameters.antialias=false] - Whether MSAA as the default anti-aliasing should be enabled or not. + * @param {Number} [parameters.samples=0] - When `antialias` is `true`, `4` samples are used by default. Set this parameter to any other integer value than 0 to overwrite the default. + * @param {Boolean} [parameters.forceWebGL=false] - If set to `true`, the renderer uses a WebGL 2 backend no matter if WebGPU is supported or not. + * @param {Number} [parameters.outputType=undefined] - Texture type for output to canvas. By default, device's preferred format is used; other formats may incur overhead. + */ constructor( parameters = {} ) { let BackendClass; @@ -45,8 +66,21 @@ class WebGPURenderer extends Renderer { //super( new Proxy( backend, debugHandler ) ); super( backend, parameters ); + /** + * The generic default value is overwritten with the + * standard node library for type mapping. + * + * @type {StandardNodeLibrary} + */ this.library = new StandardNodeLibrary(); + /** + * This flag can be used for type testing. + * + * @type {Boolean} + * @readonly + * @default true + */ this.isWebGPURenderer = true; } diff --git a/src/renderers/webgpu/nodes/BasicNodeLibrary.js b/src/renderers/webgpu/nodes/BasicNodeLibrary.js index a6a9d919190f4f..3ab241fa9ed829 100644 --- a/src/renderers/webgpu/nodes/BasicNodeLibrary.js +++ b/src/renderers/webgpu/nodes/BasicNodeLibrary.js @@ -24,8 +24,18 @@ import { import { LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping } from '../../../constants.js'; import { linearToneMapping, reinhardToneMapping, cineonToneMapping, acesFilmicToneMapping, agxToneMapping, neutralToneMapping } from '../../../nodes/display/ToneMappingFunctions.js'; +/** + * This version of a node library represents a basic version + * just focusing on lights and tone mapping techniques. + * + * @private + * @augments NodeLibrary + */ class BasicNodeLibrary extends NodeLibrary { + /** + * Constructs a new basic node library. + */ constructor() { super(); diff --git a/src/renderers/webgpu/nodes/StandardNodeLibrary.js b/src/renderers/webgpu/nodes/StandardNodeLibrary.js index 9f9f1558707972..b5efe8d3927bd1 100644 --- a/src/renderers/webgpu/nodes/StandardNodeLibrary.js +++ b/src/renderers/webgpu/nodes/StandardNodeLibrary.js @@ -43,8 +43,19 @@ import { import { LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping } from '../../../constants.js'; import { linearToneMapping, reinhardToneMapping, cineonToneMapping, acesFilmicToneMapping, agxToneMapping, neutralToneMapping } from '../../../nodes/display/ToneMappingFunctions.js'; +/** + * This version of a node library represents the standard version + * used in {@link WebGPURenderer}. It maps lights, tone mapping + * techniques and materials to node-based implementations. + * + * @private + * @augments NodeLibrary + */ class StandardNodeLibrary extends NodeLibrary { + /** + * Constructs a new standard node library. + */ constructor() { super(); diff --git a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js index d922563ab1e4f1..84cf3702d40848 100644 --- a/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +++ b/src/renderers/webgpu/nodes/WGSLNodeBuilder.js @@ -178,30 +178,83 @@ if ( ( typeof navigator !== 'undefined' && /Firefox|Deno/g.test( navigator.userA } -// - +/** + * A node builder targeting WGSL. + * + * This module generates WGSL shader code from node materials and also + * generates the respective bindings and vertex buffer definitions. These + * data are later used by the renderer to create render and compute pipelines + * for render objects. + * + * @augments NodeBuilder + */ class WGSLNodeBuilder extends NodeBuilder { + /** + * Constructs a new WGSL node builder renderer. + * + * @param {Object3D} object - The 3D object. + * @param {Renderer} renderer - The renderer. + */ constructor( object, renderer ) { super( object, renderer, new WGSLNodeParser() ); + /** + * A dictionary that holds for each shader stage ('vertex', 'fragment', 'compute') + * another dictionary which manages UBOs per group ('render','frame','object'). + * + * @type {Object>} + */ this.uniformGroups = {}; + /** + * A dictionary that holds for each shader stage a Map of builtins. + * + * @type {Object>} + */ this.builtins = {}; + /** + * A dictionary that holds for each shader stage a Set of directives. + * + * @type {Object>} + */ this.directives = {}; + /** + * A map for managing scope arrays. Only relevant for when using + * {@link module:WorkgroupInfoNode} in context of compute shaders. + * + * @type {Map} + */ this.scopedArrays = new Map(); } + /** + * Checks if the given texture requires a manual conversion to the working color space. + * + * @param {Texture} texture - The texture to check. + * @return {Boolean} Whether the given texture requires a conversion to working color space or not. + */ needsToWorkingColorSpace( texture ) { return texture.isVideoTexture === true && texture.colorSpace !== NoColorSpace; } + /** + * Generates the WGSL snippet for sampled textures. + * + * @private + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ _generateTextureSample( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -228,6 +281,15 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling video textures. + * + * @private + * @param {String} textureProperty - The name of the video texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ _generateVideoSample( textureProperty, uvSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -242,6 +304,18 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling textures with explicit mip level. + * + * @private + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ _generateTextureSampleLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( ( shaderStage === 'fragment' || shaderStage === 'compute' ) && this.isUnfilterable( texture ) === false ) { @@ -260,9 +334,15 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates a wrap function used in context of textures. + * + * @param {Texture} texture - The texture to generate the function for. + * @return {String} The name of the generated function. + */ generateWrapFunction( texture ) { - const functionName = `tsl_coord_${ wrapNames[ texture.wrapS ] }S_${ wrapNames[ texture.wrapT ] }T`; + const functionName = `tsl_coord_${ wrapNames[ texture.wrapS ] }S_${ wrapNames[ texture.wrapT ] }_${texture.isData3DTexture ? '3d' : '2d'}T`; let nodeCode = wgslCodeCache[ functionName ]; @@ -270,7 +350,9 @@ class WGSLNodeBuilder extends NodeBuilder { const includes = []; - let code = `fn ${ functionName }( coord : vec2f ) -> vec2f {\n\n\treturn vec2f(\n`; + // For 3D textures, use vec3f; for texture arrays, keep vec2f since array index is separate + const coordType = texture.isData3DTexture ? 'vec3f' : 'vec2f'; + let code = `fn ${functionName}( coord : ${coordType} ) -> ${coordType} {\n\n\treturn ${coordType}(\n`; const addWrapSnippet = ( wrap, axis ) => { @@ -308,6 +390,13 @@ class WGSLNodeBuilder extends NodeBuilder { addWrapSnippet( texture.wrapT, 'y' ); + if ( texture.isData3DTexture ) { + + code += ',\n'; + addWrapSnippet( texture.wrapR, 'z' ); + + } + code += '\n\t);\n\n}\n'; wgslCodeCache[ functionName ] = nodeCode = new CodeNode( code, includes ); @@ -320,6 +409,16 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates a WGSL variable that holds the texture dimension of the given texture. + * It also returns information about the the number of layers (elements) of an arrayed + * texture as well as the cube face count of cube textures. + * + * @param {Texture} texture - The texture to generate the function for. + * @param {String} textureProperty - The name of the video texture uniform in the shader. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The name of the dimension variable. + */ generateTextureDimension( texture, textureProperty, levelSnippet ) { const textureData = this.getDataFromNode( texture, this.shaderStage, this.globalCache ); @@ -331,29 +430,72 @@ class WGSLNodeBuilder extends NodeBuilder { if ( textureData.dimensionsSnippet[ levelSnippet ] === undefined ) { let textureDimensionsParams; + let dimensionType; const { primarySamples } = this.renderer.backend.utils.getTextureSampleData( texture ); + const isMultisampled = primarySamples > 1; - if ( primarySamples > 1 ) { + if ( texture.isData3DTexture ) { + + dimensionType = 'vec3'; + + } else { + + // Regular 2D textures, depth textures, etc. + dimensionType = 'vec2'; + + } + + // Build parameters string based on texture type and multisampling + if ( isMultisampled || texture.isVideoTexture || texture.isStorageTexture ) { textureDimensionsParams = textureProperty; } else { - textureDimensionsParams = `${ textureProperty }, u32( ${ levelSnippet } )`; + textureDimensionsParams = `${textureProperty}${levelSnippet ? `, u32( ${ levelSnippet } )` : ''}`; } - textureDimensionNode = new VarNode( new ExpressionNode( `textureDimensions( ${ textureDimensionsParams } )`, 'uvec2' ) ); + textureDimensionNode = new VarNode( new ExpressionNode( `textureDimensions( ${ textureDimensionsParams } )`, dimensionType ) ); textureData.dimensionsSnippet[ levelSnippet ] = textureDimensionNode; + if ( texture.isDataArrayTexture || texture.isData3DTexture ) { + + textureData.arrayLayerCount = new VarNode( + new ExpressionNode( + `textureNumLayers(${textureProperty})`, + 'u32' + ) + ); + + } + + // For cube textures, we know it's always 6 faces + if ( texture.isTextureCube ) { + + textureData.cubeFaceCount = new VarNode( + new ExpressionNode( '6u', 'u32' ) + ); + + } + } return textureDimensionNode.build( this ); } + /** + * Generates the WGSL snippet for a manual filtered texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The WGSL snippet. + */ generateFilteredTexture( texture, textureProperty, uvSnippet, levelSnippet = '0u' ) { this._include( 'biquadraticTexture' ); @@ -365,17 +507,39 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for a texture lookup with explicit level-of-detail. + * Since it's a lookup, no sampling or filtering is applied. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The WGSL snippet. + */ generateTextureLod( texture, textureProperty, uvSnippet, depthSnippet, levelSnippet = '0u' ) { const wrapFunction = this.generateWrapFunction( texture ); const textureDimension = this.generateTextureDimension( texture, textureProperty, levelSnippet ); - const coordSnippet = `vec2u( ${ wrapFunction }( ${ uvSnippet } ) * vec2f( ${ textureDimension } ) )`; + const vecType = texture.isData3DTexture ? 'vec3' : 'vec2'; + const coordSnippet = `${vecType}(${wrapFunction}(${uvSnippet}) * ${vecType}(${textureDimension}))`; return this.generateTextureLoad( texture, textureProperty, coordSnippet, depthSnippet, levelSnippet ); } + /** + * Generates the WGSL snippet that reads a single texel from a texture without sampling or filtering. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [levelSnippet='0u'] - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @return {String} The WGSL snippet. + */ generateTextureLoad( texture, textureProperty, uvIndexSnippet, depthSnippet, levelSnippet = '0u' ) { if ( texture.isVideoTexture === true || texture.isStorageTexture === true ) { @@ -394,18 +558,39 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet that writes a single texel to a texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvIndexSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} valueSnippet - A WGSL snippet that represent the new texel value. + * @return {String} The WGSL snippet. + */ generateTextureStore( texture, textureProperty, uvIndexSnippet, valueSnippet ) { return `textureStore( ${ textureProperty }, ${ uvIndexSnippet }, ${ valueSnippet } )`; } + /** + * Returns `true` if the sampled values of the given texture should be compared against a reference value. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the sampled values of the given texture should be compared against a reference value or not. + */ isSampleCompare( texture ) { return texture.isDepthTexture === true && texture.compareFunction !== null; } + /** + * Returns `true` if the given texture is unfilterable. + * + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the given texture is unfilterable or not. + */ isUnfilterable( texture ) { return this.getComponentTypeFromTexture( texture ) !== 'float' || @@ -415,6 +600,16 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for sampling/loading the given texture. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTexture( texture, textureProperty, uvSnippet, depthSnippet, shaderStage = this.shaderStage ) { let snippet = null; @@ -437,6 +632,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for sampling/loading the given texture using explicit gradients. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {Array} gradSnippet - An array holding both gradient WGSL snippets. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -452,6 +658,18 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet for sampling a depth texture and comparing the sampled depth values + * against a reference value. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} compareSnippet - A WGSL snippet that represents the reference value. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -466,6 +684,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling textures with explicit mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} levelSnippet - A WGSL snippet that represents the mip level, with level 0 containing a full size version of the texture. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet, shaderStage = this.shaderStage ) { let snippet = null; @@ -484,6 +713,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Generates the WGSL snippet when sampling textures with a bias to the mip level. + * + * @param {Texture} texture - The texture. + * @param {String} textureProperty - The name of the texture uniform in the shader. + * @param {String} uvSnippet - A WGSL snippet that represents texture coordinates used for sampling. + * @param {String} biasSnippet - A WGSL snippet that represents the bias to apply to the mip level before sampling. + * @param {String?} depthSnippet - A WGSL snippet that represents 0-based texture array index to sample. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The WGSL snippet. + */ generateTextureBias( texture, textureProperty, uvSnippet, biasSnippet, depthSnippet, shaderStage = this.shaderStage ) { if ( shaderStage === 'fragment' ) { @@ -498,6 +738,13 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns a WGSL snippet that represents the property name of the given node. + * + * @param {Node} node - The node. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The property name. + */ getPropertyName( node, shaderStage = this.shaderStage ) { if ( node.isNodeVarying === true && node.needsInterpolation === true ) { @@ -533,18 +780,36 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns the output struct name. + * + * @return {String} The name of the output struct. + */ getOutputStructName() { return 'output'; } + /** + * Returns uniforms group count for the given shader stage. + * + * @private + * @param {String} shaderStage - The shader stage. + * @return {Number} The uniforms group count for the given shader stage. + */ _getUniformGroupCount( shaderStage ) { return Object.keys( this.uniforms[ shaderStage ] ).length; } + /** + * Returns the native shader operator name for a given generic name. + * + * @param {String} op - The operator name to resolve. + * @return {String} The resolved operator name. + */ getFunctionOperator( op ) { const fnOp = wgslFnOpLib[ op ]; @@ -561,6 +826,13 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns the node access for the given node and shader stage. + * + * @param {StorageTextureNode|StorageBufferNode} node - The storage node. + * @param {String} shaderStage - The shader stage. + * @return {String} The node access. + */ getNodeAccess( node, shaderStage ) { if ( shaderStage !== 'compute' ) @@ -570,12 +842,32 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns A WGSL snippet representing the storage access. + * + * @param {StorageTextureNode|StorageBufferNode} node - The storage node. + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet representing the storage access. + */ getStorageAccess( node, shaderStage ) { return accessNames[ this.getNodeAccess( node, shaderStage ) ]; } + /** + * This method is one of the more important ones since it's responsible + * for generating a matching binding instance for the given uniform node. + * + * These bindings are later used in the renderer to create bind groups + * and layouts. + * + * @param {UniformNode} node - The uniform node. + * @param {String} type - The node data type. + * @param {String} shaderStage - The shader stage. + * @param {String?} [name=null] - An optional uniform name. + * @return {NodeUniform} The node uniform object. + */ getUniformFromNode( node, type, shaderStage, name = null ) { const uniformNode = super.getUniformFromNode( node, type, shaderStage, name ); @@ -672,6 +964,17 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * This method should be used whenever builtins are required in nodes. + * The internal builtins data structure will make sure builtins are + * defined in the WGSL source. + * + * @param {String} name - The builtin name. + * @param {String} property - The property name. + * @param {String} type - The node data type. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} The property name. + */ getBuiltin( name, property, type, shaderStage = this.shaderStage ) { const map = this.builtins[ shaderStage ] || ( this.builtins[ shaderStage ] = new Map() ); @@ -690,12 +993,24 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Returns `true` if the given builtin is defined in the given shader stage. + * + * @param {String} name - The builtin name. + * @param {String} [shaderStage=this.shaderStage] - The shader stage this code snippet is generated for. + * @return {String} Whether the given builtin is defined in the given shader stage or not. + */ hasBuiltin( name, shaderStage = this.shaderStage ) { return ( this.builtins[ shaderStage ] !== undefined && this.builtins[ shaderStage ].has( name ) ); } + /** + * Returns the vertex index builtin. + * + * @return {String} The vertex index. + */ getVertexIndex() { if ( this.shaderStage === 'vertex' ) { @@ -708,6 +1023,12 @@ class WGSLNodeBuilder extends NodeBuilder { } + /** + * Builds the given shader node. + * + * @param {ShaderNodeInternal} shaderNode - The shader node. + * @return {String} The WGSL function code. + */ buildFunctionCode( shaderNode ) { const layout = shaderNode.layout; @@ -742,6 +1063,11 @@ ${ flowData.code } } + /** + * Returns the instance index builtin. + * + * @return {String} The instance index. + */ getInstanceIndex() { if ( this.shaderStage === 'vertex' ) { @@ -754,12 +1080,22 @@ ${ flowData.code } } + /** + * Returns the invocation local index builtin. + * + * @return {String} The invocation local index. + */ getInvocationLocalIndex() { return this.getBuiltin( 'local_invocation_index', 'invocationLocalIndex', 'u32', 'attribute' ); } + /** + * Returns the subgroup size builtin. + * + * @return {String} The subgroup size. + */ getSubgroupSize() { this.enableSubGroups(); @@ -768,6 +1104,11 @@ ${ flowData.code } } + /** + * Returns the invocation subgroup index builtin. + * + * @return {String} The invocation subgroup index. + */ getInvocationSubgroupIndex() { this.enableSubGroups(); @@ -776,6 +1117,11 @@ ${ flowData.code } } + /** + * Returns the subgroup index builtin. + * + * @return {String} The subgroup index. + */ getSubgroupIndex() { this.enableSubGroups(); @@ -784,42 +1130,78 @@ ${ flowData.code } } + /** + * Overwritten as a NOP since this method is intended for the WebGL 2 backend. + * + * @return {null} Null. + */ getDrawIndex() { return null; } + /** + * Returns the front facing builtin. + * + * @return {String} The front facing builtin. + */ getFrontFacing() { return this.getBuiltin( 'front_facing', 'isFront', 'bool' ); } + /** + * Returns the frag coord builtin. + * + * @return {String} The frag coord builtin. + */ getFragCoord() { return this.getBuiltin( 'position', 'fragCoord', 'vec4' ) + '.xy'; } + /** + * Returns the frag depth builtin. + * + * @return {String} The frag depth builtin. + */ getFragDepth() { return 'output.' + this.getBuiltin( 'frag_depth', 'depth', 'f32', 'output' ); } + /** + * Returns the clip distances builtin. + * + * @return {String} The clip distances builtin. + */ getClipDistance() { return 'varyings.hw_clip_distances'; } + /** + * Whether to flip texture data along its vertical axis or not. + * + * @return {Boolean} Returns always `false` in context of WGSL. + */ isFlipY() { return false; } + /** + * Enables the given directive for the given shader stage. + * + * @param {String} name - The directive name. + * @param {String} [shaderStage=this.shaderStage] - The shader stage to enable the directive for. + */ enableDirective( name, shaderStage = this.shaderStage ) { const stage = this.directives[ shaderStage ] || ( this.directives[ shaderStage ] = new Set() ); @@ -827,6 +1209,12 @@ ${ flowData.code } } + /** + * Returns the directives of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} A WGSL snippet that enables the directives of the given stage. + */ getDirectives( shaderStage ) { const snippets = []; @@ -846,36 +1234,56 @@ ${ flowData.code } } + /** + * Enables the 'subgroups' directive. + */ enableSubGroups() { this.enableDirective( 'subgroups' ); } + /** + * Enables the 'subgroups-f16' directive. + */ enableSubgroupsF16() { this.enableDirective( 'subgroups-f16' ); } + /** + * Enables the 'clip_distances' directive. + */ enableClipDistances() { this.enableDirective( 'clip_distances' ); } + /** + * Enables the 'f16' directive. + */ enableShaderF16() { this.enableDirective( 'f16' ); } + /** + * Enables the 'dual_source_blending' directive. + */ enableDualSourceBlending() { this.enableDirective( 'dual_source_blending' ); } + /** + * Enables hardware clipping. + * + * @param {String} planeCount - The clipping plane count. + */ enableHardwareClipping( planeCount ) { this.enableClipDistances(); @@ -883,6 +1291,12 @@ ${ flowData.code } } + /** + * Returns the builtins of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} A WGSL snippet that represents the builtins of the given stage. + */ getBuiltins( shaderStage ) { const snippets = []; @@ -902,6 +1316,17 @@ ${ flowData.code } } + /** + * This method should be used when a new scoped buffer is used in context of + * compute shaders. It adds the array to the internal data structure which is + * later used to generate the respective WGSL. + * + * @param {String} name - The array name. + * @param {String} scope - The scope. + * @param {String} bufferType - The buffer type. + * @param {String} bufferCount - The buffer count. + * @return {String} The array name. + */ getScopedArray( name, scope, bufferType, bufferCount ) { if ( this.scopedArrays.has( name ) === false ) { @@ -919,6 +1344,13 @@ ${ flowData.code } } + /** + * Returns the scoped arrays of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String|undefined} The WGSL snippet that defines the scoped arrays. + * Returns `undefined` when used in the vertex or fragment stage. + */ getScopedArrays( shaderStage ) { if ( shaderStage !== 'compute' ) { @@ -941,13 +1373,19 @@ ${ flowData.code } } + /** + * Returns the shader attributes of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the shader attributes. + */ getAttributes( shaderStage ) { const snippets = []; if ( shaderStage === 'compute' ) { - this.getBuiltin( 'global_invocation_id', 'id', 'vec3', 'attribute' ); + this.getBuiltin( 'global_invocation_id', 'globalId', 'vec3', 'attribute' ); this.getBuiltin( 'workgroup_id', 'workgroupId', 'vec3', 'attribute' ); this.getBuiltin( 'local_invocation_id', 'localId', 'vec3', 'attribute' ); this.getBuiltin( 'num_workgroups', 'numWorkgroups', 'vec3', 'attribute' ); @@ -985,6 +1423,12 @@ ${ flowData.code } } + /** + * Returns the members of the given struct type node as a WGSL string. + * + * @param {StructTypeNode} struct - The struct type node. + * @return {String} The WGSL snippet that defines the struct members. + */ getStructMembers( struct ) { const snippets = []; @@ -1005,6 +1449,12 @@ ${ flowData.code } } + /** + * Returns the structs of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the structs. + */ getStructs( shaderStage ) { const snippets = []; @@ -1030,12 +1480,25 @@ ${ flowData.code } } + /** + * Returns a WGSL string representing a variable. + * + * @param {String} type - The variable's type. + * @param {String} name - The variable's name. + * @return {String} The WGSL snippet that defines a variable. + */ getVar( type, name ) { return `var ${ name } : ${ this.getType( type ) }`; } + /** + * Returns the variables of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the variables. + */ getVars( shaderStage ) { const snippets = []; @@ -1055,6 +1518,12 @@ ${ flowData.code } } + /** + * Returns the varyings of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the varyings. + */ getVaryings( shaderStage ) { const snippets = []; @@ -1107,6 +1576,12 @@ ${ flowData.code } } + /** + * Returns the uniforms of the given shader stage as a WGSL string. + * + * @param {String} shaderStage - The shader stage. + * @return {String} The WGSL snippet that defines the uniforms. + */ getUniforms( shaderStage ) { const uniforms = this.uniforms[ shaderStage ]; @@ -1234,6 +1709,9 @@ ${ flowData.code } } + /** + * Controls the code build of the shader stages. + */ buildCode() { const shadersData = this.material !== null ? { fragment: {}, vertex: {} } : { compute: {} }; @@ -1272,7 +1750,7 @@ ${ flowData.code } if ( flow.length > 0 ) flow += '\n'; - flow += `\t// flow -> ${ slotName }\n\t`; + flow += `\t// flow -> ${ slotName }\n`; } @@ -1334,6 +1812,13 @@ ${ flowData.code } } + /** + * Returns the native shader method name for a given generic name. + * + * @param {String} method - The method name to resolve. + * @param {String} [output=null] - An optional output. + * @return {String} The resolved WGSL method name. + */ getMethod( method, output = null ) { let wgslMethod; @@ -1354,12 +1839,24 @@ ${ flowData.code } } + /** + * Returns the WGSL type of the given node data type. + * + * @param {String} type - The node data type. + * @return {String} The WGSL type. + */ getType( type ) { return wgslTypeLib[ type ] || type; } + /** + * Whether the requested feature is available or not. + * + * @param {String} name - The requested feature. + * @return {Boolean} Whether the requested feature is supported or not. + */ isAvailable( name ) { let result = supports[ name ]; @@ -1384,6 +1881,13 @@ ${ flowData.code } } + /** + * Returns the native shader method name for a given generic name. + * + * @private + * @param {String} method - The method name to resolve. + * @return {String} The resolved WGSL method name. + */ _getWGSLMethod( method ) { if ( wgslPolyfill[ method ] !== undefined ) { @@ -1396,6 +1900,14 @@ ${ flowData.code } } + /** + * Includes the given method name into the current + * function node. + * + * @private + * @param {String} name - The method name to include. + * @return {CodeNode} The respective code node. + */ _include( name ) { const codeNode = wgslPolyfill[ name ]; @@ -1411,6 +1923,13 @@ ${ flowData.code } } + /** + * Returns a WGSL vertex shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getWGSLVertexCode( shaderData ) { return `${ this.getSignature() } @@ -1443,6 +1962,13 @@ fn main( ${shaderData.attributes} ) -> VaryingsStruct { } + /** + * Returns a WGSL fragment shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @return {String} The vertex shader. + */ _getWGSLFragmentCode( shaderData ) { return `${ this.getSignature() } @@ -1472,6 +1998,14 @@ fn main( ${shaderData.varyings} ) -> ${shaderData.returnType} { } + /** + * Returns a WGSL compute shader based on the given shader data. + * + * @private + * @param {Object} shaderData - The shader data. + * @param {String} workgroupSize - The workgroup size. + * @return {String} The vertex shader. + */ _getWGSLComputeCode( shaderData, workgroupSize ) { return `${ this.getSignature() } @@ -1494,7 +2028,7 @@ ${shaderData.codes} fn main( ${shaderData.attributes} ) { // system - instanceIndex = id.x + id.y * numWorkgroups.x * u32(${workgroupSize}) + id.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize}); + instanceIndex = globalId.x + globalId.y * numWorkgroups.x * u32(${workgroupSize}) + globalId.z * numWorkgroups.x * numWorkgroups.y * u32(${workgroupSize}); // vars ${shaderData.vars} @@ -1507,6 +2041,14 @@ fn main( ${shaderData.attributes} ) { } + /** + * Returns a WGSL struct based on the given name and variables. + * + * @private + * @param {String} name - The struct name. + * @param {String} vars - The struct variables. + * @return {String} The WGSL snippet representing a struct. + */ _getWGSLStruct( name, vars ) { return ` @@ -1516,6 +2058,17 @@ ${vars} } + /** + * Returns a WGSL struct binding. + * + * @private + * @param {String} name - The struct name. + * @param {String} vars - The struct variables. + * @param {String} access - The access. + * @param {Number} [binding=0] - The binding index. + * @param {Number} [group=0] - The group index. + * @return {String} The WGSL snippet representing a struct binding. + */ _getWGSLStructBinding( name, vars, access, binding = 0, group = 0 ) { const structName = name + 'Struct'; diff --git a/src/renderers/webgpu/utils/WebGPUAttributeUtils.js b/src/renderers/webgpu/utils/WebGPUAttributeUtils.js index c65f2a96bc2ce7..f98f4e9a3b9872 100644 --- a/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +++ b/src/renderers/webgpu/utils/WebGPUAttributeUtils.js @@ -24,14 +24,35 @@ const typeArraysToVertexFormatPrefixForItemSize1 = new Map( [ [ Float32Array, 'float32' ] ] ); +/** + * A WebGPU backend utility module for managing shader attributes. + * + * @private + */ class WebGPUAttributeUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; } + /** + * Creates the GPU buffer for the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + * @param {GPUBufferUsage} usage - A flag that indicates how the buffer may be used after its creation. + */ createAttribute( attribute, usage ) { const bufferAttribute = this._getBufferAttribute( attribute ); @@ -48,16 +69,27 @@ class WebGPUAttributeUtils { let array = bufferAttribute.array; // patch for INT16 and UINT16 - if ( attribute.normalized === false && ( array.constructor === Int16Array || array.constructor === Uint16Array ) ) { + if ( attribute.normalized === false ) { - const tempArray = new Uint32Array( array.length ); - for ( let i = 0; i < array.length; i ++ ) { + if ( array.constructor === Int16Array ) { - tempArray[ i ] = array[ i ]; + array = new Int32Array( array ); - } + } else if ( array.constructor === Uint16Array ) { + + array = new Uint32Array( array ); + + if ( usage & GPUBufferUsage.INDEX ) { + + for ( let i = 0; i < array.length; i ++ ) { - array = tempArray; + if ( array[ i ] === 0xffff ) array[ i ] = 0xffffffff; // use correct primitive restart index + + } + + } + + } } @@ -98,6 +130,11 @@ class WebGPUAttributeUtils { } + /** + * Updates the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ updateAttribute( attribute ) { const bufferAttribute = this._getBufferAttribute( attribute ); @@ -149,6 +186,13 @@ class WebGPUAttributeUtils { } + /** + * This method creates the vertex buffer layout data which are + * require when creating a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @return {Array} An array holding objects which describe the vertex buffer layout. + */ createShaderVertexBuffers( renderObject ) { const attributes = renderObject.getAttributes(); @@ -210,6 +254,11 @@ class WebGPUAttributeUtils { } + /** + * Destroys the GPU buffer of the given buffer attribute. + * + * @param {BufferAttribute} attribute - The buffer attribute. + */ destroyAttribute( attribute ) { const backend = this.backend; @@ -221,24 +270,32 @@ class WebGPUAttributeUtils { } + /** + * This method performs a readback operation by moving buffer data from + * a storage buffer attribute from the GPU to the CPU. + * + * @async + * @param {StorageBufferAttribute} attribute - The storage buffer attribute. + * @return {Promise} A promise that resolves with the buffer data when the data are ready. + */ 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, + label: `${ attribute.name }_readback`, size, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ } ); - - const cmdEncoder = device.createCommandEncoder( {} ); + const cmdEncoder = device.createCommandEncoder( { + label: `readback_encoder_${ attribute.name }` + } ); cmdEncoder.copyBufferToBuffer( bufferGPU, @@ -248,8 +305,6 @@ class WebGPUAttributeUtils { size ); - readBufferGPU.unmap(); - const gpuCommands = cmdEncoder.finish(); device.queue.submit( [ gpuCommands ] ); @@ -257,10 +312,21 @@ class WebGPUAttributeUtils { const arrayBuffer = readBufferGPU.getMappedRange(); - return arrayBuffer; + const dstBuffer = new attribute.array.constructor( arrayBuffer.slice( 0 ) ); + + readBufferGPU.unmap(); + + return dstBuffer.buffer; } + /** + * Returns the vertex format of the given buffer attribute. + * + * @private + * @param {BufferAttribute} geometryAttribute - The buffer attribute. + * @return {String} The vertex format (e.g. 'float32x3'). + */ _getVertexFormat( geometryAttribute ) { const { itemSize, normalized } = geometryAttribute; @@ -306,12 +372,27 @@ class WebGPUAttributeUtils { } + /** + * Returns `true` if the given array is a typed array. + * + * @private + * @param {Any} array - The array. + * @return {Boolean} Whether the given array is a typed array or not. + */ _isTypedArray( array ) { return ArrayBuffer.isView( array ) && ! ( array instanceof DataView ); } + /** + * Utility method for handling interleaved buffer attributes correctly. + * To process them, their `InterleavedBuffer` is returned. + * + * @private + * @param {BufferAttribute} attribute - The attribute. + * @return {BufferAttribute|InterleavedBuffer} + */ _getBufferAttribute( attribute ) { if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; diff --git a/src/renderers/webgpu/utils/WebGPUBindingUtils.js b/src/renderers/webgpu/utils/WebGPUBindingUtils.js index ba349d46592520..73e22f249f1c5a 100644 --- a/src/renderers/webgpu/utils/WebGPUBindingUtils.js +++ b/src/renderers/webgpu/utils/WebGPUBindingUtils.js @@ -5,15 +5,47 @@ import { import { FloatType, IntType, UnsignedIntType } from '../../../constants.js'; import { NodeAccess } from '../../../nodes/core/constants.js'; +/** + * A WebGPU backend utility module for managing bindings. + * + * When reading the documentation it's helpful to keep in mind that + * all class definitions starting with 'GPU*' are modules from the + * WebGPU API. So for example `BindGroup` is a class from the engine + * whereas `GPUBindGroup` is a class from WebGPU. + * + * @private + */ class WebGPUBindingUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; + + /** + * A cache for managing bind group layouts. + * + * @type {WeakMap,GPUBindGroupLayout>} + */ this.bindGroupLayoutCache = new WeakMap(); } + /** + * Creates a GPU bind group layout for the given bind group. + * + * @param {BindGroup} bindGroup - The bind group. + * @return {GPUBindGroupLayout} The GPU bind group layout. + */ createBindingsLayout( bindGroup ) { const backend = this.backend; @@ -183,6 +215,14 @@ class WebGPUBindingUtils { } + /** + * Creates bindings from the given bind group definition. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {Array} bindings - Array of bind groups. + * @param {Number} cacheIndex - The cache index. + * @param {Number} version - The version. + */ createBindings( bindGroup, bindings, cacheIndex, version = 0 ) { const { backend, bindGroupLayoutCache } = this; @@ -236,6 +276,11 @@ class WebGPUBindingUtils { } + /** + * Updates a buffer binding. + * + * @param {Buffer} binding - The buffer binding to update. + */ updateBinding( binding ) { const backend = this.backend; @@ -248,6 +293,13 @@ class WebGPUBindingUtils { } + /** + * Creates a GPU bind group for the given bind group and GPU layout. + * + * @param {BindGroup} bindGroup - The bind group. + * @param {GPUBindGroupLayout} layoutGPU - The GPU bind group layout. + * @return {GPUBindGroup} The GPU bind group. + */ createBindGroup( bindGroup, layoutGPU ) { const backend = this.backend; diff --git a/src/renderers/webgpu/utils/WebGPUPipelineUtils.js b/src/renderers/webgpu/utils/WebGPUPipelineUtils.js index c0a20faee05f91..5292bed51d8b1e 100644 --- a/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +++ b/src/renderers/webgpu/utils/WebGPUPipelineUtils.js @@ -15,20 +15,48 @@ import { NeverStencilFunc, AlwaysStencilFunc, LessStencilFunc, LessEqualStencilFunc, EqualStencilFunc, GreaterEqualStencilFunc, GreaterStencilFunc, NotEqualStencilFunc } from '../../../constants.js'; +/** + * A WebGPU backend utility module for managing pipelines. + * + * @private + */ class WebGPUPipelineUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; } - _getSampleCount( renderObjectContext ) { + /** + * Returns the sample count derived from the given render context. + * + * @private + * @param {RenderContext} renderContext - The render context. + * @return {Number} The sample count. + */ + _getSampleCount( renderContext ) { - return this.backend.utils.getSampleCountRenderContext( renderObjectContext ); + return this.backend.utils.getSampleCountRenderContext( renderContext ); } + /** + * Creates a render pipeline for the given render object. + * + * @param {RenderObject} renderObject - The render object. + * @param {Array} promises - An array of compilation promises which are used in `compileAsync()`. + */ createRenderPipeline( renderObject, promises ) { const { object, material, geometry, pipeline } = renderObject; @@ -188,6 +216,12 @@ class WebGPUPipelineUtils { } + /** + * Creates GPU render bundle encoder for the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {GPURenderBundleEncoder} The GPU render bundle encoder. + */ createBundleEncoder( renderContext ) { const backend = this.backend; @@ -208,6 +242,12 @@ class WebGPUPipelineUtils { } + /** + * Creates a compute pipeline for the given compute node. + * + * @param {ComputePipeline} pipeline - The compute pipeline. + * @param {Array} bindings - The bindings. + */ createComputePipeline( pipeline, bindings ) { const backend = this.backend; @@ -238,6 +278,14 @@ class WebGPUPipelineUtils { } + /** + * Returns the blending state as a descriptor object required + * for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {Object} The blending state. + */ _getBlending( material ) { let color, alpha; @@ -345,7 +393,13 @@ class WebGPUPipelineUtils { } } - + /** + * Returns the GPU blend factor which is required for the pipeline creation. + * + * @private + * @param {Number} blend - The blend factor as a three.js constant. + * @return {String} The GPU blend factor. + */ _getBlendFactor( blend ) { let blendFactor; @@ -413,6 +467,13 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU stencil compare function which is required for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {String} The GPU stencil compare function. + */ _getStencilCompare( material ) { let stencilCompare; @@ -462,6 +523,13 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU stencil operation which is required for the pipeline creation. + * + * @private + * @param {Number} op - A three.js constant defining the stencil operation. + * @return {String} The GPU stencil operation. + */ _getStencilOperation( op ) { let stencilOperation; @@ -509,6 +577,13 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU blend operation which is required for the pipeline creation. + * + * @private + * @param {Number} blendEquation - A three.js constant defining the blend equation. + * @return {String} The GPU blend operation. + */ _getBlendOperation( blendEquation ) { let blendOperation; @@ -544,6 +619,16 @@ class WebGPUPipelineUtils { } + /** + * Returns the primitive state as a descriptor object required + * for the pipeline creation. + * + * @private + * @param {Object3D} object - The 3D object. + * @param {BufferGeometry} geometry - The geometry. + * @param {Material} material - The material. + * @return {Object} The primitive state. + */ _getPrimitiveState( object, geometry, material ) { const descriptor = {}; @@ -584,12 +669,26 @@ class WebGPUPipelineUtils { } + /** + * Returns the GPU color write mask which is required for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {String} The GPU color write mask. + */ _getColorWriteMask( material ) { return ( material.colorWrite === true ) ? GPUColorWriteFlags.All : GPUColorWriteFlags.None; } + /** + * Returns the GPU depth compare function which is required for the pipeline creation. + * + * @private + * @param {Material} material - The material. + * @return {String} The GPU depth compare function. + */ _getDepthCompare( material ) { let depthCompare; diff --git a/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js b/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js index 913854e7a84423..33e63ca963c527 100644 --- a/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +++ b/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js @@ -1,12 +1,27 @@ import DataMap from '../../common/DataMap.js'; import { GPUTextureViewDimension, GPUIndexFormat, GPUFilterMode, GPUPrimitiveTopology, GPULoadOp, GPUStoreOp } from './WebGPUConstants.js'; +/** + * A WebGPU backend utility module used by {@link WebGPUTextureUtils}. + * + * @private + */ class WebGPUTexturePassUtils extends DataMap { + /** + * Constructs a new utility object. + * + * @param {GPUDevice} device - The WebGPU device. + */ constructor( device ) { super(); + /** + * The WebGPU device. + * + * @type {GPUDevice} + */ this.device = device; const mipmapVertexSource = ` @@ -71,23 +86,62 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } `; + + /** + * The mipmap GPU sampler. + * + * @type {GPUSampler} + */ this.mipmapSampler = device.createSampler( { minFilter: GPUFilterMode.Linear } ); + + /** + * The flipY GPU sampler. + * + * @type {GPUSampler} + */ this.flipYSampler = device.createSampler( { minFilter: GPUFilterMode.Nearest } ); //@TODO?: Consider using textureLoad() - // We'll need a new pipeline for every texture format used. + /** + * A cache for GPU render pipelines used for copy/transfer passes. + * Every texture format requires a unique pipeline. + * + * @type {Object} + */ this.transferPipelines = {}; + + /** + * A cache for GPU render pipelines used for flipY passes. + * Every texture format requires a unique pipeline. + * + * @type {Object} + */ this.flipYPipelines = {}; + /** + * The mipmap vertex shader module. + * + * @type {GPUShaderModule} + */ this.mipmapVertexShaderModule = device.createShaderModule( { label: 'mipmapVertex', code: mipmapVertexSource } ); + /** + * The mipmap fragment shader module. + * + * @type {GPUShaderModule} + */ this.mipmapFragmentShaderModule = device.createShaderModule( { label: 'mipmapFragment', code: mipmapFragmentSource } ); + /** + * The flipY fragment shader module. + * + * @type {GPUShaderModule} + */ this.flipYFragmentShaderModule = device.createShaderModule( { label: 'flipYFragment', code: flipYFragmentSource @@ -95,6 +149,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Returns a render pipeline for the internal copy render pass. The pass + * requires a unique render pipeline for each texture format. + * + * @param {String} format - The GPU texture format + * @return {GPURenderPipeline} The GPU render pipeline. + */ getTransferPipeline( format ) { let pipeline = this.transferPipelines[ format ]; @@ -127,6 +188,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Returns a render pipeline for the flipY render pass. The pass + * requires a unique render pipeline for each texture format. + * + * @param {String} format - The GPU texture format + * @return {GPURenderPipeline} The GPU render pipeline. + */ getFlipYPipeline( format ) { let pipeline = this.flipYPipelines[ format ]; @@ -159,6 +227,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Flip the contents of the given GPU texture along its vertical axis. + * + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureGPUDescriptor - The texture descriptor. + * @param {Number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. + */ flipY( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) { const format = textureGPUDescriptor.format; @@ -229,6 +304,13 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Generates mipmaps for the given GPU texture. + * + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureGPUDescriptor - The texture descriptor. + * @param {Number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. + */ generateMipmaps( textureGPU, textureGPUDescriptor, baseArrayLayer = 0 ) { const textureData = this.get( textureGPU ); @@ -254,6 +336,15 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Since multiple copy render passes are required to generate mipmaps, the passes + * are managed as render bundles to improve performance. + * + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureGPUDescriptor - The texture descriptor. + * @param {Number} baseArrayLayer - The index of the first array layer accessible to the texture view. + * @return {Array} An array of render bundles. + */ _mipmapCreateBundles( textureGPU, textureGPUDescriptor, baseArrayLayer ) { const pipeline = this.getTransferPipeline( textureGPUDescriptor.format ); @@ -319,6 +410,12 @@ fn main( @location( 0 ) vTex : vec2 ) -> @location( 0 ) vec4 { } + /** + * Executes the render bundles. + * + * @param {GPUCommandEncoder} commandEncoder - The GPU command encoder. + * @param {Array} passes - An array of render bundles. + */ _mipmapRunBundles( commandEncoder, passes ) { const levels = passes.length; diff --git a/src/renderers/webgpu/utils/WebGPUTextureUtils.js b/src/renderers/webgpu/utils/WebGPUTextureUtils.js index 476c86784b8338..694e54aa6a59d4 100644 --- a/src/renderers/webgpu/utils/WebGPUTextureUtils.js +++ b/src/renderers/webgpu/utils/WebGPUTextureUtils.js @@ -32,25 +32,82 @@ const _compareToWebGPU = { const _flipMap = [ 0, 1, 3, 2, 4, 5 ]; +/** + * A WebGPU backend utility module for managing textures. + * + * @private + */ class WebGPUTextureUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; + /** + * A reference to the pass utils. + * + * @type {WebGPUTexturePassUtils?} + * @default null + */ this._passUtils = null; + /** + * A dictionary for managing default textures. The key + * is the texture format, the value the texture object. + * + * @type {Object} + */ this.defaultTexture = {}; + + /** + * A dictionary for managing default cube textures. The key + * is the texture format, the value the texture object. + * + * @type {Object} + */ this.defaultCubeTexture = {}; + + /** + * A default video frame. + * + * @type {VideoFrame?} + * @default null + */ this.defaultVideoFrame = null; + /** + * Represents the color attachment of the default framebuffer. + * + * @type {GPUTexture?} + * @default null + */ this.colorBuffer = null; + /** + * Represents the depth attachment of the default framebuffer. + * + * @type {DepthTexture} + */ this.depthTexture = new DepthTexture(); this.depthTexture.name = 'depthBuffer'; } + /** + * Creates a GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to create the sampler for. + */ createSampler( texture ) { const backend = this.backend; @@ -86,6 +143,12 @@ class WebGPUTextureUtils { } + /** + * Creates a default texture for the given texture that can be used + * as a placeholder until the actual texture is ready for usage. + * + * @param {Texture} texture - The texture to create a default texture for. + */ createDefaultTexture( texture ) { let textureGPU; @@ -110,6 +173,13 @@ class WebGPUTextureUtils { } + /** + * Defines a texture on the GPU for the given texture object. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + * @return {undefined} + */ createTexture( texture, options = {} ) { const backend = this.backend; @@ -221,6 +291,11 @@ class WebGPUTextureUtils { } + /** + * Destroys the GPU data for the given texture object. + * + * @param {Texture} texture - The texture. + */ destroyTexture( texture ) { const backend = this.backend; @@ -234,6 +309,11 @@ class WebGPUTextureUtils { } + /** + * Destroys the GPU sampler for the given texture. + * + * @param {Texture} texture - The texture to destroy the sampler for. + */ destroySampler( texture ) { const backend = this.backend; @@ -243,6 +323,11 @@ class WebGPUTextureUtils { } + /** + * Generates mipmaps for the given texture. + * + * @param {Texture} texture - The texture. + */ generateMipmaps( texture ) { const textureData = this.backend.get( texture ); @@ -269,6 +354,12 @@ class WebGPUTextureUtils { } + /** + * Returns the color buffer representing the color + * attachment of the default framebuffer. + * + * @return {GPUTexture} The color buffer. + */ getColorBuffer() { if ( this.colorBuffer ) this.colorBuffer.destroy(); @@ -292,6 +383,14 @@ class WebGPUTextureUtils { } + /** + * Returns the depth buffer representing the depth + * attachment of the default framebuffer. + * + * @param {Boolean} [depth=true] - Whether depth is enabled or not. + * @param {Boolean} [stencil=false] - Whether stencil is enabled or not. + * @return {GPUTexture} The depth buffer. + */ getDepthBuffer( depth = true, stencil = false ) { const backend = this.backend; @@ -338,6 +437,12 @@ class WebGPUTextureUtils { } + /** + * Uploads the updated texture data to the GPU. + * + * @param {Texture} texture - The texture. + * @param {Object} [options={}] - Optional configuration parameter. + */ updateTexture( texture, options ) { const textureData = this.backend.get( texture ); @@ -389,6 +494,18 @@ class WebGPUTextureUtils { } + /** + * Returns texture data as a typed array. + * + * @async + * @param {Texture} texture - The texture to copy. + * @param {Number} x - The x coordinate of the copy origin. + * @param {Number} y - The y coordinate of the copy origin. + * @param {Number} width - The width of the copy. + * @param {Number} height - The height of the copy. + * @param {Number} faceIndex - The face index. + * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. + */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { const device = this.backend.device; @@ -438,6 +555,13 @@ class WebGPUTextureUtils { } + /** + * Returns `true` if the given texture is an environment map. + * + * @private + * @param {Texture} texture - The texture. + * @return {Boolean} Whether the given texture is an environment map or not. + */ _isEnvironmentTexture( texture ) { const mapping = texture.mapping; @@ -446,6 +570,13 @@ class WebGPUTextureUtils { } + /** + * Returns the default GPU texture for the given format. + * + * @private + * @param {String} format - The GPU format. + * @return {GPUTexture} The GPU texture. + */ _getDefaultTextureGPU( format ) { let defaultTexture = this.defaultTexture[ format ]; @@ -466,6 +597,13 @@ class WebGPUTextureUtils { } + /** + * Returns the default GPU cube texture for the given format. + * + * @private + * @param {String} format - The GPU format. + * @return {GPUTexture} The GPU texture. + */ _getDefaultCubeTextureGPU( format ) { let defaultCubeTexture = this.defaultTexture[ format ]; @@ -486,6 +624,12 @@ class WebGPUTextureUtils { } + /** + * Returns the default video frame used as default data in context of video textures. + * + * @private + * @return {VideoFrame} The video frame. + */ _getDefaultVideoFrame() { let defaultVideoFrame = this.defaultVideoFrame; @@ -507,6 +651,15 @@ class WebGPUTextureUtils { } + /** + * Uploads cube texture image data to the GPU memory. + * + * @private + * @param {Array} images - The cube image data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + * @param {Boolean} flipY - Whether to flip texture data along their vertical axis or not. + */ _copyCubeMapToTexture( images, textureGPU, textureDescriptorGPU, flipY ) { for ( let i = 0; i < 6; i ++ ) { @@ -529,13 +682,24 @@ class WebGPUTextureUtils { } + /** + * Uploads texture image data to the GPU memory. + * + * @private + * @param {HTMLImageElement|ImageBitmap|HTMLCanvasElement} image - The image data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + * @param {Number} originDepth - The origin depth. + * @param {Boolean} flipY - Whether to flip texture data along their vertical axis or not. + */ _copyImageToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY ) { const device = this.backend.device; device.queue.copyExternalImageToTexture( { - source: image + source: image, + flipY: flipY }, { texture: textureGPU, mipLevel: 0, @@ -547,14 +711,14 @@ class WebGPUTextureUtils { } ); - if ( flipY === true ) { - - this._flipY( textureGPU, textureDescriptorGPU, originDepth ); - - } - } + /** + * Returns the pass utils singleton. + * + * @private + * @return {WebGPUTexturePassUtils} The utils instance. + */ _getPassUtils() { let passUtils = this._passUtils; @@ -569,18 +733,45 @@ class WebGPUTextureUtils { } + /** + * Generates mipmaps for the given GPU texture. + * + * @private + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureDescriptorGPU - The texture descriptor. + * @param {Number} [baseArrayLayer=0] - The index of the first array layer accessible to the texture view. + */ _generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0 ) { this._getPassUtils().generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer ); } + /** + * Flip the contents of the given GPU texture along its vertical axis. + * + * @private + * @param {GPUTexture} textureGPU - The GPU texture object. + * @param {Object} textureDescriptorGPU - The texture descriptor. + * @param {Number} [originDepth=0] - The origin depth. + */ _flipY( textureGPU, textureDescriptorGPU, originDepth = 0 ) { this._getPassUtils().flipY( textureGPU, textureDescriptorGPU, originDepth ); } + /** + * Uploads texture buffer data to the GPU memory. + * + * @private + * @param {Object} image - An object defining the image buffer data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + * @param {Number} originDepth - The origin depth. + * @param {Boolean} flipY - Whether to flip texture data along their vertical axis or not. + * @param {Number} [depth=0] - TODO. + */ _copyBufferToTexture( image, textureGPU, textureDescriptorGPU, originDepth, flipY, depth = 0 ) { // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture() @@ -618,6 +809,14 @@ class WebGPUTextureUtils { } + /** + * Uploads compressed texture data to the GPU memory. + * + * @private + * @param {Array} mipmaps - An array with mipmap data. + * @param {GPUTexture} textureGPU - The GPU texture. + * @param {Object} textureDescriptorGPU - The GPU texture descriptor. + */ _copyCompressedBufferToTexture( mipmaps, textureGPU, textureDescriptorGPU ) { // @TODO: Consider to use GPUCommandEncoder.copyBufferToTexture() @@ -665,10 +864,16 @@ class WebGPUTextureUtils { } + /** + * This method is only relevant for compressed texture formats. It returns a block + * data descriptor for the given GPU compressed texture format. + * + * @private + * @param {String} format - The GPU compressed texture format. + * @return {Object} The block data descriptor. + */ _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 @@ -702,6 +907,13 @@ class WebGPUTextureUtils { } + /** + * Converts the three.js uv wrapping constants to GPU address mode constants. + * + * @private + * @param {Number} value - The three.js constant defining a uv wrapping mode. + * @return {String} The GPU address mode. + */ _convertAddressMode( value ) { let addressMode = GPUAddressMode.ClampToEdge; @@ -720,6 +932,13 @@ class WebGPUTextureUtils { } + /** + * Converts the three.js filter constants to GPU filter constants. + * + * @private + * @param {Number} value - The three.js constant defining a filter mode. + * @return {String} The GPU filter mode. + */ _convertFilterMode( value ) { let filterMode = GPUFilterMode.Linear; @@ -734,6 +953,13 @@ class WebGPUTextureUtils { } + /** + * Returns the bytes-per-texel value for the given GPU texture format. + * + * @private + * @param {String} format - The GPU texture format. + * @return {Number} The bytes-per-texel. + */ _getBytesPerTexel( format ) { // 8-bit formats @@ -790,6 +1016,13 @@ class WebGPUTextureUtils { } + /** + * Returns the corresponding typed array type for the given GPU texture format. + * + * @private + * @param {String} format - The GPU texture format. + * @return {TypedArray.constructor} The typed array type. + */ _getTypedArrayType( format ) { if ( format === GPUTextureFormat.R8Uint ) return Uint8Array; @@ -840,6 +1073,13 @@ class WebGPUTextureUtils { } + /** + * Returns the GPU dimensions for the given texture. + * + * @private + * @param {Texture} texture - The texture. + * @return {String} The GPU dimension. + */ _getDimension( texture ) { let dimension; @@ -860,6 +1100,14 @@ class WebGPUTextureUtils { } +/** + * Returns the GPU format for the given texture. + * + * @param {Texture} texture - The texture. + * @param {GPUDevice?} [device=null] - The GPU device which is used for feature detection. + * It is not necessary to apply the device for most formats. + * @return {String} The GPU format. + */ export function getFormat( texture, device = null ) { const format = texture.format; diff --git a/src/renderers/webgpu/utils/WebGPUUtils.js b/src/renderers/webgpu/utils/WebGPUUtils.js index a055059c6e15fc..382c009398aaba 100644 --- a/src/renderers/webgpu/utils/WebGPUUtils.js +++ b/src/renderers/webgpu/utils/WebGPUUtils.js @@ -1,13 +1,35 @@ +import { HalfFloatType, UnsignedByteType } from '../../../constants.js'; import { GPUPrimitiveTopology, GPUTextureFormat } from './WebGPUConstants.js'; +/** + * A WebGPU backend utility module with common helpers. + * + * @private + */ class WebGPUUtils { + /** + * Constructs a new utility object. + * + * @param {WebGPUBackend} backend - The WebGPU backend. + */ constructor( backend ) { + /** + * A reference to the WebGPU backend. + * + * @type {WebGPUBackend} + */ this.backend = backend; } + /** + * Returns the depth/stencil GPU format for the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {String} The depth/stencil GPU texture format. + */ getCurrentDepthStencilFormat( renderContext ) { let format; @@ -30,12 +52,24 @@ class WebGPUUtils { } + /** + * Returns the GPU format for the given texture. + * + * @param {Texture} texture - The texture. + * @return {String} The GPU texture format. + */ getTextureFormatGPU( texture ) { return this.backend.get( texture ).format; } + /** + * Returns an object that defines the multi-sampling state of the given texture. + * + * @param {Texture} texture - The texture. + * @return {Object} The multi-sampling state. + */ getTextureSampleData( texture ) { let samples; @@ -66,6 +100,12 @@ class WebGPUUtils { } + /** + * Returns the default color attachment's GPU format of the current render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {String} The GPU texture format of the default color attachment. + */ getCurrentColorFormat( renderContext ) { let format; @@ -84,6 +124,12 @@ class WebGPUUtils { } + /** + * Returns the output color space of the current render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {String} The output color space. + */ getCurrentColorSpace( renderContext ) { if ( renderContext.textures !== null ) { @@ -96,6 +142,13 @@ class WebGPUUtils { } + /** + * Returns GPU primitive topology for the given object and material. + * + * @param {Object3D} object - The 3D object. + * @param {Material} material - The material. + * @return {String} The GPU primitive topology. + */ getPrimitiveTopology( object, material ) { if ( object.isPoints ) return GPUPrimitiveTopology.PointList; @@ -105,6 +158,14 @@ class WebGPUUtils { } + /** + * Returns a modified sample count from the given sample count value. + * + * That is required since WebGPU does not support arbitrary sample counts. + * + * @param {Number} sampleCount - The input sample count. + * @return {Number} The (potentially updated) output sample count. + */ getSampleCount( sampleCount ) { let count = 1; @@ -126,6 +187,12 @@ class WebGPUUtils { } + /** + * Returns the sample count of the given render context. + * + * @param {RenderContext} renderContext - The render context. + * @return {Number} The sample count. + */ getSampleCountRenderContext( renderContext ) { if ( renderContext.textures !== null ) { @@ -138,18 +205,33 @@ class WebGPUUtils { } + /** + * Returns the preferred canvas format. + * + * There is a separate method for this so it's possible to + * honor edge cases for specific devices. + * + * @return {String} The GPU texture format of the canvas. + */ getPreferredCanvasFormat() { - // TODO: Remove this check when Quest 34.5 is out - // https://github.com/mrdoob/three.js/pull/29221/files#r1731833949 + const outputType = this.backend.parameters.outputType; - if ( navigator.userAgent.includes( 'Quest' ) ) { + if ( outputType === undefined ) { + + return navigator.gpu.getPreferredCanvasFormat(); + + } else if ( outputType === UnsignedByteType ) { return GPUTextureFormat.BGRA8Unorm; + } else if ( outputType === HalfFloatType ) { + + return GPUTextureFormat.RGBA16Float; + } else { - return navigator.gpu.getPreferredCanvasFormat(); + throw new Error( 'Unsupported outputType' ); } diff --git a/src/renderers/webxr/WebXRManager.js b/src/renderers/webxr/WebXRManager.js index 60b7ba41f84185..064b2384b04923 100644 --- a/src/renderers/webxr/WebXRManager.js +++ b/src/renderers/webxr/WebXRManager.js @@ -275,7 +275,11 @@ class WebXRManager extends EventDispatcher { currentPixelRatio = renderer.getPixelRatio(); renderer.getSize( currentSize ); - if ( session.renderState.layers === undefined ) { + // Check that the browser implements the necessary APIs to use an + // XRProjectionLayer rather than an XRWebGLLayer + const useLayers = typeof XRWebGLBinding !== 'undefined' && 'createProjectionLayer' in XRWebGLBinding.prototype; + + if ( ! useLayers ) { const layerInit = { antialias: attributes.antialias, @@ -782,8 +786,11 @@ class WebXRManager extends EventDispatcher { // const enabledFeatures = session.enabledFeatures; + const gpuDepthSensingEnabled = enabledFeatures && + enabledFeatures.includes( 'depth-sensing' ) && + session.depthUsage == 'gpu-optimized'; - if ( enabledFeatures && enabledFeatures.includes( 'depth-sensing' ) ) { + if ( gpuDepthSensingEnabled && glBinding ) { const depthData = glBinding.getDepthInformation( views[ 0 ] ); diff --git a/src/textures/Data3DTexture.js b/src/textures/Data3DTexture.js index 36348cc1f04a12..e6e99a4f08948a 100644 --- a/src/textures/Data3DTexture.js +++ b/src/textures/Data3DTexture.js @@ -6,9 +6,9 @@ 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. + // Users can still set in Data3DTexture directly. // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); + // const texture = new THREE.Data3DTexture( data, width, height, depth ); // texture.anisotropy = 16; // // See #14839 diff --git a/src/textures/VideoFrameTexture.js b/src/textures/VideoFrameTexture.js new file mode 100644 index 00000000000000..b58cf6e96069ce --- /dev/null +++ b/src/textures/VideoFrameTexture.js @@ -0,0 +1,33 @@ +import { VideoTexture } from './VideoTexture.js'; + +class VideoFrameTexture extends VideoTexture { + + constructor( mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { + + super( {}, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + } + + update() { + + // overwrites `VideoTexture.update()` with an empty method since + // this type of texture is updated via `setFrame()`. + + } + + clone() { + + return new this.constructor().copy( this ); // restoring Texture.clone() + + } + + setFrame( frame ) { + + this.image = frame; + this.needsUpdate = true; + + } + +} + +export { VideoFrameTexture }; diff --git a/test/e2e/deterministic-injection.js b/test/e2e/deterministic-injection.js index a0e9e99840877b..3b03ca4881bd97 100644 --- a/test/e2e/deterministic-injection.js +++ b/test/e2e/deterministic-injection.js @@ -59,7 +59,7 @@ }; - /* Semi-determitistic video */ + /* Semi-deterministic video */ const play = HTMLVideoElement.prototype.play; diff --git a/test/e2e/puppeteer.js b/test/e2e/puppeteer.js index 30361c329352b7..c65878b2428e72 100644 --- a/test/e2e/puppeteer.js +++ b/test/e2e/puppeteer.js @@ -47,10 +47,11 @@ const exceptionList = [ 'webgl_materials_video', 'webgl_video_kinect', 'webgl_video_panorama_equirectangular', + 'webgpu_video_frame', 'webaudio_visualizer', // audio can't be analyzed without proper audio hook - // WebXR also isn't determinstic enough? + // WebXR also isn't deterministic enough? 'webxr_ar_lighting', 'webxr_vr_sandbox', 'webxr_vr_video', @@ -111,14 +112,12 @@ const exceptionList = [ 'physics_jolt_instancing', // Awaiting for WebGL backend support - 'webgpu_clearcoat', 'webgpu_compute_audio', 'webgpu_compute_texture', 'webgpu_compute_texture_pingpong', "webgpu_compute_water", 'webgpu_materials', 'webgpu_sandbox', - 'webgpu_sprites', 'webgpu_video_panorama', 'webgpu_postprocessing_bloom_emissive', 'webgpu_lights_tiled', @@ -131,7 +130,6 @@ const exceptionList = [ // WebGPURenderer: Unknown problem 'webgpu_backdrop_water', 'webgpu_camera_logarithmicdepthbuffer', - 'webgpu_clipping', 'webgpu_lightprobe_cubecamera', 'webgpu_loader_materialx', 'webgpu_materials_video', @@ -154,10 +152,10 @@ const exceptionList = [ 'webgpu_tsl_vfx_flames', 'webgpu_tsl_halftone', 'webgpu_tsl_vfx_linkedparticles', - 'webgpu_tsl_vfx_tornado', 'webgpu_textures_anisotropy', + 'webgpu_textures_2d-array_compressed', + 'webgpu_rendertarget_2d-array_3d', 'webgpu_materials_envmaps_bpcem', - 'webgpu_postprocessing_ssr', 'webgpu_postprocessing_sobel', // WebGPU idleTime and parseTime too low @@ -328,11 +326,11 @@ async function main() { console.red( 'List of failed screenshots: ' + list ); console.red( `If you are sure that everything is correct, try to run "npm run make-screenshot ${ list }". If this does not help, try increasing idleTime and parseTime variables in /test/e2e/puppeteer.js file. If this also does not help, add remaining screenshots to the exception list.` ); - console.red( `${ failedScreenshots.length } from ${ files.length } screenshots have not generated succesfully.` ); + console.red( `${ failedScreenshots.length } from ${ files.length } screenshots have not generated successfully.` ); } else if ( isMakeScreenshot && ! failedScreenshots.length ) { - console.green( `${ files.length } screenshots succesfully generated.` ); + console.green( `${ files.length } screenshots successfully generated.` ); } else if ( failedScreenshots.length ) { diff --git a/test/unit/README.md b/test/unit/README.md index b846f42305b96b..e939baa2844d48 100644 --- a/test/unit/README.md +++ b/test/unit/README.md @@ -7,7 +7,7 @@ You can run the unit tests in two environments: - Node.js: Execute `npm run test-unit` from the root folder -- Browser: Execute `npx servez -p 8080 --ssl` (or run any other local web sever) from the root folder and access `https://localhost:8080/test/unit/UnitTests.html` in a web browser. +- Browser: Execute `npx servez -p 8080 --ssl` (or run any other local web sever) from the root folder and access `https://localhost:8080/test/unit/UnitTests.html` in a web browser. See [Installation](https://threejs.org/docs/#manual/introduction/Installation) for more information. @@ -15,7 +15,7 @@ See [Installation](https://threejs.org/docs/#manual/introduction/Installation) f A small number of tests can only be run in a browser environment. -For browser tests, futher changes to the library will not be reflected until the page is refreshed. +For browser tests, further changes to the library will not be reflected until the page is refreshed. ## Troubleshooting diff --git a/test/unit/src/animation/AnimationAction.tests.js b/test/unit/src/animation/AnimationAction.tests.js index b6165131af8e53..1d65e997c0afa6 100644 --- a/test/unit/src/animation/AnimationAction.tests.js +++ b/test/unit/src/animation/AnimationAction.tests.js @@ -64,7 +64,7 @@ export default QUnit.module( 'Animation', () => { const clip = new AnimationClip( 'nonname', - 1, [] ); const animationAction = new AnimationAction( mixer, clip ); - assert.ok( animationAction, 'animationAction instanciated' ); + assert.ok( animationAction, 'animationAction instantiated' ); } ); diff --git a/test/unit/src/animation/AnimationClip.tests.js b/test/unit/src/animation/AnimationClip.tests.js index d93b2d09aa9854..0eb3e8181cb7e9 100644 --- a/test/unit/src/animation/AnimationClip.tests.js +++ b/test/unit/src/animation/AnimationClip.tests.js @@ -10,7 +10,7 @@ export default QUnit.module( 'Animation', () => { QUnit.test( 'Instancing', ( assert ) => { const clip = new AnimationClip( 'clip1', 1000, [ {} ] ); - assert.ok( clip, 'AnimationClip can be instanciated' ); + assert.ok( clip, 'AnimationClip can be instantiated' ); } ); diff --git a/test/unit/src/animation/AnimationObjectGroup.tests.js b/test/unit/src/animation/AnimationObjectGroup.tests.js index 39b36d6ab99372..57ccaf5d2781da 100644 --- a/test/unit/src/animation/AnimationObjectGroup.tests.js +++ b/test/unit/src/animation/AnimationObjectGroup.tests.js @@ -27,7 +27,7 @@ export default QUnit.module( 'Animation', () => { const groupA = new AnimationObjectGroup(); assert.ok( groupA instanceof AnimationObjectGroup, - 'AnimationObjectGroup can be instanciated' + 'AnimationObjectGroup can be instantiated' ); } ); diff --git a/test/unit/src/core/BufferAttribute.tests.js b/test/unit/src/core/BufferAttribute.tests.js index 4dac2e2bcca116..95251d5e149954 100644 --- a/test/unit/src/core/BufferAttribute.tests.js +++ b/test/unit/src/core/BufferAttribute.tests.js @@ -146,9 +146,9 @@ export default QUnit.module( 'Core', () => { const i = attr.array; const i2 = attr2.array; // should be [4, 5, 6, 7, 8, 9, 1, 2, 3] - assert.ok( i2[ 0 ] === i[ 3 ] && i2[ 1 ] === i[ 4 ] && i2[ 2 ] === i[ 5 ], 'chunck copied to correct place' ); - assert.ok( i2[ 3 ] === i[ 6 ] && i2[ 4 ] === i[ 7 ] && i2[ 5 ] === i[ 8 ], 'chunck copied to correct place' ); - assert.ok( i2[ 6 ] === i[ 0 ] && i2[ 7 ] === i[ 1 ] && i2[ 8 ] === i[ 2 ], 'chunck copied to correct place' ); + assert.ok( i2[ 0 ] === i[ 3 ] && i2[ 1 ] === i[ 4 ] && i2[ 2 ] === i[ 5 ], 'chunk copied to correct place' ); + assert.ok( i2[ 3 ] === i[ 6 ] && i2[ 4 ] === i[ 7 ] && i2[ 5 ] === i[ 8 ], 'chunk copied to correct place' ); + assert.ok( i2[ 6 ] === i[ 0 ] && i2[ 7 ] === i[ 1 ] && i2[ 8 ] === i[ 2 ], 'chunk copied to correct place' ); } ); diff --git a/test/unit/src/core/InterleavedBufferAttribute.tests.js b/test/unit/src/core/InterleavedBufferAttribute.tests.js index 739d1c8ae9ae69..e7701055e6ed9e 100644 --- a/test/unit/src/core/InterleavedBufferAttribute.tests.js +++ b/test/unit/src/core/InterleavedBufferAttribute.tests.js @@ -117,7 +117,7 @@ export default QUnit.module( 'Core', () => { instance.setX( 0, 123 ); instance.setX( 1, 321 ); - // the offset was defined as 1, so go one step futher in the array + // the offset was defined as 1, so go one step further in the array assert.ok( instance.data.array[ 1 ] === 123 && instance.data.array[ 4 ] === 321, 'x was calculated correct based on index and default offset' ); diff --git a/test/unit/src/core/Object3D.tests.js b/test/unit/src/core/Object3D.tests.js index 922d0a1142676c..cf1a66f2afc59f 100644 --- a/test/unit/src/core/Object3D.tests.js +++ b/test/unit/src/core/Object3D.tests.js @@ -723,7 +723,7 @@ export default QUnit.module( 'Core', () => { parent.add( childName, childNothing ); assert.strictEqual( parent.getObjectsByProperty( 'name', 'foo' ).length, 3, 'Count the number of children with name "foo"' ); - assert.strictEqual( parent.getObjectsByProperty( 'name', 'foo' ).some( obj => obj.name !== 'foo' ), false, 'Get all childs by name "foo"' ); + assert.strictEqual( parent.getObjectsByProperty( 'name', 'foo' ).some( obj => obj.name !== 'foo' ), false, 'Get all children with name "foo"' ); } ); @@ -1323,7 +1323,7 @@ export default QUnit.module( 'Core', () => { assert.strictEqual( a, undefined, 'Undefined pre-clone()' ); a = b.clone(); - assert.notStrictEqual( a, b, 'Defined but seperate instances post-clone()' ); + assert.notStrictEqual( a, b, 'Defined but separate instances post-clone()' ); a.uuid = b.uuid; assert.deepEqual( a, b, 'But identical properties' ); diff --git a/test/unit/src/extras/DataUtils.tests.js b/test/unit/src/extras/DataUtils.tests.js index 74b549dbb52fd4..acd91f5d56532e 100644 --- a/test/unit/src/extras/DataUtils.tests.js +++ b/test/unit/src/extras/DataUtils.tests.js @@ -13,7 +13,7 @@ export default QUnit.module( 'Extras', () => { assert.ok( DataUtils.toHalfFloat( 0 ) === 0, 'Passed!' ); - // surpress the following console message during testing + // suppress the following console message during testing // THREE.DataUtils.toHalfFloat(): Value out of range. console.level = CONSOLE_LEVEL.OFF; diff --git a/test/unit/src/loaders/ImageBitmapLoader.tests.js b/test/unit/src/loaders/ImageBitmapLoader.tests.js index aa609dcbb8ef46..b995d7a1ce086f 100644 --- a/test/unit/src/loaders/ImageBitmapLoader.tests.js +++ b/test/unit/src/loaders/ImageBitmapLoader.tests.js @@ -12,7 +12,7 @@ export default QUnit.module( 'Loaders', () => { // INHERITANCE QUnit.test( 'Extending', ( assert ) => { - // surpress the following console message when testing + // suppress the following console message when testing // THREE.ImageBitmapLoader: createImageBitmap() not supported. console.level = CONSOLE_LEVEL.OFF; @@ -29,7 +29,7 @@ export default QUnit.module( 'Loaders', () => { // INSTANCING QUnit.test( 'Instancing', ( assert ) => { - // surpress the following console message when testing + // suppress the following console message when testing // THREE.ImageBitmapLoader: createImageBitmap() not supported. console.level = CONSOLE_LEVEL.OFF; @@ -43,7 +43,7 @@ export default QUnit.module( 'Loaders', () => { // PROPERTIES QUnit.test( 'options', ( assert ) => { - // surpress the following console message when testing in node + // suppress the following console message when testing in node // THREE.ImageBitmapLoader: createImageBitmap() not supported. console.level = CONSOLE_LEVEL.OFF; @@ -58,7 +58,7 @@ export default QUnit.module( 'Loaders', () => { // PUBLIC QUnit.test( 'isImageBitmapLoader', ( assert ) => { - // surpress the following console message when testing in node + // suppress the following console message when testing in node // THREE.ImageBitmapLoader: createImageBitmap() not supported. console.level = CONSOLE_LEVEL.OFF; diff --git a/test/unit/src/math/Box3.tests.js b/test/unit/src/math/Box3.tests.js index 14da461e2bfd69..083df55414b050 100644 --- a/test/unit/src/math/Box3.tests.js +++ b/test/unit/src/math/Box3.tests.js @@ -367,7 +367,7 @@ export default QUnit.module( 'Maths', () => { assert.ok( a.max.equals( new Vector3( 1, 1, 1 ) ), 'Smaller box: correct new maximum' ); // - assert.ok( new Box3().expandByObject( new Mesh() ).isEmpty() === true, 'The AABB of a mesh with inital geometry is empty.' ); + assert.ok( new Box3().expandByObject( new Mesh() ).isEmpty() === true, 'The AABB of a mesh with initial geometry is empty.' ); } ); diff --git a/test/unit/src/math/MathUtils.tests.js b/test/unit/src/math/MathUtils.tests.js index eddd6d70def64a..99312d7a29729d 100644 --- a/test/unit/src/math/MathUtils.tests.js +++ b/test/unit/src/math/MathUtils.tests.js @@ -29,11 +29,11 @@ export default QUnit.module( 'Maths', () => { QUnit.test( 'euclideanModulo', ( assert ) => { assert.ok( isNaN( MathUtils.euclideanModulo( 6, 0 ) ), 'Division by zero returns NaN' ); - assert.strictEqual( MathUtils.euclideanModulo( 6, 1 ), 0, 'Divison by trivial divisor' ); - assert.strictEqual( MathUtils.euclideanModulo( 6, 2 ), 0, 'Divison by non-trivial divisor' ); - assert.strictEqual( MathUtils.euclideanModulo( 6, 5 ), 1, 'Divison by itself - 1' ); - assert.strictEqual( MathUtils.euclideanModulo( 6, 6 ), 0, 'Divison by itself' ); - assert.strictEqual( MathUtils.euclideanModulo( 6, 7 ), 6, 'Divison by itself + 1' ); + assert.strictEqual( MathUtils.euclideanModulo( 6, 1 ), 0, 'Division by trivial divisor' ); + assert.strictEqual( MathUtils.euclideanModulo( 6, 2 ), 0, 'Division by non-trivial divisor' ); + assert.strictEqual( MathUtils.euclideanModulo( 6, 5 ), 1, 'Division by itself - 1' ); + assert.strictEqual( MathUtils.euclideanModulo( 6, 6 ), 0, 'Division by itself' ); + assert.strictEqual( MathUtils.euclideanModulo( 6, 7 ), 6, 'Division by itself + 1' ); } ); @@ -85,7 +85,7 @@ export default QUnit.module( 'Maths', () => { assert.strictEqual( MathUtils.smoothstep( 1, 0, 2 ), 0.5, 'Value within limits' ); assert.strictEqual( MathUtils.smoothstep( 1.5, 0, 2 ), 0.84375, 'Value within limits' ); assert.strictEqual( MathUtils.smoothstep( 2, 0, 2 ), 1, 'Value equal to maximum' ); - assert.strictEqual( MathUtils.smoothstep( 3, 0, 2 ), 1, 'Value highter than maximum' ); + assert.strictEqual( MathUtils.smoothstep( 3, 0, 2 ), 1, 'Value higher than maximum' ); } ); @@ -97,7 +97,7 @@ export default QUnit.module( 'Maths', () => { assert.strictEqual( MathUtils.smootherstep( 1, 0, 2 ), 0.5, 'Value within limits' ); assert.strictEqual( MathUtils.smootherstep( 1.5, 0, 2 ), 0.896484375, 'Value within limits' ); assert.strictEqual( MathUtils.smootherstep( 2, 0, 2 ), 1, 'Value equal to maximum' ); - assert.strictEqual( MathUtils.smootherstep( 3, 0, 2 ), 1, 'Value highter than maximum' ); + assert.strictEqual( MathUtils.smootherstep( 3, 0, 2 ), 1, 'Value higher than maximum' ); } ); diff --git a/test/unit/src/math/Ray.tests.js b/test/unit/src/math/Ray.tests.js index 7556c96a7e8580..3a7b03bb80683d 100644 --- a/test/unit/src/math/Ray.tests.js +++ b/test/unit/src/math/Ray.tests.js @@ -302,17 +302,17 @@ export default QUnit.module( 'Maths', () => { a.intersectPlane( c, point.copy( posInf3 ) ); assert.ok( point.equals( posInf3 ), 'Passed!' ); - // parallel plane infront + // parallel plane in front const d = new Plane().setFromNormalAndCoplanarPoint( new Vector3( 0, 0, 1 ), new Vector3( 1, 1, 1 ) ); a.intersectPlane( d, point.copy( posInf3 ) ); assert.ok( point.equals( a.origin ), 'Passed!' ); - // perpendical ray that overlaps exactly + // perpendicular ray that overlaps exactly const e = new Plane().setFromNormalAndCoplanarPoint( new Vector3( 1, 0, 0 ), one3 ); a.intersectPlane( e, point.copy( posInf3 ) ); assert.ok( point.equals( a.origin ), 'Passed!' ); - // perpendical ray that doesn't overlap + // perpendicular ray that doesn't overlap const f = new Plane().setFromNormalAndCoplanarPoint( new Vector3( 1, 0, 0 ), zero3 ); a.intersectPlane( f, point.copy( posInf3 ) ); assert.ok( point.equals( posInf3 ), 'Passed!' ); @@ -335,11 +335,11 @@ export default QUnit.module( 'Maths', () => { const d = new Plane().setFromNormalAndCoplanarPoint( new Vector3( 0, 0, 1 ), one3.clone().sub( new Vector3( 0, 0, 1 ) ) ); assert.ok( ! a.intersectsPlane( d ), 'Passed!' ); - // perpendical ray that overlaps exactly + // perpendicular ray that overlaps exactly const e = new Plane().setFromNormalAndCoplanarPoint( new Vector3( 1, 0, 0 ), one3 ); assert.ok( a.intersectsPlane( e ), 'Passed!' ); - // perpendical ray that doesn't overlap + // perpendicular ray that doesn't overlap const f = new Plane().setFromNormalAndCoplanarPoint( new Vector3( 1, 0, 0 ), zero3 ); assert.ok( ! a.intersectsPlane( f ), 'Passed!' ); diff --git a/test/unit/src/objects/Mesh.tests.js b/test/unit/src/objects/Mesh.tests.js index c494a99f7e7884..07077f8a613858 100644 --- a/test/unit/src/objects/Mesh.tests.js +++ b/test/unit/src/objects/Mesh.tests.js @@ -120,12 +120,12 @@ export default QUnit.module( 'Objects', () => { const intersection = intersections[ 0 ]; - assert.equal( intersection.object, mesh, 'intersction object' ); - assert.equal( intersection.distance, 1, 'intersction distance' ); - assert.equal( intersection.faceIndex, 1, 'intersction face index' ); - assert.deepEqual( intersection.face, { a: 0, b: 2, c: 1 }, 'intersction vertex indices' ); - assert.deepEqual( intersection.point, new Vector3( 0.25, 0.25, 0 ), 'intersction point' ); - assert.deepEqual( intersection.uv, new Vector2( 0.75, 0.75 ), 'intersction uv' ); + assert.equal( intersection.object, mesh, 'intersection object' ); + assert.equal( intersection.distance, 1, 'intersection distance' ); + assert.equal( intersection.faceIndex, 1, 'intersection face index' ); + assert.deepEqual( intersection.face, { a: 0, b: 2, c: 1 }, 'intersection vertex indices' ); + assert.deepEqual( intersection.point, new Vector3( 0.25, 0.25, 0 ), 'intersection point' ); + assert.deepEqual( intersection.uv, new Vector2( 0.75, 0.75 ), 'intersection uv' ); } ); diff --git a/test/unit/src/renderers/webgl/WebGLExtensions.tests.js b/test/unit/src/renderers/webgl/WebGLExtensions.tests.js index dcf61bbd41e817..6d579dfe45b0d6 100644 --- a/test/unit/src/renderers/webgl/WebGLExtensions.tests.js +++ b/test/unit/src/renderers/webgl/WebGLExtensions.tests.js @@ -49,7 +49,7 @@ export default QUnit.module( 'Renderers', () => { } ); - QUnit.test( 'has (with aliasses)', ( assert ) => { + QUnit.test( 'has (with aliases)', ( assert ) => { const gl = new WebglContextMock( [ 'WEBKIT_WEBGL_depth_texture' ] ); const extensions = new WebGLExtensions( gl ); @@ -68,7 +68,7 @@ export default QUnit.module( 'Renderers', () => { assert.ok( extensions.get( 'Extension2' ) ); assert.ok( extensions.get( 'Extension1' ) ); - // surpress the following console message when testing + // suppress the following console message when testing // THREE.WebGLRenderer: NonExistingExtension extension not supported. console.level = CONSOLE_LEVEL.OFF; @@ -77,14 +77,14 @@ export default QUnit.module( 'Renderers', () => { } ); - QUnit.test( 'get (with aliasses)', ( assert ) => { + QUnit.test( 'get (with aliases)', ( assert ) => { const gl = new WebglContextMock( [ 'WEBKIT_WEBGL_depth_texture' ] ); const extensions = new WebGLExtensions( gl ); assert.ok( extensions.get( 'WEBGL_depth_texture' ) ); assert.ok( extensions.get( 'WEBKIT_WEBGL_depth_texture' ) ); - // surpress the following console message when testing + // suppress the following console message when testing // THREE.WebGLRenderer: EXT_texture_filter_anisotropic extension not supported. // THREE.WebGLRenderer: NonExistingExtension extension not supported. diff --git a/test/unit/src/utils.tests.js b/test/unit/src/utils.tests.js index c5fc7f1df75d5c..ea0f8d3aa0689a 100644 --- a/test/unit/src/utils.tests.js +++ b/test/unit/src/utils.tests.js @@ -6,7 +6,7 @@ QUnit.module( 'utils', () => { QUnit.test( 'arrayMin', ( assert ) => { - assert.equal( arrayMin( [] ), Infinity, 'Empty array return positive infinit' ); + assert.equal( arrayMin( [] ), Infinity, 'Empty array return positive infinity' ); assert.equal( arrayMin( [ 5 ] ), 5, 'Single valued array should return the unique value as minimum' ); assert.equal( arrayMin( [ 1, 5, 10 ] ), 1, 'The array [ 1, 5, 10 ] return 1' ); assert.equal( arrayMin( [ 5, 1, 10 ] ), 1, 'The array [ 5, 1, 10 ] return 1' ); @@ -18,7 +18,7 @@ QUnit.module( 'utils', () => { QUnit.test( 'arrayMax', ( assert ) => { - assert.equal( arrayMax( [] ), - Infinity, 'Empty array return negative infinit' ); + assert.equal( arrayMax( [] ), - Infinity, 'Empty array return negative infinity' ); assert.equal( arrayMax( [ 5 ] ), 5, 'Single valued array should return the unique value as maximum' ); assert.equal( arrayMax( [ 10, 5, 1 ] ), 10, 'The array [ 10, 5, 1 ] return 10' ); assert.equal( arrayMax( [ 1, 10, 5 ] ), 10, 'The array [ 1, 10, 5 ] return 10' ); diff --git a/test/unit/utils/qunit-utils.js b/test/unit/utils/qunit-utils.js index 695db27fb5b031..e5b3fc60af9838 100644 --- a/test/unit/utils/qunit-utils.js +++ b/test/unit/utils/qunit-utils.js @@ -141,7 +141,7 @@ function checkGeometryJsonWriting( geom, json ) { } - // All parameters from json should be transfered to the geometry. + // All parameters from json should be transferred to the geometry. // json is flat. Ignore first level json properties that are not parameters. const notParameters = [ 'metadata', 'uuid', 'type' ]; keys = Object.keys( json ); diff --git a/utils/build/rollup.config.js b/utils/build/rollup.config.js index 0d74075e53854d..2385b25c560cc8 100644 --- a/utils/build/rollup.config.js +++ b/utils/build/rollup.config.js @@ -45,7 +45,7 @@ function header() { code.prepend( `/** * @license - * Copyright 2010-2024 Three.js Authors + * Copyright 2010-2025 Three.js Authors * SPDX-License-Identifier: MIT */\n` ); diff --git a/utils/docs/jsdoc.config.json b/utils/docs/jsdoc.config.json index 76e9502895fd79..040ce014759bd4 100644 --- a/utils/docs/jsdoc.config.json +++ b/utils/docs/jsdoc.config.json @@ -4,7 +4,24 @@ "encoding": "utf8", "package": "package.json", "recurse": true, - "template": "node_modules/clean-jsdoc-theme" + "template": "node_modules/clean-jsdoc-theme", + "theme_opts": { + "homepageTitle": "three.js docs" + } }, - "plugins": [ "plugins/markdown" ] + "plugins": [ "plugins/markdown" ], + "source": { + "include": [ + "examples/jsm/tsl", + "src/loaders/nodes", + "src/materials/nodes", + "src/nodes", + "src/renderers/common", + "src/renderers/webgpu" + ] + }, + "markdown": { + "hardwrap": false, + "idInHeadings": true + } }