vendor: 662,772 bytes, lines 1-19719
1/** 2 * @license 3 * Copyright 2010-2026 Three.js Authors 4 * SPDX-License-Identifier: MIT 5 */ 6import { Matrix3, Vector2, Color, Vector3, mergeUniforms, CubeUVReflectionMapping, Mesh, BoxGeometry, ShaderMaterial, BackSide, cloneUniforms, Matrix4, ColorManagement, SRGBTransfer, PlaneGeometry, FrontSide, getUnlitUniformColorSpace, IntType, warn, HalfFloatType, UnsignedByteType, FloatType, RGBAFormat, Plane, CubeReflectionMapping, CubeRefractionMapping, BufferGeometry, OrthographicCamera, PerspectiveCamera, NoToneMapping, MeshBasicMaterial, NoBlending, WebGLRenderTarget, BufferAttribute, LinearSRGBColorSpace, LinearFilter, CubeTexture, LinearMipmapLinearFilter, CubeCamera, EquirectangularReflectionMapping, EquirectangularRefractionMapping, warnOnce, Uint32BufferAttribute, Uint16BufferAttribute, error, DataArrayTexture, Vector4, Float32BufferAttribute, RawShaderMaterial, CustomToneMapping, NeutralToneMapping, AgXToneMapping, ACESFilmicToneMapping, CineonToneMapping, ReinhardToneMapping, LinearToneMapping, Data3DTexture, GreaterEqualCompare, LessEqualCompare, DepthTexture, Texture, GLSL3, VSMShadowMap, PCFShadowMap, AddOperation, MixOperation, MultiplyOperation, LinearTransfer, UniformsUtils, DoubleSide, NormalBlending, TangentSpaceNormalMap, ObjectSpaceNormalMap, Layers, RGFormat, RG11_EAC_Format, RED_GREEN_RGTC2_Format, MeshDepthMaterial, MeshDistanceMaterial, PCFSoftShadowMap, DepthFormat, NearestFilter, CubeDepthTexture, UnsignedIntType, Frustum, LessEqualDepth, ReverseSubtractEquation, SubtractEquation, AddEquation, OneMinusConstantAlphaFactor, ConstantAlphaFactor, OneMinusConstantColorFactor, ConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, DstAlphaFactor, DstColorFactor, SrcAlphaSaturateFactor, SrcAlphaFactor, SrcColorFactor, OneFactor, ZeroFactor, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessDepth, AlwaysDepth, NeverDepth, CullFaceNone, CullFaceBack, CullFaceFront, CustomBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, ReversedDepthFuncs, MinEquation, MaxEquation, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, LinearMipmapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NotEqualCompare, GreaterCompare, EqualCompare, LessCompare, AlwaysCompare, NeverCompare, NoColorSpace, DepthStencilFormat, getByteLength, UnsignedInt248Type, UnsignedShortType, createElementNS, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt5999Type, UnsignedInt101111Type, ByteType, ShortType, AlphaFormat, RGBFormat, RedFormat, RedIntegerFormat, 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, R11_EAC_Format, SIGNED_R11_EAC_Format, SIGNED_RG11_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, SIGNED_RED_GREEN_RGTC2_Format, ExternalTexture, EventDispatcher, ArrayCamera, WebXRController, RAD2DEG, DataTexture, createCanvasElement, SRGBColorSpace, REVISION, log, WebGLCoordinateSystem, probeAsync } from './three.core.js'; 7export { AdditiveAnimationBlendMode, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BasicShadowMap, BatchedMesh, BezierInterpolant, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, Compatibility, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, Controls, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CylinderGeometry, Cylindrical, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualStencilFunc, Euler, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Fog, FogExp2, FramebufferTexture, FrustumArray, GLBufferAttribute, GLSL1, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HTMLTexture, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateBezier, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InterpolationSamplingMode, InterpolationSamplingType, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, LightShadow, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, Material, MaterialBlending, MaterialLoader, MathUtils, Matrix2, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NeverStencilFunc, NoNormalPacking, NormalAnimationBlendMode, NormalGAPacking, NormalRGPacking, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, OctahedronGeometry, Path, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBADepthPacking, RGBDepthPacking, RGBIntegerFormat, RGDepthPacking, Ray, Raycaster, RectAreaLight, RenderObjectRefreshType, RenderTarget, RenderTarget3D, 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, TextureSource, TextureUtils, Timer, TimestampQuery, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, ZeroStencilOp, getConsoleFunction, setConsoleFunction } from './three.core.js'; 8 9function WebGLAnimation() { 10 11 let context = null; 12 let isAnimating = false; 13 let animationLoop = null; 14 let requestId = null; 15 16 function onAnimationFrame( time, frame ) { 17 18 requestId = context.requestAnimationFrame( onAnimationFrame ); 19 20 animationLoop( time, frame ); 21 22 } 23 24 return { 25 26 start: function () { 27 28 if ( isAnimating === true ) return; 29 if ( animationLoop === null ) return; 30 if ( context === null ) return; 31 32 requestId = context.requestAnimationFrame( onAnimationFrame ); 33 34 isAnimating = true; 35 36 }, 37 38 stop: function () { 39 40 if ( context !== null ) context.cancelAnimationFrame( requestId ); 41 42 isAnimating = false; 43 44 }, 45 46 setAnimationLoop: function ( callback ) { 47 48 animationLoop = callback; 49 50 }, 51 52 setContext: function ( value ) { 53 54 context = value; 55 56 } 57 58 }; 59 60} 61 62function WebGLAttributes( gl ) { 63 64 const buffers = new WeakMap(); 65 66 function createBuffer( attribute, bufferType ) { 67 68 const array = attribute.array; 69 const usage = attribute.usage; 70 const size = array.byteLength; 71 72 const buffer = gl.createBuffer(); 73 74 gl.bindBuffer( bufferType, buffer ); 75 gl.bufferData( bufferType, array, usage ); 76 77 attribute.onUploadCallback(); 78 79 let type; 80 81 if ( array instanceof Float32Array ) { 82 83 type = gl.FLOAT; 84 85 } else if ( typeof Float16Array !== 'undefined' && array instanceof Float16Array ) { 86 87 type = gl.HALF_FLOAT; 88 89 } else if ( array instanceof Uint16Array ) { 90 91 if ( attribute.isFloat16BufferAttribute ) { 92 93 type = gl.HALF_FLOAT; 94 95 } else { 96 97 type = gl.UNSIGNED_SHORT; 98 99 } 100 101 } else if ( array instanceof Int16Array ) { 102 103 type = gl.SHORT; 104 105 } else if ( array instanceof Uint32Array ) { 106 107 type = gl.UNSIGNED_INT; 108 109 } else if ( array instanceof Int32Array ) { 110 111 type = gl.INT; 112 113 } else if ( array instanceof Int8Array ) { 114 115 type = gl.BYTE; 116 117 } else if ( array instanceof Uint8Array ) { 118 119 type = gl.UNSIGNED_BYTE; 120 121 } else if ( array instanceof Uint8ClampedArray ) { 122 123 type = gl.UNSIGNED_BYTE; 124 125 } else { 126 127 throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array ); 128 129 } 130 131 return { 132 buffer: buffer, 133 type: type, 134 bytesPerElement: array.BYTES_PER_ELEMENT, 135 version: attribute.version, 136 size: size 137 }; 138 139 } 140 141 function updateBuffer( buffer, attribute, bufferType ) { 142 143 const array = attribute.array; 144 const updateRanges = attribute.updateRanges; 145 146 gl.bindBuffer( bufferType, buffer ); 147 148 if ( updateRanges.length === 0 ) { 149 150 // Not using update ranges 151 gl.bufferSubData( bufferType, 0, array ); 152 153 } else { 154 155 // Before applying update ranges, we merge any adjacent / overlapping 156 // ranges to reduce load on `gl.bufferSubData`. Empirically, this has led 157 // to performance improvements for applications which make heavy use of 158 // update ranges. Likely due to GPU command overhead. 159 // 160 // Note that to reduce garbage collection between frames, we merge the 161 // update ranges in-place. This is safe because this method will clear the 162 // update ranges once updated. 163 164 updateRanges.sort( ( a, b ) => a.start - b.start ); 165 166 // To merge the update ranges in-place, we work from left to right in the 167 // existing updateRanges array, merging ranges. This may result in a final 168 // array which is smaller than the original. This index tracks the last 169 // index representing a merged range, any data after this index can be 170 // trimmed once the merge algorithm is completed. 171 let mergeIndex = 0; 172 173 for ( let i = 1; i < updateRanges.length; i ++ ) { 174 175 const previousRange = updateRanges[ mergeIndex ]; 176 const range = updateRanges[ i ]; 177 178 // We add one here to merge adjacent ranges. This is safe because ranges 179 // operate over positive integers. 180 if ( range.start <= previousRange.start + previousRange.count + 1 ) { 181 182 previousRange.count = Math.max( 183 previousRange.count, 184 range.start + range.count - previousRange.start 185 ); 186 187 } else { 188 189 ++ mergeIndex; 190 updateRanges[ mergeIndex ] = range; 191 192 } 193 194 } 195 196 // Trim the array to only contain the merged ranges. 197 updateRanges.length = mergeIndex + 1; 198 199 for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { 200 201 const range = updateRanges[ i ]; 202 203 gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, 204 array, range.start, range.count ); 205 206 } 207 208 attribute.clearUpdateRanges(); 209 210 } 211 212 attribute.onUploadCallback(); 213 214 } 215 216 // 217 218 function get( attribute ) { 219 220 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; 221 222 return buffers.get( attribute ); 223 224 } 225 226 function remove( attribute ) { 227 228 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; 229 230 const data = buffers.get( attribute ); 231 232 if ( data ) { 233 234 gl.deleteBuffer( data.buffer ); 235 236 buffers.delete( attribute ); 237 238 } 239 240 } 241 242 function update( attribute, bufferType ) { 243 244 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; 245 246 if ( attribute.isGLBufferAttribute ) { 247 248 const cached = buffers.get( attribute ); 249 250 if ( ! cached || cached.version < attribute.version ) { 251 252 buffers.set( attribute, { 253 buffer: attribute.buffer, 254 type: attribute.type, 255 bytesPerElement: attribute.elementSize, 256 version: attribute.version 257 } ); 258 259 } 260 261 return; 262 263 } 264 265 const data = buffers.get( attribute ); 266 267 if ( data === undefined ) { 268 269 buffers.set( attribute, createBuffer( attribute, bufferType ) ); 270 271 } else if ( data.version < attribute.version ) { 272 273 if ( data.size !== attribute.array.byteLength ) { 274 275 throw new Error( 'THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.' ); 276 277 } 278 279 updateBuffer( data.buffer, attribute, bufferType ); 280 281 data.version = attribute.version; 282 283 } 284 285 } 286 287 return { 288 289 get: get, 290 remove: remove, 291 update: update 292 293 }; 294 295} 296 297var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; 298 299var alphahash_pars_fragment = "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D( vec2 value ) {\n\t\treturn fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) );\n\t}\n\tfloat hash3D( vec3 value ) {\n\t\treturn hash2D( vec2( hash2D( value.xy ), value.z ) );\n\t}\n\tfloat getAlphaHashThreshold( vec3 position ) {\n\t\tfloat maxDeriv = max(\n\t\t\tlength( dFdx( position.xyz ) ),\n\t\t\tlength( dFdy( position.xyz ) )\n\t\t);\n\t\tfloat pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv );\n\t\tvec2 pixScales = vec2(\n\t\t\texp2( floor( log2( pixScale ) ) ),\n\t\t\texp2( ceil( log2( pixScale ) ) )\n\t\t);\n\t\tvec2 alpha = vec2(\n\t\t\thash3D( floor( pixScales.x * position.xyz ) ),\n\t\t\thash3D( floor( pixScales.y * position.xyz ) )\n\t\t);\n\t\tfloat lerpFactor = fract( log2( pixScale ) );\n\t\tfloat x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y;\n\t\tfloat a = min( lerpFactor, 1.0 - lerpFactor );\n\t\tvec3 cases = vec3(\n\t\t\tx * x / ( 2.0 * a * ( 1.0 - a ) ),\n\t\t\t( x - 0.5 * a ) / ( 1.0 - a ),\n\t\t\t1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )\n\t\t);\n\t\tfloat threshold = ( x < ( 1.0 - a ) )\n\t\t\t? ( ( x < a ) ? cases.x : cases.y )\n\t\t\t: cases.z;\n\t\treturn clamp( threshold , 1.0e-6, 1.0 );\n\t}\n#endif"; 300 301var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; 302 303var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; 304 305var alphatest_fragment = "#ifdef USE_ALPHATEST\n\t#ifdef ALPHA_TO_COVERAGE\n\tdiffuseColor.a = smoothstep( alphaTest, alphaTest + fwidth( diffuseColor.a ), diffuseColor.a );\n\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\tif ( diffuseColor.a < alphaTest ) discard;\n\t#endif\n#endif"; 306 307var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; 308 309var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; 310 311var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; 312 313var batching_pars_vertex = "#ifdef USE_BATCHING\n\t#if ! defined( GL_ANGLE_multi_draw )\n\t#define gl_DrawID _gl_DrawID\n\tuniform int _gl_DrawID;\n\t#endif\n\tuniform highp sampler2D batchingTexture;\n\tuniform highp usampler2D batchingIdTexture;\n\tmat4 getBatchingMatrix( const in float i ) {\n\t\tint size = textureSize( batchingTexture, 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( batchingTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n\tfloat getIndirectIndex( const in int i ) {\n\t\tint size = textureSize( batchingIdTexture, 0 ).x;\n\t\tint x = i % size;\n\t\tint y = i / size;\n\t\treturn float( texelFetch( batchingIdTexture, ivec2( x, y ), 0 ).r );\n\t}\n#endif\n#ifdef USE_BATCHING_COLOR\n\tuniform sampler2D batchingColorTexture;\n\tvec4 getBatchingColor( const in float i ) {\n\t\tint size = textureSize( batchingColorTexture, 0 ).x;\n\t\tint j = int( i );\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\treturn texelFetch( batchingColorTexture, ivec2( x, y ), 0 );\n\t}\n#endif"; 314 315var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( getIndirectIndex( gl_DrawID ) );\n#endif"; 316 317var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; 318 319var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; 320 321var bsdfs = "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n} // validated"; 322 323var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; 324 325var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vBumpMapUv );\n\t\tvec2 dSTdy = dFdy( vBumpMapUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) );\n\t\tvec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; 326 327var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 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"; 328 329var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; 330 331var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; 332 333var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; 334 335var color_fragment = "#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#endif"; 336 337var color_pars_fragment = "#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#endif"; 338 339var color_pars_vertex = "#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\n\tvarying vec4 vColor;\n#endif"; 340 341var color_vertex = "#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\n\tvColor = vec4( 1.0 );\n#endif\n#ifdef USE_COLOR_ALPHA\n\tvColor *= color;\n#elif defined( USE_COLOR )\n\tvColor.rgb *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.rgb *= instanceColor.rgb;\n#endif\n#ifdef USE_BATCHING_COLOR\n\tvColor *= getBatchingColor( getIndirectIndex( gl_DrawID ) );\n#endif"; 342 343var 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}\n#define inverseTransformDirection transformDirectionByInverseViewMatrix\nvec3 transformNormalByInverseViewMatrix( in vec3 normal, in mat4 viewMatrix ) {\n\treturn normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz );\n}\nvec3 transformDirectionByInverseViewMatrix( in vec3 dir, in mat4 viewMatrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * viewMatrix ).xyz );\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"; 344 345var 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"; 346 347var 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#endif"; 348 349var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; 350 351var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; 352 353var 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"; 354 355var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; 356 357var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; 358 359var 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}"; 360 361var 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 = transformNormalByInverseViewMatrix( 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 * reflectVec );\n\t\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t\t#endif\n\t#endif\n#endif"; 362 363var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\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#endif"; 364 365var 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"; 366 367var 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"; 368 369var 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 = transformNormalByInverseViewMatrix( 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"; 370 371var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; 372 373var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; 374 375var 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"; 376 377var 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"; 378 379var 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}"; 380 381var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; 382 383var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; 384 385var 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"; 386 387var 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 = transformNormalByInverseViewMatrix( 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_SUN_LIGHTS > 0\n\tstruct SunLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform SunLight sunLights[ NUM_SUN_LIGHTS ];\n\tvoid getSunLightInfo( const in SunLight sunLight, out IncidentLight light ) {\n\t\tlight.color = sunLight.color;\n\t\tlight.direction = sunLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\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\n#include <lightprobes_pars_fragment>"; 388 389var 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 = transformNormalByInverseViewMatrix( 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, pow4( roughness ) ) );\n\t\t\treflectVec = transformDirectionByInverseViewMatrix( 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_RETROREFLECTION\n\t\tvec3 getIBLRetroRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 retroVec = normalize( mix( viewDir, normal, pow4( roughness ) ) );\n\t\t\t\tretroVec = transformDirectionByInverseViewMatrix( retroVec, viewMatrix );\n\t\t\t\tvec4 envMapColor = textureCubeUV( envMap, envMapRotation * retroVec, roughness );\n\t\t\t\treturn envMapColor.rgb * envMapIntensity;\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\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\t#ifdef USE_RETROREFLECTION\n\t\t\tvec3 getIBLAnisotropyRetroRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\t\treturn getIBLRetroRadiance( viewDir, bentNormal, roughness );\n\t\t\t\t#else\n\t\t\t\t\treturn vec3( 0.0 );\n\t\t\t\t#endif\n\t\t\t}\n\t\t#endif\n\t#endif\n#endif"; 390 391var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; 392 393var 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"; 394 395var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; 396 397var 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"; 398 399var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.diffuseContribution = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.metalness = 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 = min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor;\n\tmaterial.specularColorBlended = mix( material.specularColor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = vec3( 0.04 );\n\tmaterial.specularColorBlended = mix( material.specularColor, 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_RETROREFLECTION\n\tmaterial.retroreflectivity = retroreflectivity;\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.0001, 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"; 400 401var lights_physical_pars_fragment = "uniform sampler2D dfgLUT;\nstruct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tvec3 diffuseContribution;\n\tvec3 specularColor;\n\tvec3 specularColorBlended;\n\tfloat roughness;\n\tfloat metalness;\n\tfloat specularF90;\n\tfloat dispersion;\n\tvec2 dfg;\n\tvec3 multiScatteringCompensation;\n\t#ifdef USE_RETROREFLECTION\n\t\tfloat retroreflectivity;\n\t#endif\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 iridescenceF0Dielectric;\n\t\tvec3 iridescenceF0Metallic;\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\treturn 0.5 / max( gv + gl, EPSILON );\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.specularColorBlended;\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 * transpose( 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 rInv = 1.0 / ( roughness + 0.1 );\n\tfloat a = -1.9362 + 1.0678 * roughness + 0.4573 * r2 - 0.8469 * rInv;\n\tfloat b = -0.6014 + 0.5538 * roughness - 0.4670 * r2 - 0.1255 * rInv;\n\tfloat DG = exp( a * dotNV + b );\n\treturn saturate( DG );\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 fab = texture2D( dfgLUT, vec2( roughness, dotNV ) ).rg;\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec2 fab, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec2 fab, const in vec3 specularColor, const in float specularF90, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\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.specularColorBlended * t2.x + ( material.specularF90 - material.specularColorBlended ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseContribution * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t\t#ifdef USE_CLEARCOAT\n\t\t\tvec3 Ncc = geometryClearcoatNormal;\n\t\t\tvec2 uvClearcoat = LTC_Uv( Ncc, viewDir, material.clearcoatRoughness );\n\t\t\tvec4 t1Clearcoat = texture2D( ltc_1, uvClearcoat );\n\t\t\tvec4 t2Clearcoat = texture2D( ltc_2, uvClearcoat );\n\t\t\tmat3 mInvClearcoat = mat3(\n\t\t\t\tvec3( t1Clearcoat.x, 0, t1Clearcoat.y ),\n\t\t\t\tvec3( 0, 1, 0 ),\n\t\t\t\tvec3( t1Clearcoat.z, 0, t1Clearcoat.w )\n\t\t\t);\n\t\t\tvec3 fresnelClearcoat = material.clearcoatF0 * t2Clearcoat.x + ( material.clearcoatF90 - material.clearcoatF0 ) * t2Clearcoat.y;\n\t\t\tclearcoatSpecularDirect += lightColor * fresnelClearcoat * LTC_Evaluate( Ncc, viewDir, position, mInvClearcoat, rectCoords );\n\t\t#endif\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 \n \t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n \n \t\tfloat sheenAlbedoV = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n \t\tfloat sheenAlbedoL = IBLSheenBRDF( geometryNormal, directLight.direction, material.sheenRoughness );\n \n \t\tfloat sheenEnergyComp = 1.0 - max3( material.sheenColor ) * max( sheenAlbedoV, sheenAlbedoL );\n \n \t\tirradiance *= sheenEnergyComp;\n \n \t#endif\n\tvec3 specularBRDF = BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\t#ifdef USE_RETROREFLECTION\n\t\tvec3 retroViewDir = reflect( - geometryViewDir, geometryNormal );\n\t\tvec3 retroSpecularBRDF = BRDF_GGX( directLight.direction, retroViewDir, geometryNormal, material );\n\t\tspecularBRDF = mix( specularBRDF, retroSpecularBRDF, saturate( material.retroreflectivity ) );\n\t#endif\n\treflectedLight.directSpecular += irradiance * specularBRDF * material.multiScatteringCompensation;\n\tvec3 halfDir = normalize( directLight.direction + geometryViewDir );\n\tfloat dotVH = saturate( dot( geometryViewDir, halfDir ) );\n\tvec3 F = F_Schlick( material.specularColor, material.specularF90, dotVH );\n\t#ifdef USE_RETROREFLECTION\n\t\tvec3 retroHalfDir = normalize( directLight.direction + retroViewDir );\n\t\tfloat dotRetroVH = saturate( dot( retroViewDir, retroHalfDir ) );\n\t\tvec3 retroF = F_Schlick( material.specularColor, material.specularF90, dotRetroVH );\n\t\tF = mix( F, retroF, saturate( material.retroreflectivity ) );\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseContribution ) * ( 1.0 - F );\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\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( material.dfg, material.specularColor, material.specularF90, material.iridescence, material.iridescenceF0Dielectric, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( material.dfg, material.specularColor, material.specularF90, singleScattering, multiScattering );\n\t#endif\n\tvec3 diffuse = irradiance * BRDF_Lambert( material.diffuseContribution ) * ( 1.0 - singleScattering - multiScattering );\n\t#ifdef USE_SHEEN\n\t\tfloat sheenAlbedo = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * sheenAlbedo * RECIPROCAL_PI;\n\t\tfloat sheenEnergyComp = 1.0 - max3( material.sheenColor ) * sheenAlbedo;\n\t\tdiffuse *= sheenEnergyComp;\n\t#endif\n\treflectedLight.indirectDiffuse += diffuse;\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 ) * RECIPROCAL_PI;\n \t#endif\n\tvec3 singleScatteringDielectric = vec3( 0.0 );\n\tvec3 multiScatteringDielectric = vec3( 0.0 );\n\tvec3 singleScatteringMetallic = vec3( 0.0 );\n\tvec3 multiScatteringMetallic = vec3( 0.0 );\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( material.dfg, material.specularColor, material.specularF90, material.iridescence, material.iridescenceF0Dielectric, singleScatteringDielectric, multiScatteringDielectric );\n\t\tcomputeMultiscatteringIridescence( material.dfg, material.diffuseColor, material.specularF90, material.iridescence, material.iridescenceF0Metallic, singleScatteringMetallic, multiScatteringMetallic );\n\t#else\n\t\tcomputeMultiscattering( material.dfg, material.specularColor, material.specularF90, singleScatteringDielectric, multiScatteringDielectric );\n\t\tcomputeMultiscattering( material.dfg, material.diffuseColor, material.specularF90, singleScatteringMetallic, multiScatteringMetallic );\n\t#endif\n\tvec3 singleScattering = mix( singleScatteringDielectric, singleScatteringMetallic, material.metalness );\n\tvec3 multiScattering = mix( multiScatteringDielectric, multiScatteringMetallic, material.metalness );\n\tvec3 totalScatteringDielectric = singleScatteringDielectric + multiScatteringDielectric;\n\tvec3 diffuse = material.diffuseContribution * ( 1.0 - totalScatteringDielectric );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tvec3 indirectSpecular = radiance * singleScattering;\n\tindirectSpecular += multiScattering * cosineWeightedIrradiance;\n\tvec3 indirectDiffuse = diffuse * cosineWeightedIrradiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenAlbedo = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t\tfloat sheenEnergyComp = 1.0 - max3( material.sheenColor ) * sheenAlbedo;\n\t\tindirectSpecular *= sheenEnergyComp;\n\t\tindirectDiffuse *= sheenEnergyComp;\n\t#endif\n\treflectedLight.indirectSpecular += indirectSpecular;\n\treflectedLight.indirectDiffuse += indirectDiffuse;\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}"; 402 403var 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\tvec3 iridescenceFresnelDielectric = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tvec3 iridescenceFresnelMetallic = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.diffuseColor );\n\t\tmaterial.iridescenceFresnel = mix( iridescenceFresnelDielectric, iridescenceFresnelMetallic, material.metalness );\n\t\tmaterial.iridescenceF0Dielectric = Schlick_to_F0( iridescenceFresnelDielectric, 1.0, dotNVi );\n\t\tmaterial.iridescenceF0Metallic = Schlick_to_F0( iridescenceFresnelMetallic, 1.0, dotNVi );\n\t}\n#endif\n#ifdef STANDARD\n\tfloat dotNVms = saturate( dot( geometryNormal, geometryViewDir ) );\n\tmaterial.dfg = texture2D( dfgLUT, vec2( material.roughness, dotNVms ) ).rg;\n\t#if ( NUM_SUN_LIGHTS > 0 || NUM_DIR_LIGHTS > 0 || NUM_POINT_LIGHTS > 0 || NUM_SPOT_LIGHTS > 0 )\n\t\tfloat EssMs = material.dfg.x + material.dfg.y;\n\t\tmaterial.multiScatteringCompensation = 1.0 + material.specularColorBlended * ( 1.0 / EssMs - 1.0 );\n\t#endif\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 ) && ( defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_BASIC ) )\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_SUN_LIGHTS > 0 ) && defined( RE_Direct )\n\tSunLight sunLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SUN_LIGHT_SHADOWS > 0\n\tSunLightShadow sunLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SUN_LIGHTS; i ++ ) {\n\t\tsunLight = sunLights[ i ];\n\t\tgetSunLightInfo( sunLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SUN_LIGHT_SHADOWS )\n\t\tsunLightShadow = sunLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getSunShadow( sunShadowMap[ i ], sunLightShadow, UNROLLED_LOOP_INDEX ) : 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\t#ifdef USE_LIGHT_PROBES_GRID\n\t\tvec3 probeWorldPos = ( ( vec4( geometryPosition, 1.0 ) - viewMatrix[ 3 ] ) * viewMatrix ).xyz;\n\t\tvec3 probeWorldNormal = transformNormalByInverseViewMatrix( geometryNormal, viewMatrix );\n\t\tirradiance += getLightProbeGridIrradiance( probeWorldPos, probeWorldNormal );\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; 404 405var 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( ENVMAP_TYPE_CUBE_UV )\n\t\t#if defined( STANDARD ) || defined( LAMBERT ) || defined( PHONG )\n\t\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t\t#endif\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 iblRadiance = getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tvec3 iblRadiance = getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_RETROREFLECTION\n\t\t#ifdef USE_ANISOTROPY\n\t\t\tvec3 retroIBLRadiance = getIBLAnisotropyRetroRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t\t#else\n\t\t\tvec3 retroIBLRadiance = getIBLRetroRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t\t#endif\n\t\tiblRadiance = mix( iblRadiance, retroIBLRadiance, saturate( material.retroreflectivity ) );\n\t#endif\n\tradiance += iblRadiance;\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; 406 407var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\t#if defined( LAMBERT ) || defined( PHONG )\n\t\tirradiance += iblIrradiance;\n\t#endif\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"; 408 409var lightprobes_pars_fragment = "#ifdef USE_LIGHT_PROBES_GRID\nuniform highp sampler3D probesSH;\nuniform vec3 probesMin;\nuniform vec3 probesMax;\nuniform vec3 probesResolution;\nvec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) {\n\tvec3 res = probesResolution;\n\tvec3 gridRange = probesMax - probesMin;\n\tvec3 resMinusOne = res - 1.0;\n\tvec3 probeSpacing = gridRange / resMinusOne;\n\tvec3 samplePos = worldPos + worldNormal * probeSpacing * 0.5;\n\tvec3 uvw = clamp( ( samplePos - probesMin ) / gridRange, 0.0, 1.0 );\n\tuvw = uvw * resMinusOne / res + 0.5 / res;\n\tfloat nz = res.z;\n\tfloat paddedSlices = nz + 2.0;\n\tfloat atlasDepth = 7.0 * paddedSlices;\n\tfloat uvZBase = uvw.z * nz + 1.0;\n\tvec4 s0 = texture( probesSH, vec3( uvw.xy, ( uvZBase ) / atlasDepth ) );\n\tvec4 s1 = texture( probesSH, vec3( uvw.xy, ( uvZBase + paddedSlices ) / atlasDepth ) );\n\tvec4 s2 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 2.0 * paddedSlices ) / atlasDepth ) );\n\tvec4 s3 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 3.0 * paddedSlices ) / atlasDepth ) );\n\tvec4 s4 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 4.0 * paddedSlices ) / atlasDepth ) );\n\tvec4 s5 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 5.0 * paddedSlices ) / atlasDepth ) );\n\tvec4 s6 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 6.0 * paddedSlices ) / atlasDepth ) );\n\tvec3 c0 = s0.xyz;\n\tvec3 c1 = vec3( s0.w, s1.xy );\n\tvec3 c2 = vec3( s1.zw, s2.x );\n\tvec3 c3 = s2.yzw;\n\tvec3 c4 = s3.xyz;\n\tvec3 c5 = vec3( s3.w, s4.xy );\n\tvec3 c6 = vec3( s4.zw, s5.x );\n\tvec3 c7 = s5.yzw;\n\tvec3 c8 = s6.xyz;\n\tfloat x = worldNormal.x, y = worldNormal.y, z = worldNormal.z;\n\tvec3 result = c0 * 0.886227;\n\tresult += c1 * 2.0 * 0.511664 * y;\n\tresult += c2 * 2.0 * 0.511664 * z;\n\tresult += c3 * 2.0 * 0.511664 * x;\n\tresult += c4 * 2.0 * 0.429043 * x * y;\n\tresult += c5 * 2.0 * 0.429043 * y * z;\n\tresult += c6 * ( 0.743125 * z * z - 0.247708 );\n\tresult += c7 * 2.0 * 0.429043 * x * z;\n\tresult += c8 * 0.429043 * ( x * x - y * y );\n\treturn max( result, vec3( 0.0 ) );\n}\n#endif"; 410 411var logdepthbuf_fragment = "#if defined( USE_LOGARITHMIC_DEPTH_BUFFER )\n\tgl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; 412 413var logdepthbuf_pars_fragment = "#if defined( USE_LOGARITHMIC_DEPTH_BUFFER )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; 414 415var logdepthbuf_pars_vertex = "#ifdef USE_LOGARITHMIC_DEPTH_BUFFER\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; 416 417var logdepthbuf_vertex = "#ifdef USE_LOGARITHMIC_DEPTH_BUFFER\n\tvFragDepth = 1.0 + gl_Position.w;\n\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n#endif"; 418 419var 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"; 420 421var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; 422 423var 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"; 424 425var 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"; 426 427var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; 428 429var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; 430 431var 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"; 432 433var 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"; 434 435var 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"; 436 437var 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"; 438 439var 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"; 440 441var 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#ifdef DOUBLE_SIDED\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#ifdef DOUBLE_SIDED\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;"; 442 443var 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\t#if defined( USE_PACKED_NORMALMAP )\n\t\tmapN = vec3( mapN.xy, sqrt( saturate( 1.0 - dot( mapN.xy, mapN.xy ) ) ) );\n\t#endif\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; 444 445var 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"; 446 447var 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"; 448 449var 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\t#ifdef FLIP_SIDED\n\t\t\tvBitangent = - vBitangent;\n\t\t#endif\n\t#endif\n#endif"; 450 451var 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"; 452 453var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; 454 455var 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"; 456 457var 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"; 458 459var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; 460 461var 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 );"; 462 463var 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\t#ifdef USE_REVERSED_DEPTH_BUFFER\n\t\n\t\treturn depth * ( far - near ) - far;\n\t#else\n\t\treturn depth * ( near - far ) - near;\n\t#endif\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\t\n\t#ifdef USE_REVERSED_DEPTH_BUFFER\n\t\treturn ( near * far ) / ( ( near - far ) * depth - near );\n\t#else\n\t\treturn ( near * far ) / ( ( far - near ) * depth - far );\n\t#endif\n}"; 464 465var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; 466 467var 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;"; 468 469var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; 470 471var 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"; 472 473var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; 474 475var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; 476 477var 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_SUN_LIGHT_SHADOWS > 0\n\t\t#define SUN_LIGHT_CASCADES 2\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tuniform sampler2DShadow sunShadowMap[ NUM_SUN_LIGHT_SHADOWS ];\n\t\t#else\n\t\t\tuniform sampler2D sunShadowMap[ NUM_SUN_LIGHT_SHADOWS ];\n\t\t#endif\n\t\tuniform mat4 sunShadowMatrix[ NUM_SUN_LIGHT_SHADOWS * SUN_LIGHT_CASCADES ];\n\t\tuniform vec4 sunShadowCascade[ NUM_SUN_LIGHT_SHADOWS * SUN_LIGHT_CASCADES ];\n\t\tvarying vec4 vSunShadowWorldPosition;\n\t\tvarying vec3 vSunShadowWorldNormal;\n\t\tstruct SunLightShadow {\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 SunLightShadow sunLightShadows[ NUM_SUN_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tuniform sampler2DShadow directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\t#else\n\t\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\t#endif\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\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tuniform sampler2DShadow spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\t#else\n\t\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\t#endif\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\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tuniform samplerCubeShadow pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\t#elif defined( SHADOWMAP_TYPE_BASIC )\n\t\t\tuniform samplerCube pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\t#endif\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\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\tfloat interleavedGradientNoise( vec2 position ) {\n\t\t\treturn fract( 52.9829189 * fract( dot( position, vec2( 0.06711056, 0.00583715 ) ) ) );\n\t\t}\n\t\tvec2 vogelDiskSample( int sampleIndex, int samplesCount, float phi ) {\n\t\t\tconst float goldenAngle = 2.399963229728653;\n\t\t\tfloat r = sqrt( ( float( sampleIndex ) + 0.5 ) / float( samplesCount ) );\n\t\t\tfloat theta = float( sampleIndex ) * goldenAngle + phi;\n\t\t\treturn vec2( cos( theta ), sin( theta ) ) * r;\n\t\t}\n\t#endif\n\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\tfloat getShadow( sampler2DShadow shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\t\tfloat shadow = 1.0;\n\t\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\t\tshadowCoord.z += shadowBias;\n\t\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\t\tif ( frustumTest ) {\n\t\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\t\tfloat radius = shadowRadius * texelSize.x;\n\t\t\t\tfloat phi = interleavedGradientNoise( gl_FragCoord.xy ) * PI2;\n\t\t\t\tshadow = (\n\t\t\t\t\ttexture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 0, 5, phi ) * radius, shadowCoord.z ) ) +\n\t\t\t\t\ttexture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 1, 5, phi ) * radius, shadowCoord.z ) ) +\n\t\t\t\t\ttexture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 2, 5, phi ) * radius, shadowCoord.z ) ) +\n\t\t\t\t\ttexture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 3, 5, phi ) * radius, shadowCoord.z ) ) +\n\t\t\t\t\ttexture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 4, 5, phi ) * radius, shadowCoord.z ) )\n\t\t\t\t) * 0.2;\n\t\t\t}\n\t\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t\t}\n\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\t\tfloat shadow = 1.0;\n\t\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\t\t#ifdef USE_REVERSED_DEPTH_BUFFER\n\t\t\t\tshadowCoord.z -= shadowBias;\n\t\t\t#else\n\t\t\t\tshadowCoord.z += shadowBias;\n\t\t\t#endif\n\t\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\t\tif ( frustumTest ) {\n\t\t\t\tvec2 distribution = texture2D( shadowMap, shadowCoord.xy ).rg;\n\t\t\t\tfloat mean = distribution.x;\n\t\t\t\tfloat variance = distribution.y * distribution.y;\n\t\t\t\t#ifdef USE_REVERSED_DEPTH_BUFFER\n\t\t\t\t\tfloat hard_shadow = step( mean, shadowCoord.z );\n\t\t\t\t#else\n\t\t\t\t\tfloat hard_shadow = step( shadowCoord.z, mean );\n\t\t\t\t#endif\n\t\t\t\t\n\t\t\t\tif ( hard_shadow == 1.0 ) {\n\t\t\t\t\tshadow = 1.0;\n\t\t\t\t} else {\n\t\t\t\t\tvariance = max( variance, 0.0000001 );\n\t\t\t\t\tfloat d = shadowCoord.z - mean;\n\t\t\t\t\tfloat p_max = variance / ( variance + d * d );\n\t\t\t\t\tp_max = clamp( ( p_max - 0.3 ) / 0.65, 0.0, 1.0 );\n\t\t\t\t\tshadow = max( hard_shadow, p_max );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t\t}\n\t#else\n\t\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\t\tfloat shadow = 1.0;\n\t\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\t\t#ifdef USE_REVERSED_DEPTH_BUFFER\n\t\t\t\tshadowCoord.z -= shadowBias;\n\t\t\t#else\n\t\t\t\tshadowCoord.z += shadowBias;\n\t\t\t#endif\n\t\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\t\tif ( frustumTest ) {\n\t\t\t\tfloat depth = texture2D( shadowMap, shadowCoord.xy ).r;\n\t\t\t\t#ifdef USE_REVERSED_DEPTH_BUFFER\n\t\t\t\t\tshadow = step( depth, shadowCoord.z );\n\t\t\t\t#else\n\t\t\t\t\tshadow = step( shadowCoord.z, depth );\n\t\t\t\t#endif\n\t\t\t}\n\t\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t\t}\n\t#endif\n\t#if NUM_SUN_LIGHT_SHADOWS > 0\n\t\tfloat getSunShadow(\n\t\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\t\tsampler2DShadow shadowMap,\n\t\t\t#else\n\t\t\t\tsampler2D shadowMap,\n\t\t\t#endif\n\t\t\tSunLightShadow sunLightShadow,\n\t\t\tint shadowIndex\n\t\t) {\n\t\t\tvec4 shadowWorldPosition = vec4( vSunShadowWorldPosition.xyz + vSunShadowWorldNormal * sunLightShadow.shadowNormalBias, 1.0 );\n\t\t\tfloat viewDepth = vSunShadowWorldPosition.w;\n\t\t\tint cascadeOffset = shadowIndex * SUN_LIGHT_CASCADES;\n\t\t\tfloat shadow = 1.0;\n\t\t\tfor ( int i = SUN_LIGHT_CASCADES - 1; i >= 0; i -- ) {\n\t\t\t\tvec4 cascade = sunShadowCascade[ cascadeOffset + i ];\n\t\t\t\tif ( viewDepth >= cascade.x && viewDepth < cascade.y ) {\n\t\t\t\t\tfloat cascadeShadow = getShadow(\n\t\t\t\t\t\tshadowMap,\n\t\t\t\t\t\tsunLightShadow.shadowMapSize,\n\t\t\t\t\t\tsunLightShadow.shadowIntensity,\n\t\t\t\t\t\tsunLightShadow.shadowBias,\n\t\t\t\t\t\tsunLightShadow.shadowRadius,\n\t\t\t\t\t\tsunShadowMatrix[ cascadeOffset + i ] * shadowWorldPosition\n\t\t\t\t\t);\n\t\t\t\t\tshadow = mix( cascadeShadow, shadow, smoothstep( cascade.z, cascade.y, viewDepth ) );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn shadow;\n\t\t}\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#if defined( SHADOWMAP_TYPE_PCF )\n\tfloat getPointShadow( samplerCubeShadow 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\tvec3 bd3D = normalize( lightToPosition );\n\t\tvec3 absVec = abs( lightToPosition );\n\t\tfloat viewSpaceZ = max( max( absVec.x, absVec.y ), absVec.z );\n\t\tif ( viewSpaceZ - shadowCameraFar <= 0.0 && viewSpaceZ - shadowCameraNear >= 0.0 ) {\n\t\t\t#ifdef USE_REVERSED_DEPTH_BUFFER\n\t\t\t\tfloat dp = ( shadowCameraNear * ( shadowCameraFar - viewSpaceZ ) ) / ( viewSpaceZ * ( shadowCameraFar - shadowCameraNear ) );\n\t\t\t\tdp -= shadowBias;\n\t\t\t#else\n\t\t\t\tfloat dp = ( shadowCameraFar * ( viewSpaceZ - shadowCameraNear ) ) / ( viewSpaceZ * ( shadowCameraFar - shadowCameraNear ) );\n\t\t\t\tdp += shadowBias;\n\t\t\t#endif\n\t\t\tfloat texelSize = shadowRadius / shadowMapSize.x;\n\t\t\tvec3 absDir = abs( bd3D );\n\t\t\tvec3 tangent = absDir.x > absDir.z ? vec3( 0.0, 1.0, 0.0 ) : vec3( 1.0, 0.0, 0.0 );\n\t\t\ttangent = normalize( cross( bd3D, tangent ) );\n\t\t\tvec3 bitangent = cross( bd3D, tangent );\n\t\t\tfloat phi = interleavedGradientNoise( gl_FragCoord.xy ) * PI2;\n\t\t\tvec2 sample0 = vogelDiskSample( 0, 5, phi );\n\t\t\tvec2 sample1 = vogelDiskSample( 1, 5, phi );\n\t\t\tvec2 sample2 = vogelDiskSample( 2, 5, phi );\n\t\t\tvec2 sample3 = vogelDiskSample( 3, 5, phi );\n\t\t\tvec2 sample4 = vogelDiskSample( 4, 5, phi );\n\t\t\tshadow = (\n\t\t\t\ttexture( shadowMap, vec4( bd3D + ( tangent * sample0.x + bitangent * sample0.y ) * texelSize, dp ) ) +\n\t\t\t\ttexture( shadowMap, vec4( bd3D + ( tangent * sample1.x + bitangent * sample1.y ) * texelSize, dp ) ) +\n\t\t\t\ttexture( shadowMap, vec4( bd3D + ( tangent * sample2.x + bitangent * sample2.y ) * texelSize, dp ) ) +\n\t\t\t\ttexture( shadowMap, vec4( bd3D + ( tangent * sample3.x + bitangent * sample3.y ) * texelSize, dp ) ) +\n\t\t\t\ttexture( shadowMap, vec4( bd3D + ( tangent * sample4.x + bitangent * sample4.y ) * texelSize, dp ) )\n\t\t\t) * 0.2;\n\t\t}\n\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t}\n\t#elif defined( SHADOWMAP_TYPE_BASIC )\n\tfloat getPointShadow( samplerCube 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\tvec3 absVec = abs( lightToPosition );\n\t\tfloat viewSpaceZ = max( max( absVec.x, absVec.y ), absVec.z );\n\t\tif ( viewSpaceZ - shadowCameraFar <= 0.0 && viewSpaceZ - shadowCameraNear >= 0.0 ) {\n\t\t\tfloat dp = ( shadowCameraFar * ( viewSpaceZ - shadowCameraNear ) ) / ( viewSpaceZ * ( shadowCameraFar - shadowCameraNear ) );\n\t\t\tdp += shadowBias;\n\t\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t\tfloat depth = textureCube( shadowMap, bd3D ).r;\n\t\t\t#ifdef USE_REVERSED_DEPTH_BUFFER\n\t\t\t\tdepth = 1.0 - depth;\n\t\t\t#endif\n\t\t\tshadow = step( dp, depth );\n\t\t}\n\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t}\n\t#endif\n\t#endif\n#endif"; 478 479var 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_SUN_LIGHT_SHADOWS > 0\n\t\tvarying vec4 vSunShadowWorldPosition;\n\t\tvarying vec3 vSunShadowWorldNormal;\n\t#endif\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"; 480 481var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SUN_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\t#ifdef HAS_NORMAL\n\t\tvec3 shadowWorldNormal = transformNormalByInverseViewMatrix( transformedNormal, viewMatrix );\n\t#else\n\t\tvec3 shadowWorldNormal = vec3( 0.0 );\n\t#endif\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_SUN_LIGHT_SHADOWS > 0\n\t\tvSunShadowWorldPosition = vec4( worldPosition.xyz, - mvPosition.z );\n\t\tvSunShadowWorldNormal = shadowWorldNormal;\n\t#endif\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"; 482 483var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_SUN_LIGHT_SHADOWS > 0\n\tSunLightShadow sunLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SUN_LIGHT_SHADOWS; i ++ ) {\n\t\tsunLight = sunLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getSunShadow( sunShadowMap[ i ], sunLight, UNROLLED_LOOP_INDEX ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\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 && ( defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_BASIC ) )\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}"; 484 485var 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"; 486 487var 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"; 488 489var 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"; 490 491var 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"; 492 493var 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"; 494 495var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; 496 497var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; 498 499var 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; }"; 500 501var 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 = transformNormalByInverseViewMatrix( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseContribution, material.specularColorBlended, 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"; 502 503var 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"; 504 505var 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"; 506 507var 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"; 508 509var 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"; 510 511var 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"; 512 513const vertex$h = "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}"; 514 515const fragment$h = "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 <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}"; 516 517const vertex$g = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}"; 518 519const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nuniform mat3 backgroundRotation;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, backgroundRotation * vWorldDirection );\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 <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}"; 520 521const vertex$f = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}"; 522 523const fragment$f = "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 <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}"; 524 525const vertex$e = "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <skinbase_vertex>\n\t#include <morphinstance_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvHighPrecisionZW = gl_Position.zw;\n}"; 526 527const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <clipping_planes_fragment>\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <logdepthbuf_fragment>\n\t#ifdef USE_REVERSED_DEPTH_BUFFER\n\t\tfloat fragCoordZ = vHighPrecisionZW[ 0 ] / vHighPrecisionZW[ 1 ];\n\t#else\n\t\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[ 0 ] / vHighPrecisionZW[ 1 ] + 0.5;\n\t#endif\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}"; 528 529const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <skinbase_vertex>\n\t#include <morphinstance_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition.xyz;\n}"; 530 531const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <clipping_planes_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = vec4( dist, 0.0, 0.0, 1.0 );\n}"; 532 533const vertex$c = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}"; 534 535const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}"; 536 537const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}"; 538 539const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}"; 540 541const vertex$a = "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinbase_vertex>\n\t\t#include <skinnormal_vertex>\n\t\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}"; 542 543const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\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 <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 544 545const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}"; 546 547const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <cube_uv_reflection_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <envmap_physical_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_lambert_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_lambert_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 548 549const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}"; 550 551const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <normal_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\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 <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 552 553const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; 554 555const fragment$7 = "#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 <uv_pars_fragment>\n#include <normal_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity );\n\t#include <clipping_planes_fragment>\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tgl_FragColor = vec4( normalize( normal ) * 0.5 + 0.5, diffuseColor.a );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; 556 557const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}"; 558 559const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <cube_uv_reflection_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <envmap_physical_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 560 561const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; 562 563const fragment$5 = "#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_RETROREFLECTION\n\tuniform float retroreflectivity;\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 <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <iridescence_fragment>\n#include <cube_uv_reflection_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_physical_pars_fragment>\n#include <fog_pars_fragment>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_physical_pars_fragment>\n#include <transmission_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <clearcoat_pars_fragment>\n#include <iridescence_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <clearcoat_normal_fragment_begin>\n\t#include <clearcoat_normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include <transmission_fragment>\n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n \n\t\toutgoingLight = outgoingLight + sheenSpecularDirect + sheenSpecularIndirect;\n \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 <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 564 565const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}"; 566 567const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_toon_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_toon_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 568 569const vertex$3 = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\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 <color_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\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 <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n}"; 570 571const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}"; 572 573const vertex$2 = "#include <common>\n#include <batching_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphinstance_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}"; 574 575const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <logdepthbuf_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}"; 576 577const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\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 <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}"; 578 579const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}"; 580 581const ShaderChunk = { 582 alphahash_fragment: alphahash_fragment, 583 alphahash_pars_fragment: alphahash_pars_fragment, 584 alphamap_fragment: alphamap_fragment, 585 alphamap_pars_fragment: alphamap_pars_fragment, 586 alphatest_fragment: alphatest_fragment, 587 alphatest_pars_fragment: alphatest_pars_fragment, 588 aomap_fragment: aomap_fragment, 589 aomap_pars_fragment: aomap_pars_fragment, 590 batching_pars_vertex: batching_pars_vertex, 591 batching_vertex: batching_vertex, 592 begin_vertex: begin_vertex, 593 beginnormal_vertex: beginnormal_vertex, 594 bsdfs: bsdfs, 595 iridescence_fragment: iridescence_fragment, 596 bumpmap_pars_fragment: bumpmap_pars_fragment, 597 clipping_planes_fragment: clipping_planes_fragment, 598 clipping_planes_pars_fragment: clipping_planes_pars_fragment, 599 clipping_planes_pars_vertex: clipping_planes_pars_vertex, 600 clipping_planes_vertex: clipping_planes_vertex, 601 color_fragment: color_fragment, 602 color_pars_fragment: color_pars_fragment, 603 color_pars_vertex: color_pars_vertex, 604 color_vertex: color_vertex, 605 common: common, 606 cube_uv_reflection_fragment: cube_uv_reflection_fragment, 607 defaultnormal_vertex: defaultnormal_vertex, 608 displacementmap_pars_vertex: displacementmap_pars_vertex, 609 displacementmap_vertex: displacementmap_vertex, 610 emissivemap_fragment: emissivemap_fragment, 611 emissivemap_pars_fragment: emissivemap_pars_fragment, 612 colorspace_fragment: colorspace_fragment, 613 colorspace_pars_fragment: colorspace_pars_fragment, 614 envmap_fragment: envmap_fragment, 615 envmap_common_pars_fragment: envmap_common_pars_fragment, 616 envmap_pars_fragment: envmap_pars_fragment, 617 envmap_pars_vertex: envmap_pars_vertex, 618 envmap_physical_pars_fragment: envmap_physical_pars_fragment, 619 envmap_vertex: envmap_vertex, 620 fog_vertex: fog_vertex, 621 fog_pars_vertex: fog_pars_vertex, 622 fog_fragment: fog_fragment, 623 fog_pars_fragment: fog_pars_fragment, 624 gradientmap_pars_fragment: gradientmap_pars_fragment, 625 lightmap_pars_fragment: lightmap_pars_fragment, 626 lights_lambert_fragment: lights_lambert_fragment, 627 lights_lambert_pars_fragment: lights_lambert_pars_fragment, 628 lights_pars_begin: lights_pars_begin, 629 lights_toon_fragment: lights_toon_fragment, 630 lights_toon_pars_fragment: lights_toon_pars_fragment, 631 lights_phong_fragment: lights_phong_fragment, 632 lights_phong_pars_fragment: lights_phong_pars_fragment, 633 lights_physical_fragment: lights_physical_fragment, 634 lights_physical_pars_fragment: lights_physical_pars_fragment, 635 lights_fragment_begin: lights_fragment_begin, 636 lights_fragment_maps: lights_fragment_maps, 637 lights_fragment_end: lights_fragment_end, 638 lightprobes_pars_fragment: lightprobes_pars_fragment, 639 logdepthbuf_fragment: logdepthbuf_fragment, 640 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, 641 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, 642 logdepthbuf_vertex: logdepthbuf_vertex, 643 map_fragment: map_fragment, 644 map_pars_fragment: map_pars_fragment, 645 map_particle_fragment: map_particle_fragment, 646 map_particle_pars_fragment: map_particle_pars_fragment, 647 metalnessmap_fragment: metalnessmap_fragment, 648 metalnessmap_pars_fragment: metalnessmap_pars_fragment, 649 morphinstance_vertex: morphinstance_vertex, 650 morphcolor_vertex: morphcolor_vertex, 651 morphnormal_vertex: morphnormal_vertex, 652 morphtarget_pars_vertex: morphtarget_pars_vertex, 653 morphtarget_vertex: morphtarget_vertex, 654 normal_fragment_begin: normal_fragment_begin, 655 normal_fragment_maps: normal_fragment_maps, 656 normal_pars_fragment: normal_pars_fragment, 657 normal_pars_vertex: normal_pars_vertex, 658 normal_vertex: normal_vertex, 659 normalmap_pars_fragment: normalmap_pars_fragment, 660 clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, 661 clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, 662 clearcoat_pars_fragment: clearcoat_pars_fragment, 663 iridescence_pars_fragment: iridescence_pars_fragment, 664 opaque_fragment: opaque_fragment, 665 packing: packing, 666 premultiplied_alpha_fragment: premultiplied_alpha_fragment, 667 project_vertex: project_vertex, 668 dithering_fragment: dithering_fragment, 669 dithering_pars_fragment: dithering_pars_fragment, 670 roughnessmap_fragment: roughnessmap_fragment, 671 roughnessmap_pars_fragment: roughnessmap_pars_fragment, 672 shadowmap_pars_fragment: shadowmap_pars_fragment, 673 shadowmap_pars_vertex: shadowmap_pars_vertex, 674 shadowmap_vertex: shadowmap_vertex, 675 shadowmask_pars_fragment: shadowmask_pars_fragment, 676 skinbase_vertex: skinbase_vertex, 677 skinning_pars_vertex: skinning_pars_vertex, 678 skinning_vertex: skinning_vertex, 679 skinnormal_vertex: skinnormal_vertex, 680 specularmap_fragment: specularmap_fragment, 681 specularmap_pars_fragment: specularmap_pars_fragment, 682 tonemapping_fragment: tonemapping_fragment, 683 tonemapping_pars_fragment: tonemapping_pars_fragment, 684 transmission_fragment: transmission_fragment, 685 transmission_pars_fragment: transmission_pars_fragment, 686 uv_pars_fragment: uv_pars_fragment, 687 uv_pars_vertex: uv_pars_vertex, 688 uv_vertex: uv_vertex, 689 worldpos_vertex: worldpos_vertex, 690 691 background_vert: vertex$h, 692 background_frag: fragment$h, 693 backgroundCube_vert: vertex$g, 694 backgroundCube_frag: fragment$g, 695 cube_vert: vertex$f, 696 cube_frag: fragment$f, 697 depth_vert: vertex$e, 698 depth_frag: fragment$e, 699 distance_vert: vertex$d, 700 distance_frag: fragment$d, 701 equirect_vert: vertex$c, 702 equirect_frag: fragment$c, 703 linedashed_vert: vertex$b, 704 linedashed_frag: fragment$b, 705 meshbasic_vert: vertex$a, 706 meshbasic_frag: fragment$a, 707 meshlambert_vert: vertex$9, 708 meshlambert_frag: fragment$9, 709 meshmatcap_vert: vertex$8, 710 meshmatcap_frag: fragment$8, 711 meshnormal_vert: vertex$7, 712 meshnormal_frag: fragment$7, 713 meshphong_vert: vertex$6, 714 meshphong_frag: fragment$6, 715 meshphysical_vert: vertex$5, 716 meshphysical_frag: fragment$5, 717 meshtoon_vert: vertex$4, 718 meshtoon_frag: fragment$4, 719 points_vert: vertex$3, 720 points_frag: fragment$3, 721 shadow_vert: vertex$2, 722 shadow_frag: fragment$2, 723 sprite_vert: vertex$1, 724 sprite_frag: fragment$1 725}; 726 727// Uniforms library for shared webgl shaders 728const UniformsLib = { 729 730 common: { 731 732 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, 733 opacity: { value: 1.0 }, 734 735 map: { value: null }, 736 mapTransform: { value: /*@__PURE__*/ new Matrix3() }, 737 738 alphaMap: { value: null }, 739 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 740 741 alphaTest: { value: 0 } 742 743 }, 744 745 specularmap: { 746 747 specularMap: { value: null }, 748 specularMapTransform: { value: /*@__PURE__*/ new Matrix3() } 749 750 }, 751 752 envmap: { 753 754 envMap: { value: null }, 755 envMapRotation: { value: /*@__PURE__*/ new Matrix3() }, 756 reflectivity: { value: 1.0 }, // basic, lambert, phong 757 ior: { value: 1.5 }, // physical 758 refractionRatio: { value: 0.98 }, // basic, lambert, phong 759 dfgLUT: { value: null } // DFG LUT for physically-based rendering 760 761 }, 762 763 aomap: { 764 765 aoMap: { value: null }, 766 aoMapIntensity: { value: 1 }, 767 aoMapTransform: { value: /*@__PURE__*/ new Matrix3() } 768 769 }, 770 771 lightmap: { 772 773 lightMap: { value: null }, 774 lightMapIntensity: { value: 1 }, 775 lightMapTransform: { value: /*@__PURE__*/ new Matrix3() } 776 777 }, 778 779 bumpmap: { 780 781 bumpMap: { value: null }, 782 bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 783 bumpScale: { value: 1 } 784 785 }, 786 787 normalmap: { 788 789 normalMap: { value: null }, 790 normalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 791 normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } 792 793 }, 794 795 displacementmap: { 796 797 displacementMap: { value: null }, 798 displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 799 displacementScale: { value: 1 }, 800 displacementBias: { value: 0 } 801 802 }, 803 804 emissivemap: { 805 806 emissiveMap: { value: null }, 807 emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() } 808 809 }, 810 811 metalnessmap: { 812 813 metalnessMap: { value: null }, 814 metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } 815 816 }, 817 818 roughnessmap: { 819 820 roughnessMap: { value: null }, 821 roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } 822 823 }, 824 825 gradientmap: { 826 827 gradientMap: { value: null } 828 829 }, 830 831 fog: { 832 833 fogDensity: { value: 0.00025 }, 834 fogNear: { value: 1 }, 835 fogFar: { value: 2000 }, 836 fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) } 837 838 }, 839 840 lights: { 841 842 ambientLightColor: { value: [] }, 843 844 lightProbe: { value: [] }, 845 846 sunLights: { value: [], properties: { 847 direction: {}, 848 color: {} 849 } }, 850 851 sunLightShadows: { value: [], properties: { 852 shadowIntensity: 1, 853 shadowBias: {}, 854 shadowNormalBias: {}, 855 shadowRadius: {}, 856 shadowMapSize: {} 857 } }, 858 859 sunShadowMatrix: { value: [] }, 860 sunShadowCascade: { value: [] }, 861 862 directionalLights: { value: [], properties: { 863 direction: {}, 864 color: {} 865 } }, 866 867 directionalLightShadows: { value: [], properties: { 868 shadowIntensity: 1, 869 shadowBias: {}, 870 shadowNormalBias: {}, 871 shadowRadius: {}, 872 shadowMapSize: {} 873 } }, 874 875 directionalShadowMatrix: { value: [] }, 876 877 spotLights: { value: [], properties: { 878 color: {}, 879 position: {}, 880 direction: {}, 881 distance: {}, 882 coneCos: {}, 883 penumbraCos: {}, 884 decay: {} 885 } }, 886 887 spotLightShadows: { value: [], properties: { 888 shadowIntensity: 1, 889 shadowBias: {}, 890 shadowNormalBias: {}, 891 shadowRadius: {}, 892 shadowMapSize: {} 893 } }, 894 895 spotLightMap: { value: [] }, 896 spotLightMatrix: { value: [] }, 897 898 pointLights: { value: [], properties: { 899 color: {}, 900 position: {}, 901 decay: {}, 902 distance: {} 903 } }, 904 905 pointLightShadows: { value: [], properties: { 906 shadowIntensity: 1, 907 shadowBias: {}, 908 shadowNormalBias: {}, 909 shadowRadius: {}, 910 shadowMapSize: {}, 911 shadowCameraNear: {}, 912 shadowCameraFar: {} 913 } }, 914 915 pointShadowMatrix: { value: [] }, 916 917 hemisphereLights: { value: [], properties: { 918 direction: {}, 919 skyColor: {}, 920 groundColor: {} 921 } }, 922 923 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src 924 rectAreaLights: { value: [], properties: { 925 color: {}, 926 position: {}, 927 width: {}, 928 height: {} 929 } }, 930 931 ltc_1: { value: null }, 932 ltc_2: { value: null }, 933 934 probesSH: { value: null }, 935 probesMin: { value: /*@__PURE__*/ new Vector3() }, 936 probesMax: { value: /*@__PURE__*/ new Vector3() }, 937 probesResolution: { value: /*@__PURE__*/ new Vector3() } 938 939 }, 940 941 points: { 942 943 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, 944 opacity: { value: 1.0 }, 945 size: { value: 1.0 }, 946 scale: { value: 1.0 }, 947 map: { value: null }, 948 alphaMap: { value: null }, 949 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 950 alphaTest: { value: 0 }, 951 uvTransform: { value: /*@__PURE__*/ new Matrix3() } 952 953 }, 954 955 sprite: { 956 957 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, 958 opacity: { value: 1.0 }, 959 center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, 960 rotation: { value: 0.0 }, 961 map: { value: null }, 962 mapTransform: { value: /*@__PURE__*/ new Matrix3() }, 963 alphaMap: { value: null }, 964 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 965 alphaTest: { value: 0 } 966 967 } 968 969}; 970 971const ShaderLib = { 972 973 basic: { 974 975 uniforms: /*@__PURE__*/ mergeUniforms( [ 976 UniformsLib.common, 977 UniformsLib.specularmap, 978 UniformsLib.envmap, 979 UniformsLib.aomap, 980 UniformsLib.lightmap, 981 UniformsLib.fog 982 ] ), 983 984 vertexShader: ShaderChunk.meshbasic_vert, 985 fragmentShader: ShaderChunk.meshbasic_frag 986 987 }, 988 989 lambert: { 990 991 uniforms: /*@__PURE__*/ mergeUniforms( [ 992 UniformsLib.common, 993 UniformsLib.specularmap, 994 UniformsLib.envmap, 995 UniformsLib.aomap, 996 UniformsLib.lightmap, 997 UniformsLib.emissivemap, 998 UniformsLib.bumpmap, 999 UniformsLib.normalmap, 1000 UniformsLib.displacementmap, 1001 UniformsLib.fog, 1002 UniformsLib.lights, 1003 { 1004 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 1005 envMapIntensity: { value: 1 } 1006 } 1007 ] ), 1008 1009 vertexShader: ShaderChunk.meshlambert_vert, 1010 fragmentShader: ShaderChunk.meshlambert_frag 1011 1012 }, 1013 1014 phong: { 1015 1016 uniforms: /*@__PURE__*/ mergeUniforms( [ 1017 UniformsLib.common, 1018 UniformsLib.specularmap, 1019 UniformsLib.envmap, 1020 UniformsLib.aomap, 1021 UniformsLib.lightmap, 1022 UniformsLib.emissivemap, 1023 UniformsLib.bumpmap, 1024 UniformsLib.normalmap, 1025 UniformsLib.displacementmap, 1026 UniformsLib.fog, 1027 UniformsLib.lights, 1028 { 1029 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 1030 specular: { value: /*@__PURE__*/ new Color( 0x111111 ) }, 1031 shininess: { value: 30 }, 1032 envMapIntensity: { value: 1 } 1033 } 1034 ] ), 1035 1036 vertexShader: ShaderChunk.meshphong_vert, 1037 fragmentShader: ShaderChunk.meshphong_frag 1038 1039 }, 1040 1041 standard: { 1042 1043 uniforms: /*@__PURE__*/ mergeUniforms( [ 1044 UniformsLib.common, 1045 UniformsLib.envmap, 1046 UniformsLib.aomap, 1047 UniformsLib.lightmap, 1048 UniformsLib.emissivemap, 1049 UniformsLib.bumpmap, 1050 UniformsLib.normalmap, 1051 UniformsLib.displacementmap, 1052 UniformsLib.roughnessmap, 1053 UniformsLib.metalnessmap, 1054 UniformsLib.fog, 1055 UniformsLib.lights, 1056 { 1057 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 1058 roughness: { value: 1.0 }, 1059 metalness: { value: 0.0 }, 1060 envMapIntensity: { value: 1 } 1061 } 1062 ] ), 1063 1064 vertexShader: ShaderChunk.meshphysical_vert, 1065 fragmentShader: ShaderChunk.meshphysical_frag 1066 1067 }, 1068 1069 toon: { 1070 1071 uniforms: /*@__PURE__*/ mergeUniforms( [ 1072 UniformsLib.common, 1073 UniformsLib.aomap, 1074 UniformsLib.lightmap, 1075 UniformsLib.emissivemap, 1076 UniformsLib.bumpmap, 1077 UniformsLib.normalmap, 1078 UniformsLib.displacementmap, 1079 UniformsLib.gradientmap, 1080 UniformsLib.fog, 1081 UniformsLib.lights, 1082 { 1083 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } 1084 } 1085 ] ), 1086 1087 vertexShader: ShaderChunk.meshtoon_vert, 1088 fragmentShader: ShaderChunk.meshtoon_frag 1089 1090 }, 1091 1092 matcap: { 1093 1094 uniforms: /*@__PURE__*/ mergeUniforms( [ 1095 UniformsLib.common, 1096 UniformsLib.bumpmap, 1097 UniformsLib.normalmap, 1098 UniformsLib.displacementmap, 1099 UniformsLib.fog, 1100 { 1101 matcap: { value: null } 1102 } 1103 ] ), 1104 1105 vertexShader: ShaderChunk.meshmatcap_vert, 1106 fragmentShader: ShaderChunk.meshmatcap_frag 1107 1108 }, 1109 1110 points: { 1111 1112 uniforms: /*@__PURE__*/ mergeUniforms( [ 1113 UniformsLib.points, 1114 UniformsLib.fog 1115 ] ), 1116 1117 vertexShader: ShaderChunk.points_vert, 1118 fragmentShader: ShaderChunk.points_frag 1119 1120 }, 1121 1122 dashed: { 1123 1124 uniforms: /*@__PURE__*/ mergeUniforms( [ 1125 UniformsLib.common, 1126 UniformsLib.fog, 1127 { 1128 scale: { value: 1 }, 1129 dashSize: { value: 1 }, 1130 totalSize: { value: 2 } 1131 } 1132 ] ), 1133 1134 vertexShader: ShaderChunk.linedashed_vert, 1135 fragmentShader: ShaderChunk.linedashed_frag 1136 1137 }, 1138 1139 depth: { 1140 1141 uniforms: /*@__PURE__*/ mergeUniforms( [ 1142 UniformsLib.common, 1143 UniformsLib.displacementmap 1144 ] ), 1145 1146 vertexShader: ShaderChunk.depth_vert, 1147 fragmentShader: ShaderChunk.depth_frag 1148 1149 }, 1150 1151 normal: { 1152 1153 uniforms: /*@__PURE__*/ mergeUniforms( [ 1154 UniformsLib.common, 1155 UniformsLib.bumpmap, 1156 UniformsLib.normalmap, 1157 UniformsLib.displacementmap, 1158 { 1159 opacity: { value: 1.0 } 1160 } 1161 ] ), 1162 1163 vertexShader: ShaderChunk.meshnormal_vert, 1164 fragmentShader: ShaderChunk.meshnormal_frag 1165 1166 }, 1167 1168 sprite: { 1169 1170 uniforms: /*@__PURE__*/ mergeUniforms( [ 1171 UniformsLib.sprite, 1172 UniformsLib.fog 1173 ] ), 1174 1175 vertexShader: ShaderChunk.sprite_vert, 1176 fragmentShader: ShaderChunk.sprite_frag 1177 1178 }, 1179 1180 background: { 1181 1182 uniforms: { 1183 uvTransform: { value: /*@__PURE__*/ new Matrix3() }, 1184 t2D: { value: null }, 1185 backgroundIntensity: { value: 1 } 1186 }, 1187 1188 vertexShader: ShaderChunk.background_vert, 1189 fragmentShader: ShaderChunk.background_frag 1190 1191 }, 1192 1193 backgroundCube: { 1194 1195 uniforms: { 1196 envMap: { value: null }, 1197 backgroundBlurriness: { value: 0 }, 1198 backgroundIntensity: { value: 1 }, 1199 backgroundRotation: { value: /*@__PURE__*/ new Matrix3() } 1200 }, 1201 1202 vertexShader: ShaderChunk.backgroundCube_vert, 1203 fragmentShader: ShaderChunk.backgroundCube_frag 1204 1205 }, 1206 1207 cube: { 1208 1209 uniforms: { 1210 tCube: { value: null }, 1211 tFlip: { value: -1 }, 1212 opacity: { value: 1.0 } 1213 }, 1214 1215 vertexShader: ShaderChunk.cube_vert, 1216 fragmentShader: ShaderChunk.cube_frag 1217 1218 }, 1219 1220 equirect: { 1221 1222 uniforms: { 1223 tEquirect: { value: null }, 1224 }, 1225 1226 vertexShader: ShaderChunk.equirect_vert, 1227 fragmentShader: ShaderChunk.equirect_frag 1228 1229 }, 1230 1231 distance: { 1232 1233 uniforms: /*@__PURE__*/ mergeUniforms( [ 1234 UniformsLib.common, 1235 UniformsLib.displacementmap, 1236 { 1237 referencePosition: { value: /*@__PURE__*/ new Vector3() }, 1238 nearDistance: { value: 1 }, 1239 farDistance: { value: 1000 } 1240 } 1241 ] ), 1242 1243 vertexShader: ShaderChunk.distance_vert, 1244 fragmentShader: ShaderChunk.distance_frag 1245 1246 }, 1247 1248 shadow: { 1249 1250 uniforms: /*@__PURE__*/ mergeUniforms( [ 1251 UniformsLib.lights, 1252 UniformsLib.fog, 1253 { 1254 color: { value: /*@__PURE__*/ new Color( 0x00000 ) }, 1255 opacity: { value: 1.0 } 1256 }, 1257 ] ), 1258 1259 vertexShader: ShaderChunk.shadow_vert, 1260 fragmentShader: ShaderChunk.shadow_frag 1261 1262 } 1263 1264}; 1265 1266ShaderLib.physical = { 1267 1268 uniforms: /*@__PURE__*/ mergeUniforms( [ 1269 ShaderLib.standard.uniforms, 1270 { 1271 clearcoat: { value: 0 }, 1272 clearcoatMap: { value: null }, 1273 clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1274 clearcoatNormalMap: { value: null }, 1275 clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1276 clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, 1277 clearcoatRoughness: { value: 0 }, 1278 clearcoatRoughnessMap: { value: null }, 1279 clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1280 dispersion: { value: 0 }, 1281 retroreflectivity: { value: 0 }, 1282 iridescence: { value: 0 }, 1283 iridescenceMap: { value: null }, 1284 iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1285 iridescenceIOR: { value: 1.3 }, 1286 iridescenceThicknessMinimum: { value: 100 }, 1287 iridescenceThicknessMaximum: { value: 400 }, 1288 iridescenceThicknessMap: { value: null }, 1289 iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1290 sheen: { value: 0 }, 1291 sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 1292 sheenColorMap: { value: null }, 1293 sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1294 sheenRoughness: { value: 1 }, 1295 sheenRoughnessMap: { value: null }, 1296 sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1297 transmission: { value: 0 }, 1298 transmissionMap: { value: null }, 1299 transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1300 transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, 1301 transmissionSamplerMap: { value: null }, 1302 thickness: { value: 0 }, 1303 thicknessMap: { value: null }, 1304 thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1305 attenuationDistance: { value: 0 }, 1306 attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 1307 specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, 1308 specularColorMap: { value: null }, 1309 specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1310 specularIntensity: { value: 1 }, 1311 specularIntensityMap: { value: null }, 1312 specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1313 anisotropyVector: { value: /*@__PURE__*/ new Vector2() }, 1314 anisotropyMap: { value: null }, 1315 anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 1316 } 1317 ] ), 1318 1319 vertexShader: ShaderChunk.meshphysical_vert, 1320 fragmentShader: ShaderChunk.meshphysical_frag 1321 1322}; 1323 1324const _rgb = { r: 0, b: 0, g: 0 }; 1325const _m1$1 = /*@__PURE__*/ new Matrix4(); 1326const _m$1 = /*@__PURE__*/ new Matrix3(); 1327 1328_m$1.set( -1, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ); 1329 1330function WebGLBackground( renderer, environments, state, objects, alpha, premultipliedAlpha ) { 1331 1332 const clearColor = new Color( 0x000000 ); 1333 let clearAlpha = alpha === true ? 0 : 1; 1334 1335 let planeMesh; 1336 let boxMesh; 1337 1338 let currentBackground = null; 1339 let currentBackgroundVersion = 0; 1340 let currentTonemapping = null; 1341 1342 function getBackground( scene ) { 1343 1344 let background = scene.isScene === true ? scene.background : null; 1345 1346 if ( background && background.isTexture ) { 1347 1348 const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background 1349 background = environments.get( background, usePMREM ); 1350 1351 } 1352 1353 return background; 1354 1355 } 1356 1357 function render( scene ) { 1358 1359 let forceClear = false; 1360 const background = getBackground( scene ); 1361 1362 if ( background === null ) { 1363 1364 setClear( clearColor, clearAlpha ); 1365 1366 } else if ( background && background.isColor ) { 1367 1368 setClear( background, 1 ); 1369 forceClear = true; 1370 1371 } 1372 1373 const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); 1374 1375 if ( environmentBlendMode === 'additive' ) { 1376 1377 state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha ); 1378 1379 } else if ( environmentBlendMode === 'alpha-blend' ) { 1380 1381 state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha ); 1382 1383 } 1384 1385 if ( renderer.autoClear || forceClear ) { 1386 1387 // buffers might not be writable which is required to ensure a correct clear 1388 1389 state.buffers.depth.setTest( true ); 1390 state.buffers.depth.setMask( true ); 1391 state.buffers.color.setMask( true ); 1392 1393 renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); 1394 1395 } 1396 1397 } 1398 1399 function addToRenderList( renderList, scene ) { 1400 1401 const background = getBackground( scene ); 1402 1403 if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) { 1404 1405 if ( boxMesh === undefined ) { 1406 1407 boxMesh = new Mesh( 1408 new BoxGeometry( 1, 1, 1 ), 1409 new ShaderMaterial( { 1410 name: 'BackgroundCubeMaterial', 1411 uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ), 1412 vertexShader: ShaderLib.backgroundCube.vertexShader, 1413 fragmentShader: ShaderLib.backgroundCube.fragmentShader, 1414 side: BackSide, 1415 depthTest: false, 1416 depthWrite: false, 1417 fog: false, 1418 allowOverride: false 1419 } ) 1420 ); 1421 1422 boxMesh.geometry.deleteAttribute( 'normal' ); 1423 boxMesh.geometry.deleteAttribute( 'uv' ); 1424 1425 boxMesh.onBeforeRender = function ( renderer, scene, camera ) { 1426 1427 this.matrixWorld.copyPosition( camera.matrixWorld ); 1428 1429 }; 1430 1431 // add "envMap" material property so the renderer can evaluate it like for built-in materials 1432 Object.defineProperty( boxMesh.material, 'envMap', { 1433 1434 get: function () { 1435 1436 return this.uniforms.envMap.value; 1437 1438 } 1439 1440 } ); 1441 1442 objects.update( boxMesh ); 1443 1444 } 1445 1446 1447 boxMesh.material.uniforms.envMap.value = background; 1448 boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness; 1449 boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; 1450 1451 1452 // note: since the matrix is orthonormal, we can use the more-efficient transpose() in lieu of invert() 1453 boxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4( _m1$1.makeRotationFromEuler( scene.backgroundRotation ) ).transpose(); 1454 1455 if ( background.isCubeTexture && background.isRenderTargetTexture === false ) { 1456 1457 boxMesh.material.uniforms.backgroundRotation.value.premultiply( _m$1 ); 1458 1459 } 1460 1461 1462 boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; 1463 1464 if ( currentBackground !== background || 1465 currentBackgroundVersion !== background.version || 1466 currentTonemapping !== renderer.toneMapping ) { 1467 1468 boxMesh.material.needsUpdate = true; 1469 1470 currentBackground = background; 1471 currentBackgroundVersion = background.version; 1472 currentTonemapping = renderer.toneMapping; 1473 1474 } 1475 1476 boxMesh.layers.enableAll(); 1477 1478 // push to the pre-sorted opaque render list 1479 renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null ); 1480 1481 } else if ( background && background.isTexture ) { 1482 1483 if ( planeMesh === undefined ) { 1484 1485 planeMesh = new Mesh( 1486 new PlaneGeometry( 2, 2 ), 1487 new ShaderMaterial( { 1488 name: 'BackgroundMaterial', 1489 uniforms: cloneUniforms( ShaderLib.background.uniforms ), 1490 vertexShader: ShaderLib.background.vertexShader, 1491 fragmentShader: ShaderLib.background.fragmentShader, 1492 side: FrontSide, 1493 depthTest: false, 1494 depthWrite: false, 1495 fog: false, 1496 allowOverride: false 1497 } ) 1498 ); 1499 1500 planeMesh.geometry.deleteAttribute( 'normal' ); 1501 1502 // add "map" material property so the renderer can evaluate it like for built-in materials 1503 Object.defineProperty( planeMesh.material, 'map', { 1504 1505 get: function () { 1506 1507 return this.uniforms.t2D.value; 1508 1509 } 1510 1511 } ); 1512 1513 objects.update( planeMesh ); 1514 1515 } 1516 1517 planeMesh.material.uniforms.t2D.value = background; 1518 planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; 1519 planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; 1520 1521 if ( background.matrixAutoUpdate === true ) { 1522 1523 background.updateMatrix(); 1524 1525 } 1526 1527 planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); 1528 1529 if ( currentBackground !== background || 1530 currentBackgroundVersion !== background.version || 1531 currentTonemapping !== renderer.toneMapping ) { 1532 1533 planeMesh.material.needsUpdate = true; 1534 1535 currentBackground = background; 1536 currentBackgroundVersion = background.version; 1537 currentTonemapping = renderer.toneMapping; 1538 1539 } 1540 1541 planeMesh.layers.enableAll(); 1542 1543 // push to the pre-sorted opaque render list 1544 renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null ); 1545 1546 } 1547 1548 } 1549 1550 function setClear( color, alpha ) { 1551 1552 color.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) ); 1553 1554 state.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha ); 1555 1556 } 1557 1558 function dispose() { 1559 1560 if ( boxMesh !== undefined ) { 1561 1562 boxMesh.geometry.dispose(); 1563 boxMesh.material.dispose(); 1564 1565 boxMesh = undefined; 1566 1567 } 1568 1569 if ( planeMesh !== undefined ) { 1570 1571 planeMesh.geometry.dispose(); 1572 planeMesh.material.dispose(); 1573 1574 planeMesh = undefined; 1575 1576 } 1577 1578 } 1579 1580 return { 1581 1582 getClearColor: function () { 1583 1584 return clearColor; 1585 1586 }, 1587 setClearColor: function ( color, alpha = 1 ) { 1588 1589 clearColor.set( color ); 1590 clearAlpha = alpha; 1591 setClear( clearColor, clearAlpha ); 1592 1593 }, 1594 getClearAlpha: function () { 1595 1596 return clearAlpha; 1597 1598 }, 1599 setClearAlpha: function ( alpha ) { 1600 1601 clearAlpha = alpha; 1602 setClear( clearColor, clearAlpha ); 1603 1604 }, 1605 render: render, 1606 addToRenderList: addToRenderList, 1607 dispose: dispose 1608 1609 }; 1610 1611} 1612 1613function WebGLBindingStates( gl, attributes ) { 1614 1615 const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); 1616 1617 const bindingStates = {}; 1618 1619 const defaultState = createBindingState( null ); 1620 let currentState = defaultState; 1621 let forceUpdate = false; 1622 1623 function setup( object, material, program, geometry, index ) { 1624 1625 let updateBuffers = false; 1626 1627 const state = getBindingState( object, geometry, program, material ); 1628 1629 if ( currentState !== state ) { 1630 1631 currentState = state; 1632 bindVertexArrayObject( currentState.object ); 1633 1634 } 1635 1636 updateBuffers = needsUpdate( object, geometry, program, index ); 1637 1638 if ( updateBuffers ) saveCache( object, geometry, program, index ); 1639 1640 if ( index !== null ) { 1641 1642 attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); 1643 1644 } 1645 1646 if ( updateBuffers || forceUpdate ) { 1647 1648 forceUpdate = false; 1649 1650 setupVertexAttributes( object, material, program, geometry ); 1651 1652 if ( index !== null ) { 1653 1654 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer ); 1655 1656 } 1657 1658 } 1659 1660 } 1661 1662 function createVertexArrayObject() { 1663 1664 return gl.createVertexArray(); 1665 1666 } 1667 1668 function bindVertexArrayObject( vao ) { 1669 1670 return gl.bindVertexArray( vao ); 1671 1672 } 1673 1674 function deleteVertexArrayObject( vao ) { 1675 1676 return gl.deleteVertexArray( vao ); 1677 1678 } 1679 1680 function getBindingState( object, geometry, program, material ) { 1681 1682 const wireframe = ( material.wireframe === true ); 1683 1684 let objectMap = bindingStates[ geometry.id ]; 1685 1686 if ( objectMap === undefined ) { 1687 1688 objectMap = {}; 1689 bindingStates[ geometry.id ] = objectMap; 1690 1691 } 1692 1693 // Each InstancedMesh requires unique binding states because it contains instanced attributes. 1694 const objectId = ( object.isInstancedMesh === true ) ? object.id : 0; 1695 1696 let programMap = objectMap[ objectId ]; 1697 1698 if ( programMap === undefined ) { 1699 1700 programMap = {}; 1701 objectMap[ objectId ] = programMap; 1702 1703 } 1704 1705 let stateMap = programMap[ program.id ]; 1706 1707 if ( stateMap === undefined ) { 1708 1709 stateMap = {}; 1710 programMap[ program.id ] = stateMap; 1711 1712 } 1713 1714 let state = stateMap[ wireframe ]; 1715 1716 if ( state === undefined ) { 1717 1718 state = createBindingState( createVertexArrayObject() ); 1719 stateMap[ wireframe ] = state; 1720 1721 } 1722 1723 return state; 1724 1725 } 1726 1727 function createBindingState( vao ) { 1728 1729 const newAttributes = []; 1730 const enabledAttributes = []; 1731 const attributeDivisors = []; 1732 1733 for ( let i = 0; i < maxVertexAttributes; i ++ ) { 1734 1735 newAttributes[ i ] = 0; 1736 enabledAttributes[ i ] = 0; 1737 attributeDivisors[ i ] = 0; 1738 1739 } 1740 1741 return { 1742 1743 // for backward compatibility on non-VAO support browser 1744 geometry: null, 1745 program: null, 1746 wireframe: false, 1747 1748 newAttributes: newAttributes, 1749 enabledAttributes: enabledAttributes, 1750 attributeDivisors: attributeDivisors, 1751 object: vao, 1752 attributes: {}, 1753 index: null 1754 1755 }; 1756 1757 } 1758 1759 function needsUpdate( object, geometry, program, index ) { 1760 1761 const cachedAttributes = currentState.attributes; 1762 const geometryAttributes = geometry.attributes; 1763 1764 let attributesNum = 0; 1765 1766 const programAttributes = program.getAttributes(); 1767 1768 for ( const name in programAttributes ) { 1769 1770 const programAttribute = programAttributes[ name ]; 1771 1772 if ( programAttribute.location >= 0 ) { 1773 1774 const cachedAttribute = cachedAttributes[ name ]; 1775 let geometryAttribute = geometryAttributes[ name ]; 1776 1777 if ( geometryAttribute === undefined ) { 1778 1779 if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; 1780 if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; 1781 1782 } 1783 1784 if ( cachedAttribute === undefined ) return true; 1785 1786 if ( cachedAttribute.attribute !== geometryAttribute ) return true; 1787 1788 if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true; 1789 1790 attributesNum ++; 1791 1792 } 1793 1794 } 1795 1796 if ( currentState.attributesNum !== attributesNum ) return true; 1797 1798 if ( currentState.index !== index ) return true; 1799 1800 return false; 1801 1802 } 1803 1804 function saveCache( object, geometry, program, index ) { 1805 1806 const cache = {}; 1807 const attributes = geometry.attributes; 1808 let attributesNum = 0; 1809 1810 const programAttributes = program.getAttributes(); 1811 1812 for ( const name in programAttributes ) { 1813 1814 const programAttribute = programAttributes[ name ]; 1815 1816 if ( programAttribute.location >= 0 ) { 1817 1818 let attribute = attributes[ name ]; 1819 1820 if ( attribute === undefined ) { 1821 1822 if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix; 1823 if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor; 1824 1825 } 1826 1827 const data = {}; 1828 data.attribute = attribute; 1829 1830 if ( attribute && attribute.data ) { 1831 1832 data.data = attribute.data; 1833 1834 } 1835 1836 cache[ name ] = data; 1837 1838 attributesNum ++; 1839 1840 } 1841 1842 } 1843 1844 currentState.attributes = cache; 1845 currentState.attributesNum = attributesNum; 1846 1847 currentState.index = index; 1848 1849 } 1850 1851 function initAttributes() { 1852 1853 const newAttributes = currentState.newAttributes; 1854 1855 for ( let i = 0, il = newAttributes.length; i < il; i ++ ) { 1856 1857 newAttributes[ i ] = 0; 1858 1859 } 1860 1861 } 1862 1863 function enableAttribute( attribute ) { 1864 1865 enableAttributeAndDivisor( attribute, 0 ); 1866 1867 } 1868 1869 function enableAttributeAndDivisor( attribute, meshPerAttribute ) { 1870 1871 const newAttributes = currentState.newAttributes; 1872 const enabledAttributes = currentState.enabledAttributes; 1873 const attributeDivisors = currentState.attributeDivisors; 1874 1875 newAttributes[ attribute ] = 1; 1876 1877 if ( enabledAttributes[ attribute ] === 0 ) { 1878 1879 gl.enableVertexAttribArray( attribute ); 1880 enabledAttributes[ attribute ] = 1; 1881 1882 } 1883 1884 if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { 1885 1886 gl.vertexAttribDivisor( attribute, meshPerAttribute ); 1887 attributeDivisors[ attribute ] = meshPerAttribute; 1888 1889 } 1890 1891 } 1892 1893 function disableUnusedAttributes() { 1894 1895 const newAttributes = currentState.newAttributes; 1896 const enabledAttributes = currentState.enabledAttributes; 1897 1898 for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) { 1899 1900 if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { 1901 1902 gl.disableVertexAttribArray( i ); 1903 enabledAttributes[ i ] = 0; 1904 1905 } 1906 1907 } 1908 1909 } 1910 1911 function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) { 1912 1913 if ( integer === true ) { 1914 1915 gl.vertexAttribIPointer( index, size, type, stride, offset ); 1916 1917 } else { 1918 1919 gl.vertexAttribPointer( index, size, type, normalized, stride, offset ); 1920 1921 } 1922 1923 } 1924 1925 function setupVertexAttributes( object, material, program, geometry ) { 1926 1927 initAttributes(); 1928 1929 const geometryAttributes = geometry.attributes; 1930 1931 const programAttributes = program.getAttributes(); 1932 1933 const materialDefaultAttributeValues = material.defaultAttributeValues; 1934 1935 for ( const name in programAttributes ) { 1936 1937 const programAttribute = programAttributes[ name ]; 1938 1939 if ( programAttribute.location >= 0 ) { 1940 1941 let geometryAttribute = geometryAttributes[ name ]; 1942 1943 if ( geometryAttribute === undefined ) { 1944 1945 if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; 1946 if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; 1947 1948 } 1949 1950 if ( geometryAttribute !== undefined ) { 1951 1952 const normalized = geometryAttribute.normalized; 1953 const size = geometryAttribute.itemSize; 1954 1955 const attribute = attributes.get( geometryAttribute ); 1956 1957 // TODO Attribute may not be available on context restore 1958 1959 if ( attribute === undefined ) continue; 1960 1961 const buffer = attribute.buffer; 1962 const type = attribute.type; 1963 const bytesPerElement = attribute.bytesPerElement; 1964 1965 // check for integer attributes 1966 1967 const integer = ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ); 1968 1969 if ( geometryAttribute.isInterleavedBufferAttribute ) { 1970 1971 const data = geometryAttribute.data; 1972 const stride = data.stride; 1973 const offset = geometryAttribute.offset; 1974 1975 if ( data.isInstancedInterleavedBuffer ) { 1976 1977 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 1978 1979 enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute ); 1980 1981 } 1982 1983 if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { 1984 1985 geometry._maxInstanceCount = data.meshPerAttribute * data.count; 1986 1987 } 1988 1989 } else { 1990 1991 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 1992 1993 enableAttribute( programAttribute.location + i ); 1994 1995 } 1996 1997 } 1998 1999 gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); 2000 2001 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 2002 2003 vertexAttribPointer( 2004 programAttribute.location + i, 2005 size / programAttribute.locationSize, 2006 type, 2007 normalized, 2008 stride * bytesPerElement, 2009 ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement, 2010 integer 2011 ); 2012 2013 } 2014 2015 } else { 2016 2017 if ( geometryAttribute.isInstancedBufferAttribute ) { 2018 2019 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 2020 2021 enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute ); 2022 2023 } 2024 2025 if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { 2026 2027 geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; 2028 2029 } 2030 2031 } else { 2032 2033 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 2034 2035 enableAttribute( programAttribute.location + i ); 2036 2037 } 2038 2039 } 2040 2041 gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); 2042 2043 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 2044 2045 vertexAttribPointer( 2046 programAttribute.location + i, 2047 size / programAttribute.locationSize, 2048 type, 2049 normalized, 2050 size * bytesPerElement, 2051 ( size / programAttribute.locationSize ) * i * bytesPerElement, 2052 integer 2053 ); 2054 2055 } 2056 2057 } 2058 2059 } else if ( materialDefaultAttributeValues !== undefined ) { 2060 2061 const value = materialDefaultAttributeValues[ name ]; 2062 2063 if ( value !== undefined ) { 2064 2065 switch ( value.length ) { 2066 2067 case 2: 2068 gl.vertexAttrib2fv( programAttribute.location, value ); 2069 break; 2070 2071 case 3: 2072 gl.vertexAttrib3fv( programAttribute.location, value ); 2073 break; 2074 2075 case 4: 2076 gl.vertexAttrib4fv( programAttribute.location, value ); 2077 break; 2078 2079 default: 2080 gl.vertexAttrib1fv( programAttribute.location, value ); 2081 2082 } 2083 2084 } 2085 2086 } 2087 2088 } 2089 2090 } 2091 2092 disableUnusedAttributes(); 2093 2094 } 2095 2096 function dispose() { 2097 2098 reset(); 2099 2100 for ( const geometryId in bindingStates ) { 2101 2102 const objectMap = bindingStates[ geometryId ]; 2103 2104 for ( const objectId in objectMap ) { 2105 2106 const programMap = objectMap[ objectId ]; 2107 2108 for ( const programId in programMap ) { 2109 2110 const stateMap = programMap[ programId ]; 2111 2112 for ( const wireframe in stateMap ) { 2113 2114 deleteVertexArrayObject( stateMap[ wireframe ].object ); 2115 2116 delete stateMap[ wireframe ]; 2117 2118 } 2119 2120 delete programMap[ programId ]; 2121 2122 } 2123 2124 } 2125 2126 delete bindingStates[ geometryId ]; 2127 2128 } 2129 2130 } 2131 2132 function releaseStatesOfGeometry( geometry ) { 2133 2134 if ( bindingStates[ geometry.id ] === undefined ) return; 2135 2136 const objectMap = bindingStates[ geometry.id ]; 2137 2138 for ( const objectId in objectMap ) { 2139 2140 const programMap = objectMap[ objectId ]; 2141 2142 for ( const programId in programMap ) { 2143 2144 const stateMap = programMap[ programId ]; 2145 2146 for ( const wireframe in stateMap ) { 2147 2148 deleteVertexArrayObject( stateMap[ wireframe ].object ); 2149 2150 delete stateMap[ wireframe ]; 2151 2152 } 2153 2154 delete programMap[ programId ]; 2155 2156 } 2157 2158 } 2159 2160 delete bindingStates[ geometry.id ]; 2161 2162 } 2163 2164 function releaseStatesOfProgram( program ) { 2165 2166 for ( const geometryId in bindingStates ) { 2167 2168 const objectMap = bindingStates[ geometryId ]; 2169 2170 for ( const objectId in objectMap ) { 2171 2172 const programMap = objectMap[ objectId ]; 2173 2174 if ( programMap[ program.id ] === undefined ) continue; 2175 2176 const stateMap = programMap[ program.id ]; 2177 2178 for ( const wireframe in stateMap ) { 2179 2180 deleteVertexArrayObject( stateMap[ wireframe ].object ); 2181 2182 delete stateMap[ wireframe ]; 2183 2184 } 2185 2186 delete programMap[ program.id ]; 2187 2188 } 2189 2190 } 2191 2192 } 2193 2194 function releaseStatesOfObject( object ) { 2195 2196 for ( const geometryId in bindingStates ) { 2197 2198 const objectMap = bindingStates[ geometryId ]; 2199 2200 const objectId = ( object.isInstancedMesh === true ) ? object.id : 0; 2201 2202 const programMap = objectMap[ objectId ]; 2203 2204 if ( programMap === undefined ) continue; 2205 2206 for ( const programId in programMap ) { 2207 2208 const stateMap = programMap[ programId ]; 2209 2210 for ( const wireframe in stateMap ) { 2211 2212 deleteVertexArrayObject( stateMap[ wireframe ].object ); 2213 2214 delete stateMap[ wireframe ]; 2215 2216 } 2217 2218 delete programMap[ programId ]; 2219 2220 } 2221 2222 delete objectMap[ objectId ]; 2223 2224 if ( Object.keys( objectMap ).length === 0 ) { 2225 2226 delete bindingStates[ geometryId ]; 2227 2228 } 2229 2230 } 2231 2232 } 2233 2234 2235 function reset() { 2236 2237 resetDefaultState(); 2238 forceUpdate = true; 2239 2240 if ( currentState === defaultState ) return; 2241 2242 currentState = defaultState; 2243 bindVertexArrayObject( currentState.object ); 2244 2245 } 2246 2247 // for backward-compatibility 2248 2249 function resetDefaultState() { 2250 2251 defaultState.geometry = null; 2252 defaultState.program = null; 2253 defaultState.wireframe = false; 2254 2255 } 2256 2257 return { 2258 2259 setup: setup, 2260 reset: reset, 2261 resetDefaultState: resetDefaultState, 2262 dispose: dispose, 2263 releaseStatesOfGeometry: releaseStatesOfGeometry, 2264 releaseStatesOfObject: releaseStatesOfObject, 2265 releaseStatesOfProgram: releaseStatesOfProgram, 2266 2267 initAttributes: initAttributes, 2268 enableAttribute: enableAttribute, 2269 disableUnusedAttributes: disableUnusedAttributes 2270 2271 }; 2272 2273} 2274 2275function WebGLBufferRenderer( gl, extensions, info ) { 2276 2277 let mode; 2278 2279 function setMode( value ) { 2280 2281 mode = value; 2282 2283 } 2284 2285 function render( start, count ) { 2286 2287 gl.drawArrays( mode, start, count ); 2288 2289 info.update( count, mode, 1 ); 2290 2291 } 2292 2293 function renderInstances( start, count, primcount ) { 2294 2295 if ( primcount === 0 ) return; 2296 2297 gl.drawArraysInstanced( mode, start, count, primcount ); 2298 2299 info.update( count, mode, primcount ); 2300 2301 } 2302 2303 function renderMultiDraw( starts, counts, drawCount ) { 2304 2305 if ( drawCount === 0 ) return; 2306 2307 const extension = extensions.get( 'WEBGL_multi_draw' ); 2308 extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount ); 2309 2310 let elementCount = 0; 2311 for ( let i = 0; i < drawCount; i ++ ) { 2312 2313 elementCount += counts[ i ]; 2314 2315 } 2316 2317 info.update( elementCount, mode, 1 ); 2318 2319 } 2320 2321 // 2322 2323 this.setMode = setMode; 2324 this.render = render; 2325 this.renderInstances = renderInstances; 2326 this.renderMultiDraw = renderMultiDraw; 2327 2328} 2329 2330function WebGLCapabilities( gl, extensions, parameters, utils ) { 2331 2332 let maxAnisotropy; 2333 2334 function getMaxAnisotropy() { 2335 2336 if ( maxAnisotropy !== undefined ) return maxAnisotropy; 2337 2338 if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { 2339 2340 const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); 2341 2342 maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); 2343 2344 } else { 2345 2346 maxAnisotropy = 0; 2347 2348 } 2349 2350 return maxAnisotropy; 2351 2352 } 2353 2354 function textureFormatReadable( textureFormat ) { 2355 2356 if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { 2357 2358 return false; 2359 2360 } 2361 2362 return true; 2363 2364 } 2365 2366 function textureTypeReadable( textureType ) { 2367 2368 const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) ); 2369 2370 if ( textureType !== UnsignedByteType && textureType !== FloatType && ! halfFloatSupportedByExt && 2371 utils.convert( textureType ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_TYPE ) ) { // Edge and Chrome Mac < 52 (#9513) 2372 2373 return false; 2374 2375 } 2376 2377 return true; 2378 2379 } 2380 2381 function getMaxPrecision( precision ) { 2382 2383 if ( precision === 'highp' ) { 2384 2385 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && 2386 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { 2387 2388 return 'highp'; 2389 2390 } 2391 2392 precision = 'mediump'; 2393 2394 } 2395 2396 if ( precision === 'mediump' ) { 2397 2398 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && 2399 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { 2400 2401 return 'mediump'; 2402 2403 } 2404 2405 } 2406 2407 return 'lowp'; 2408 2409 } 2410 2411 let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; 2412 const maxPrecision = getMaxPrecision( precision ); 2413 2414 if ( maxPrecision !== precision ) { 2415 2416 warn( 'WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); 2417 precision = maxPrecision; 2418 2419 } 2420 2421 const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; 2422 const reversedDepthBuffer = parameters.reversedDepthBuffer === true && extensions.has( 'EXT_clip_control' ); 2423 2424 if ( parameters.reversedDepthBuffer === true && reversedDepthBuffer === false ) { 2425 2426 warn( 'WebGLRenderer: Unable to use reversed depth buffer due to missing EXT_clip_control extension. Fallback to default depth buffer.' ); 2427 2428 } 2429 2430 const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); 2431 const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); 2432 const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); 2433 const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); 2434 2435 const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); 2436 const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); 2437 const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); 2438 const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); 2439 2440 const maxSamples = gl.getParameter( gl.MAX_SAMPLES ); 2441 const samples = gl.getParameter( gl.SAMPLES ); 2442 2443 return { 2444 2445 isWebGL2: true, // keeping this for backwards compatibility 2446 2447 getMaxAnisotropy: getMaxAnisotropy, 2448 getMaxPrecision: getMaxPrecision, 2449 2450 textureFormatReadable: textureFormatReadable, 2451 textureTypeReadable: textureTypeReadable, 2452 2453 precision: precision, 2454 logarithmicDepthBuffer: logarithmicDepthBuffer, 2455 reversedDepthBuffer: reversedDepthBuffer, 2456 2457 maxTextures: maxTextures, 2458 maxVertexTextures: maxVertexTextures, 2459 maxTextureSize: maxTextureSize, 2460 maxCubemapSize: maxCubemapSize, 2461 2462 maxAttributes: maxAttributes, 2463 maxVertexUniforms: maxVertexUniforms, 2464 maxVaryings: maxVaryings, 2465 maxFragmentUniforms: maxFragmentUniforms, 2466 2467 maxSamples: maxSamples, 2468 2469 samples: samples 2470 2471 }; 2472 2473} 2474 2475function WebGLClipping( properties ) { 2476 2477 const scope = this; 2478 2479 let globalState = null, 2480 numGlobalPlanes = 0, 2481 localClippingEnabled = false, 2482 renderingShadows = false; 2483 2484 const plane = new Plane(), 2485 viewNormalMatrix = new Matrix3(), 2486 2487 uniform = { value: null, needsUpdate: false }; 2488 2489 this.uniform = uniform; 2490 this.numPlanes = 0; 2491 this.numIntersection = 0; 2492 2493 this.init = function ( planes, enableLocalClipping ) { 2494 2495 const enabled = 2496 planes.length !== 0 || 2497 enableLocalClipping || 2498 // enable state of previous frame - the clipping code has to 2499 // run another frame in order to reset the state: 2500 numGlobalPlanes !== 0 || 2501 localClippingEnabled; 2502 2503 localClippingEnabled = enableLocalClipping; 2504 2505 numGlobalPlanes = planes.length; 2506 2507 return enabled; 2508 2509 }; 2510 2511 this.beginShadows = function () { 2512 2513 renderingShadows = true; 2514 projectPlanes( null ); 2515 2516 }; 2517 2518 this.endShadows = function () { 2519 2520 renderingShadows = false; 2521 2522 }; 2523 2524 this.setGlobalState = function ( planes, camera ) { 2525 2526 globalState = projectPlanes( planes, camera, 0 ); 2527 2528 }; 2529 2530 this.setState = function ( material, camera, useCache ) { 2531 2532 const planes = material.clippingPlanes, 2533 clipIntersection = material.clipIntersection, 2534 clipShadows = material.clipShadows; 2535 2536 const materialProperties = properties.get( material ); 2537 2538 if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { 2539 2540 // there's no local clipping 2541 2542 if ( renderingShadows ) { 2543 2544 // there's no global clipping 2545 2546 projectPlanes( null ); 2547 2548 } else { 2549 2550 resetGlobalState(); 2551 2552 } 2553 2554 } else { 2555 2556 const nGlobal = renderingShadows ? 0 : numGlobalPlanes, 2557 lGlobal = nGlobal * 4; 2558 2559 let dstArray = materialProperties.clippingState || null; 2560 2561 uniform.value = dstArray; // ensure unique state 2562 2563 dstArray = projectPlanes( planes, camera, lGlobal, useCache ); 2564 2565 for ( let i = 0; i !== lGlobal; ++ i ) { 2566 2567 dstArray[ i ] = globalState[ i ]; 2568 2569 } 2570 2571 materialProperties.clippingState = dstArray; 2572 this.numIntersection = clipIntersection ? this.numPlanes : 0; 2573 this.numPlanes += nGlobal; 2574 2575 } 2576 2577 2578 }; 2579 2580 function resetGlobalState() { 2581 2582 if ( uniform.value !== globalState ) { 2583 2584 uniform.value = globalState; 2585 uniform.needsUpdate = numGlobalPlanes > 0; 2586 2587 } 2588 2589 scope.numPlanes = numGlobalPlanes; 2590 scope.numIntersection = 0; 2591 2592 } 2593 2594 function projectPlanes( planes, camera, dstOffset, skipTransform ) { 2595 2596 const nPlanes = planes !== null ? planes.length : 0; 2597 let dstArray = null; 2598 2599 if ( nPlanes !== 0 ) { 2600 2601 dstArray = uniform.value; 2602 2603 if ( skipTransform !== true || dstArray === null ) { 2604 2605 const flatSize = dstOffset + nPlanes * 4, 2606 viewMatrix = camera.matrixWorldInverse; 2607 2608 viewNormalMatrix.getNormalMatrix( viewMatrix ); 2609 2610 if ( dstArray === null || dstArray.length < flatSize ) { 2611 2612 dstArray = new Float32Array( flatSize ); 2613 2614 } 2615 2616 for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { 2617 2618 plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); 2619 2620 plane.normal.toArray( dstArray, i4 ); 2621 dstArray[ i4 + 3 ] = plane.constant; 2622 2623 } 2624 2625 } 2626 2627 uniform.value = dstArray; 2628 uniform.needsUpdate = true; 2629 2630 } 2631 2632 scope.numPlanes = nPlanes; 2633 scope.numIntersection = 0; 2634 2635 return dstArray; 2636 2637 } 2638 2639} 2640 2641const LOD_MIN = 4; 2642 2643// The number of extra mips. 2644// Used for scene blur in fromScene() method. 2645const EXTRA_LODS = 6; 2646 2647// The number of spiral samples per blur pass. 2648// Used for scene blur in fromScene() method. 2649const BLUR_SAMPLES = 20; 2650 2651// GGX VNDF importance sampling configuration 2652const GGX_SAMPLES = 256; 2653 2654const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); 2655const _clearColor = /*@__PURE__*/ new Color(); 2656let _oldTarget = null; 2657let _oldActiveCubeFace = 0; 2658let _oldActiveMipmapLevel = 0; 2659let _oldXrEnabled = false; 2660 2661const _origin = /*@__PURE__*/ new Vector3(); 2662const _direction = /*@__PURE__*/ new Vector3(); 2663 2664/** 2665 * This class generates a Prefiltered, Mipmapped Radiance Environment Map 2666 * (PMREM) from a cubeMap environment texture. This allows different levels of 2667 * blur to be quickly accessed based on material roughness. It is packed into a 2668 * special CubeUV format that allows us to perform custom interpolation so that 2669 * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap 2670 * chain, it only goes down to the LOD_MIN level (above), and then creates extra 2671 * even more filtered 'mips' at the same LOD_MIN resolution, associated with 2672 * higher roughness levels. In this way we maintain resolution to smoothly 2673 * interpolate diffuse lighting while limiting sampling computation. 2674 * 2675 * The prefiltering uses GGX VNDF (Visible Normal Distribution Function) 2676 * importance sampling based on "Sampling the GGX Distribution of Visible Normals" 2677 * (Heitz, 2018) to generate environment maps that accurately match the GGX BRDF 2678 * used in material rendering for physically-based image-based lighting. 2679 */ 2680class PMREMGenerator { 2681 2682 /** 2683 * Constructs a new PMREM generator. 2684 * 2685 * @param {WebGLRenderer} renderer - The renderer. 2686 */ 2687 constructor( renderer ) { 2688 2689 this._renderer = renderer; 2690 this._pingPongRenderTarget = null; 2691 2692 this._lodMax = 0; 2693 this._cubeSize = 0; 2694 this._sizeLods = []; 2695 this._lodMeshes = []; 2696 2697 this._backgroundBox = null; 2698 2699 this._cubemapMaterial = null; 2700 this._equirectMaterial = null; 2701 2702 this._blurMaterial = null; 2703 this._ggxMaterial = null; 2704 2705 } 2706 2707 /** 2708 * Generates a PMREM from a supplied Scene, which can be faster than using an 2709 * image if networking bandwidth is low. Optional sigma specifies a blur radius 2710 * in radians to be applied to the scene before PMREM generation. Optional near 2711 * and far planes ensure the scene is rendered in its entirety. 2712 * 2713 * @param {Scene} scene - The scene to be captured. 2714 * @param {number} [sigma=0] - The blur radius in radians. 2715 * @param {number} [near=0.1] - The near plane distance. 2716 * @param {number} [far=100] - The far plane distance. 2717 * @param {Object} [options={}] - The configuration options. 2718 * @param {number} [options.size=256] - The texture size of the PMREM. 2719 * @param {Vector3} [options.position=origin] - The position of the internal cube camera that renders the scene. 2720 * @return {WebGLRenderTarget} The resulting PMREM. 2721 */ 2722 fromScene( scene, sigma = 0, near = 0.1, far = 100, options = {} ) { 2723 2724 const { 2725 size = 256, 2726 position = _origin, 2727 } = options; 2728 2729 _oldTarget = this._renderer.getRenderTarget(); 2730 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 2731 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 2732 _oldXrEnabled = this._renderer.xr.enabled; 2733 2734 this._renderer.xr.enabled = false; 2735 2736 this._setSize( size ); 2737 2738 const cubeUVRenderTarget = this._allocateTargets(); 2739 cubeUVRenderTarget.depthBuffer = true; 2740 2741 this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position ); 2742 2743 if ( sigma > 0 ) { 2744 2745 this._blur( cubeUVRenderTarget, 0, 0, sigma ); 2746 2747 } 2748 2749 this._applyPMREM( cubeUVRenderTarget ); 2750 this._cleanup( cubeUVRenderTarget ); 2751 2752 return cubeUVRenderTarget; 2753 2754 } 2755 2756 /** 2757 * Generates a PMREM from an equirectangular texture, which can be either LDR 2758 * or HDR. The ideal input image size is 1k (1024 x 512), as this matches best 2759 * with the 256 x 256 cubemap output. The minimum supported input image size 2760 * is 64 x 32. 2761 * 2762 * @param {Texture} equirectangular - The equirectangular texture to be converted. 2763 * @param {?WebGLRenderTarget} [renderTarget=null] - The render target to use. 2764 * @return {WebGLRenderTarget} The resulting PMREM. 2765 */ 2766 fromEquirectangular( equirectangular, renderTarget = null ) { 2767 2768 return this._fromTexture( equirectangular, renderTarget ); 2769 2770 } 2771 2772 /** 2773 * Generates a PMREM from an cubemap texture, which can be either LDR 2774 * or HDR. The ideal input cube size is 256 x 256, as this matches best 2775 * with the 256 x 256 cubemap output. The minimum supported input cube 2776 * size is 16 x 16 per face. 2777 * 2778 * @param {Texture} cubemap - The cubemap texture to be converted. 2779 * @param {?WebGLRenderTarget} [renderTarget=null] - The render target to use. 2780 * @return {WebGLRenderTarget} The resulting PMREM. 2781 */ 2782 fromCubemap( cubemap, renderTarget = null ) { 2783 2784 return this._fromTexture( cubemap, renderTarget ); 2785 2786 } 2787 2788 /** 2789 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during 2790 * your texture's network fetch for increased concurrency. 2791 */ 2792 compileCubemapShader() { 2793 2794 if ( this._cubemapMaterial === null ) { 2795 2796 this._cubemapMaterial = _getCubemapMaterial(); 2797 this._compileMaterial( this._cubemapMaterial ); 2798 2799 } 2800 2801 } 2802 2803 /** 2804 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during 2805 * your texture's network fetch for increased concurrency. 2806 */ 2807 compileEquirectangularShader() { 2808 2809 if ( this._equirectMaterial === null ) { 2810 2811 this._equirectMaterial = _getEquirectMaterial(); 2812 this._compileMaterial( this._equirectMaterial ); 2813 2814 } 2815 2816 } 2817 2818 /** 2819 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, 2820 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on 2821 * one of them will cause any others to also become unusable. 2822 */ 2823 dispose() { 2824 2825 this._dispose(); 2826 2827 if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose(); 2828 if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose(); 2829 2830 if ( this._backgroundBox !== null ) { 2831 2832 this._backgroundBox.geometry.dispose(); 2833 this._backgroundBox.material.dispose(); 2834 2835 } 2836 2837 } 2838 2839 // private interface 2840 2841 _setSize( cubeSize ) { 2842 2843 this._lodMax = Math.floor( Math.log2( cubeSize ) ); 2844 this._cubeSize = Math.pow( 2, this._lodMax ); 2845 2846 } 2847 2848 _dispose() { 2849 2850 if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); 2851 if ( this._ggxMaterial !== null ) this._ggxMaterial.dispose(); 2852 2853 if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); 2854 2855 for ( let i = 0; i < this._lodMeshes.length; i ++ ) { 2856 2857 this._lodMeshes[ i ].geometry.dispose(); 2858 2859 } 2860 2861 } 2862 2863 _cleanup( outputTarget ) { 2864 2865 this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); 2866 this._renderer.xr.enabled = _oldXrEnabled; 2867 2868 outputTarget.scissorTest = false; 2869 _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); 2870 2871 } 2872 2873 _fromTexture( texture, renderTarget ) { 2874 2875 if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) { 2876 2877 this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) ); 2878 2879 } else { // Equirectangular 2880 2881 this._setSize( texture.image.width / 4 ); 2882 2883 } 2884 2885 _oldTarget = this._renderer.getRenderTarget(); 2886 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 2887 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 2888 _oldXrEnabled = this._renderer.xr.enabled; 2889 2890 this._renderer.xr.enabled = false; 2891 2892 const cubeUVRenderTarget = renderTarget || this._allocateTargets(); 2893 this._textureToCubeUV( texture, cubeUVRenderTarget ); 2894 this._applyPMREM( cubeUVRenderTarget ); 2895 this._cleanup( cubeUVRenderTarget ); 2896 2897 return cubeUVRenderTarget; 2898 2899 } 2900 2901 _allocateTargets() { 2902 2903 const width = 3 * Math.max( this._cubeSize, 16 * 7 ); 2904 const height = 4 * this._cubeSize; 2905 2906 const params = { 2907 magFilter: LinearFilter, 2908 minFilter: LinearFilter, 2909 generateMipmaps: false, 2910 type: HalfFloatType, 2911 format: RGBAFormat, 2912 colorSpace: LinearSRGBColorSpace, 2913 depthBuffer: false 2914 }; 2915 2916 const cubeUVRenderTarget = _createRenderTarget( width, height, params ); 2917 2918 if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { 2919 2920 if ( this._pingPongRenderTarget !== null ) { 2921 2922 this._dispose(); 2923 2924 } 2925 2926 this._pingPongRenderTarget = _createRenderTarget( width, height, params ); 2927 2928 const { _lodMax } = this; 2929 ( { lodMeshes: this._lodMeshes, sizeLods: this._sizeLods } = _createPlanes( _lodMax ) ); 2930 2931 this._blurMaterial = _getBlurShader( _lodMax, width, height ); 2932 this._ggxMaterial = _getGGXShader( _lodMax, width, height ); 2933 2934 } 2935 2936 return cubeUVRenderTarget; 2937 2938 } 2939 2940 _compileMaterial( material ) { 2941 2942 const mesh = new Mesh( new BufferGeometry(), material ); 2943 this._renderer.compile( mesh, _flatCamera ); 2944 2945 } 2946 2947 _sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position ) { 2948 2949 const fov = 90; 2950 const aspect = 1; 2951 const cubeCamera = new PerspectiveCamera( fov, aspect, near, far ); 2952 const upSign = [ 1, -1, 1, 1, 1, 1 ]; 2953 const forwardSign = [ 1, 1, 1, -1, -1, -1 ]; 2954 const renderer = this._renderer; 2955 2956 const originalAutoClear = renderer.autoClear; 2957 const toneMapping = renderer.toneMapping; 2958 renderer.getClearColor( _clearColor ); 2959 2960 renderer.toneMapping = NoToneMapping; 2961 renderer.autoClear = false; 2962 2963 // https://github.com/mrdoob/three.js/issues/31413#issuecomment-3095966812 2964 const reversedDepthBuffer = renderer.state.buffers.depth.getReversed(); 2965 2966 if ( reversedDepthBuffer ) { 2967 2968 renderer.setRenderTarget( cubeUVRenderTarget ); 2969 renderer.clearDepth(); 2970 renderer.setRenderTarget( null ); 2971 2972 } 2973 2974 if ( this._backgroundBox === null ) { 2975 2976 this._backgroundBox = new Mesh( 2977 new BoxGeometry(), 2978 new MeshBasicMaterial( { 2979 name: 'PMREM.Background', 2980 side: BackSide, 2981 depthWrite: false, 2982 depthTest: false, 2983 } ) 2984 ); 2985 2986 } 2987 2988 const backgroundBox = this._backgroundBox; 2989 const backgroundMaterial = backgroundBox.material; 2990 2991 let useSolidColor = false; 2992 2993 const background = scene.background; 2994 2995 if ( background ) { 2996 2997 if ( background.isColor ) { 2998 2999 backgroundMaterial.color.copy( background ); 3000 scene.background = null; 3001 useSolidColor = true; 3002 3003 } 3004 3005 } else { 3006 3007 backgroundMaterial.color.copy( _clearColor ); 3008 useSolidColor = true; 3009 3010 } 3011 3012 for ( let i = 0; i < 6; i ++ ) { 3013 3014 const col = i % 3; 3015 3016 if ( col === 0 ) { 3017 3018 cubeCamera.up.set( 0, upSign[ i ], 0 ); 3019 cubeCamera.position.set( position.x, position.y, position.z ); 3020 cubeCamera.lookAt( position.x + forwardSign[ i ], position.y, position.z ); 3021 3022 } else if ( col === 1 ) { 3023 3024 cubeCamera.up.set( 0, 0, upSign[ i ] ); 3025 cubeCamera.position.set( position.x, position.y, position.z ); 3026 cubeCamera.lookAt( position.x, position.y + forwardSign[ i ], position.z ); 3027 3028 3029 } else { 3030 3031 cubeCamera.up.set( 0, upSign[ i ], 0 ); 3032 cubeCamera.position.set( position.x, position.y, position.z ); 3033 cubeCamera.lookAt( position.x, position.y, position.z + forwardSign[ i ] ); 3034 3035 } 3036 3037 const size = this._cubeSize; 3038 3039 _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size ); 3040 3041 renderer.setRenderTarget( cubeUVRenderTarget ); 3042 3043 if ( useSolidColor ) { 3044 3045 renderer.render( backgroundBox, cubeCamera ); 3046 3047 } 3048 3049 renderer.render( scene, cubeCamera ); 3050 3051 } 3052 3053 renderer.toneMapping = toneMapping; 3054 renderer.autoClear = originalAutoClear; 3055 scene.background = background; 3056 3057 } 3058 3059 _textureToCubeUV( texture, cubeUVRenderTarget ) { 3060 3061 const renderer = this._renderer; 3062 3063 const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ); 3064 3065 if ( isCubeTexture ) { 3066 3067 if ( this._cubemapMaterial === null ) { 3068 3069 this._cubemapMaterial = _getCubemapMaterial(); 3070 3071 } 3072 3073 this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? -1 : 1; 3074 3075 } else { 3076 3077 if ( this._equirectMaterial === null ) { 3078 3079 this._equirectMaterial = _getEquirectMaterial(); 3080 3081 } 3082 3083 } 3084 3085 const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; 3086 3087 const mesh = this._lodMeshes[ 0 ]; 3088 mesh.material = material; 3089 3090 const uniforms = material.uniforms; 3091 3092 uniforms[ 'envMap' ].value = texture; 3093 3094 const size = this._cubeSize; 3095 3096 _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size ); 3097 3098 renderer.setRenderTarget( cubeUVRenderTarget ); 3099 renderer.render( mesh, _flatCamera ); 3100 3101 } 3102 3103 _applyPMREM( cubeUVRenderTarget ) { 3104 3105 const renderer = this._renderer; 3106 const autoClear = renderer.autoClear; 3107 renderer.autoClear = false; 3108 3109 const n = this._lodMeshes.length; 3110 3111 // Use GGX VNDF importance sampling 3112 for ( let i = 1; i < n; i ++ ) { 3113 3114 this._applyGGXFilter( cubeUVRenderTarget, i - 1, i ); 3115 3116 } 3117 3118 renderer.autoClear = autoClear; 3119 3120 } 3121 3122 /** 3123 * Applies GGX VNDF importance sampling filter to generate a prefiltered environment map. 3124 * Uses Monte Carlo integration with VNDF importance sampling to accurately represent the 3125 * GGX BRDF for physically-based rendering. Reads from the previous LOD level and 3126 * applies incremental roughness filtering to avoid over-blurring. 3127 * 3128 * @private 3129 * @param {WebGLRenderTarget} cubeUVRenderTarget 3130 * @param {number} lodIn - Source LOD level to read from 3131 * @param {number} lodOut - Target LOD level to write to 3132 */ 3133 _applyGGXFilter( cubeUVRenderTarget, lodIn, lodOut ) { 3134 3135 const renderer = this._renderer; 3136 const pingPongRenderTarget = this._pingPongRenderTarget; 3137 3138 const ggxMaterial = this._ggxMaterial; 3139 const ggxMesh = this._lodMeshes[ lodOut ]; 3140 ggxMesh.material = ggxMaterial; 3141 3142 const ggxUniforms = ggxMaterial.uniforms; 3143 3144 // Calculate incremental roughness between LOD levels 3145 const targetRoughness = lodOut / ( this._lodMeshes.length - 1 ); 3146 const sourceRoughness = lodIn / ( this._lodMeshes.length - 1 ); 3147 const incrementalRoughness = Math.sqrt( targetRoughness * targetRoughness - sourceRoughness * sourceRoughness ); 3148 3149 // Apply blur strength mapping for better quality across the roughness range 3150 const blurStrength = targetRoughness * 1.25; 3151 const adjustedRoughness = incrementalRoughness * blurStrength; 3152 3153 // Calculate viewport position based on output LOD level 3154 const { _lodMax } = this; 3155 const outputSize = this._sizeLods[ lodOut ]; 3156 const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); 3157 const y = 4 * ( this._cubeSize - outputSize ); 3158 3159 // Read from previous LOD with incremental roughness 3160 ggxUniforms[ 'envMap' ].value = cubeUVRenderTarget.texture; 3161 ggxUniforms[ 'roughness' ].value = adjustedRoughness; 3162 ggxUniforms[ 'mipInt' ].value = _lodMax - lodIn; // Sample from input LOD 3163 3164 _setViewport( pingPongRenderTarget, x, y, 3 * outputSize, 2 * outputSize ); 3165 renderer.setRenderTarget( pingPongRenderTarget ); 3166 renderer.render( ggxMesh, _flatCamera ); 3167 3168 // Copy from pingPong back to cubeUV (simple direct copy) 3169 ggxUniforms[ 'envMap' ].value = pingPongRenderTarget.texture; 3170 ggxUniforms[ 'roughness' ].value = 0.0; // Direct copy 3171 ggxUniforms[ 'mipInt' ].value = _lodMax - lodOut; // Read from the level we just wrote 3172 3173 _setViewport( cubeUVRenderTarget, x, y, 3 * outputSize, 2 * outputSize ); 3174 renderer.setRenderTarget( cubeUVRenderTarget ); 3175 renderer.render( ggxMesh, _flatCamera ); 3176 3177 } 3178 3179 /** 3180 * This is a two-pass Gaussian blur for a cubemap. Each pass importance-samples 3181 * the Gaussian along a spiral kernel (Golden Angle), which distributes samples 3182 * isotropically on the sphere (no pole artifacts). 3183 * 3184 * Used for initial scene blur in fromScene() method when sigma > 0. 3185 * 3186 * @private 3187 * @param {WebGLRenderTarget} cubeUVRenderTarget 3188 * @param {number} lodIn 3189 * @param {number} lodOut 3190 * @param {number} sigma 3191 */ 3192 _blur( cubeUVRenderTarget, lodIn, lodOut, sigma ) { 3193 3194 const pingPongRenderTarget = this._pingPongRenderTarget; 3195 3196 // Two passes of sigma / sqrt( 2 ) compose to a blur of sigma while squaring 3197 // the effective sample count. Sigmas beyond PI are visually indistinguishable 3198 // from a uniform blur, so clamp to keep the shader math finite. 3199 const blurSigma = Math.min( sigma, Math.PI ) / Math.SQRT2; 3200 3201 this._blurPass( cubeUVRenderTarget, pingPongRenderTarget, lodIn, lodOut, blurSigma ); 3202 this._blurPass( pingPongRenderTarget, cubeUVRenderTarget, lodOut, lodOut, blurSigma ); 3203 3204 } 3205 3206 _blurPass( targetIn, targetOut, lodIn, lodOut, sigmaRadians ) { 3207 3208 const renderer = this._renderer; 3209 const blurMaterial = this._blurMaterial; 3210 3211 const blurMesh = this._lodMeshes[ lodOut ]; 3212 blurMesh.material = blurMaterial; 3213 3214 const blurUniforms = blurMaterial.uniforms; 3215 3216 blurUniforms[ 'envMap' ].value = targetIn.texture; 3217 blurUniforms[ 'sigma' ].value = sigmaRadians; 3218 blurUniforms[ 'mipInt' ].value = this._lodMax - lodIn; 3219 3220 const outputSize = this._sizeLods[ lodOut ]; 3221 const x = 3 * outputSize * ( lodOut > this._lodMax - LOD_MIN ? lodOut - this._lodMax + LOD_MIN : 0 ); 3222 const y = 4 * ( this._cubeSize - outputSize ); 3223 3224 _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); 3225 renderer.setRenderTarget( targetOut ); 3226 renderer.render( blurMesh, _flatCamera ); 3227 3228 } 3229 3230} 3231 3232 3233 3234function _createPlanes( lodMax ) { 3235 3236 const sizeLods = []; 3237 const lodMeshes = []; 3238 3239 let lod = lodMax; 3240 3241 const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LODS; 3242 3243 for ( let i = 0; i < totalLods; i ++ ) { 3244 3245 const sizeLod = Math.pow( 2, lod ); 3246 sizeLods.push( sizeLod ); 3247 3248 // UVs overshoot the face by one texel to bake the CubeUV border into the directions. 3249 const texelSize = 1.0 / ( sizeLod - 2 ); 3250 const min = - texelSize; 3251 const max = 1 + texelSize; 3252 const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; 3253 3254 const cubeFaces = 6; 3255 const vertices = 6; 3256 const positionSize = 3; 3257 3258 const position = new Float32Array( positionSize * vertices * cubeFaces ); 3259 const outputDirection = new Float32Array( positionSize * vertices * cubeFaces ); 3260 3261 for ( let face = 0; face < cubeFaces; face ++ ) { 3262 3263 const x = ( face % 3 ) * 2 / 3 - 1; 3264 const y = face > 2 ? 0 : -1; 3265 const coordinates = [ 3266 x, y, 0, 3267 x + 2 / 3, y, 0, 3268 x + 2 / 3, y + 1, 0, 3269 x, y, 0, 3270 x + 2 / 3, y + 1, 0, 3271 x, y + 1, 0 3272 ]; 3273 position.set( coordinates, positionSize * vertices * face ); 3274 3275 for ( let vertex = 0; vertex < vertices; vertex ++ ) { 3276 3277 const u = uv1[ vertex * 2 ] * 2 - 1; 3278 const v = uv1[ vertex * 2 + 1 ] * 2 - 1; 3279 3280 // RH coordinate system; PMREM face-indexing convention 3281 if ( face === 0 ) { 3282 3283 _direction.set( 1, v, u ); // pos x 3284 3285 } else if ( face === 1 ) { 3286 3287 _direction.set( - u, 1, - v ); // pos y 3288 3289 } else if ( face === 2 ) { 3290 3291 _direction.set( - u, v, 1 ); // pos z 3292 3293 } else if ( face === 3 ) { 3294 3295 _direction.set( -1, v, - u ); // neg x 3296 3297 } else if ( face === 4 ) { 3298 3299 _direction.set( - u, -1, v ); // neg y 3300 3301 } else { 3302 3303 _direction.set( u, v, -1 ); // neg z 3304 3305 } 3306 3307 _direction.toArray( outputDirection, ( face * vertices + vertex ) * positionSize ); 3308 3309 } 3310 3311 } 3312 3313 const planes = new BufferGeometry(); 3314 planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); 3315 planes.setAttribute( 'outputDirection', new BufferAttribute( outputDirection, positionSize ) ); 3316 lodMeshes.push( new Mesh( planes, null ) ); 3317 3318 if ( lod > LOD_MIN ) { 3319 3320 lod --; 3321 3322 } 3323 3324 } 3325 3326 return { lodMeshes, sizeLods }; 3327 3328} 3329 3330function _createRenderTarget( width, height, params ) { 3331 3332 const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params ); 3333 cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; 3334 cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; 3335 cubeUVRenderTarget.scissorTest = true; 3336 return cubeUVRenderTarget; 3337 3338} 3339 3340function _setViewport( target, x, y, width, height ) { 3341 3342 target.viewport.set( x, y, width, height ); 3343 target.scissor.set( x, y, width, height ); 3344 3345} 3346 3347function _getGGXShader( lodMax, width, height ) { 3348 3349 const shaderMaterial = new ShaderMaterial( { 3350 3351 name: 'PMREMGGXConvolution', 3352 3353 defines: { 3354 'GGX_SAMPLES': GGX_SAMPLES, 3355 'CUBEUV_TEXEL_WIDTH': 1.0 / width, 3356 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, 3357 'CUBEUV_MAX_MIP': `${lodMax}.0`, 3358 }, 3359 3360 uniforms: { 3361 'envMap': { value: null }, 3362 'roughness': { value: 0.0 }, 3363 'mipInt': { value: 0 } 3364 }, 3365 3366 vertexShader: _getCommonVertexShader(), 3367 3368 fragmentShader: /* glsl */` 3369 3370 precision highp float; 3371 precision highp int; 3372 3373 varying vec3 vOutputDirection; 3374 3375 uniform sampler2D envMap; 3376 uniform float roughness; 3377 uniform float mipInt; 3378 3379 #define ENVMAP_TYPE_CUBE_UV 3380 #include <cube_uv_reflection_fragment> 3381 3382 #define PI 3.14159265359 3383 3384 // Van der Corput radical inverse 3385 float radicalInverse_VdC(uint bits) { 3386 bits = (bits << 16u) | (bits >> 16u); 3387 bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); 3388 bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); 3389 bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); 3390 bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); 3391 return float(bits) * 2.3283064365386963e-10; // / 0x100000000 3392 } 3393 3394 // Hammersley sequence 3395 vec2 hammersley(uint i, uint N) { 3396 return vec2(float(i) / float(N), radicalInverse_VdC(i)); 3397 } 3398 3399 // GGX VNDF importance sampling (Eric Heitz 2018) 3400 // "Sampling the GGX Distribution of Visible Normals" 3401 // https://jcgt.org/published/0007/04/01/ 3402 vec3 importanceSampleGGX_VNDF(vec2 Xi, vec3 V, float roughness) { 3403 float alpha = roughness * roughness; 3404 3405 // Section 4.1: Orthonormal basis 3406 vec3 T1 = vec3(1.0, 0.0, 0.0); 3407 vec3 T2 = cross(V, T1); 3408 3409 // Section 4.2: Parameterization of projected area 3410 float r = sqrt(Xi.x); 3411 float phi = 2.0 * PI * Xi.y; 3412 float t1 = r * cos(phi); 3413 float t2 = r * sin(phi); 3414 float s = 0.5 * (1.0 + V.z); 3415 t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2; 3416 3417 // Section 4.3: Reprojection onto hemisphere 3418 vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * V; 3419 3420 // Section 3.4: Transform back to ellipsoid configuration 3421 return normalize(vec3(alpha * Nh.x, alpha * Nh.y, max(0.0, Nh.z))); 3422 } 3423 3424 void main() { 3425 vec3 N = normalize(vOutputDirection); 3426 vec3 V = N; // Assume view direction equals normal for pre-filtering 3427 3428 vec3 prefilteredColor = vec3(0.0); 3429 float totalWeight = 0.0; 3430 3431 // For very low roughness, just sample the environment directly 3432 if (roughness < 0.001) { 3433 gl_FragColor = vec4(bilinearCubeUV(envMap, N, mipInt), 1.0); 3434 return; 3435 } 3436 3437 // Tangent space basis for VNDF sampling 3438 vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); 3439 vec3 tangent = normalize(cross(up, N)); 3440 vec3 bitangent = cross(N, tangent); 3441 3442 for(uint i = 0u; i < uint(GGX_SAMPLES); i++) { 3443 vec2 Xi = hammersley(i, uint(GGX_SAMPLES)); 3444 3445 // For PMREM, V = N, so in tangent space V is always (0, 0, 1) 3446 vec3 H_tangent = importanceSampleGGX_VNDF(Xi, vec3(0.0, 0.0, 1.0), roughness); 3447 3448 // Transform H back to world space 3449 vec3 H = normalize(tangent * H_tangent.x + bitangent * H_tangent.y + N * H_tangent.z); 3450 vec3 L = normalize(2.0 * dot(V, H) * H - V); 3451 3452 float NdotL = max(dot(N, L), 0.0); 3453 3454 if(NdotL > 0.0) { 3455 // Sample environment at fixed mip level 3456 // VNDF importance sampling handles the distribution filtering 3457 vec3 sampleColor = bilinearCubeUV(envMap, L, mipInt); 3458 3459 // Weight by NdotL for the split-sum approximation 3460 // VNDF PDF naturally accounts for the visible microfacet distribution 3461 prefilteredColor += sampleColor * NdotL; 3462 totalWeight += NdotL; 3463 } 3464 } 3465 3466 if (totalWeight > 0.0) { 3467 prefilteredColor = prefilteredColor / totalWeight; 3468 } 3469 3470 gl_FragColor = vec4(prefilteredColor, 1.0); 3471 } 3472 `, 3473 3474 blending: NoBlending, 3475 depthTest: false, 3476 depthWrite: false 3477 3478 } ); 3479 3480 return shaderMaterial; 3481 3482} 3483 3484function _getBlurShader( lodMax, width, height ) { 3485 3486 const shaderMaterial = new ShaderMaterial( { 3487 3488 name: 'SphericalGaussianBlur', 3489 3490 defines: { 3491 'SAMPLES': BLUR_SAMPLES, 3492 'CUBEUV_TEXEL_WIDTH': 1.0 / width, 3493 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, 3494 'CUBEUV_MAX_MIP': `${lodMax}.0`, 3495 }, 3496 3497 uniforms: { 3498 'envMap': { value: null }, 3499 'sigma': { value: 0 }, 3500 'mipInt': { value: 0 }, 3501 }, 3502 3503 vertexShader: _getCommonVertexShader(), 3504 3505 fragmentShader: /* glsl */` 3506 3507 precision highp float; 3508 precision highp int; 3509 3510 varying vec3 vOutputDirection; 3511 3512 uniform sampler2D envMap; 3513 uniform float sigma; 3514 uniform float mipInt; 3515 3516 #define ENVMAP_TYPE_CUBE_UV 3517 #include <cube_uv_reflection_fragment> 3518 3519 #define PI 3.14159265359 3520 #define GOLDEN_ANGLE 2.39996322973 3521 3522 void main() { 3523 3524 if ( sigma == 0.0 ) { 3525 3526 gl_FragColor = vec4( bilinearCubeUV( envMap, vOutputDirection, mipInt ), 1.0 ); 3527 return; 3528 3529 } 3530 3531 vec3 outputDirection = normalize( vOutputDirection ); 3532 3533 vec3 up = abs( outputDirection.z ) < 0.999 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 1.0, 0.0, 0.0 ); 3534 vec3 tangent = normalize( cross( up, outputDirection ) ); 3535 vec3 bitangent = cross( outputDirection, tangent ); 3536 3537 // Truncate the kernel at three standard deviations or at the antipode. 3538 float thetaMax = min( 3.0 * sigma, PI ); 3539 float truncation = 1.0 - exp( - 0.5 * thetaMax * thetaMax / ( sigma * sigma ) ); 3540 3541 vec3 accumColor = vec3( 0.0 ); 3542 float accumWeight = 0.0; 3543 3544 for ( int i = 0; i < SAMPLES; i ++ ) { 3545 3546 // Stratified inverse-CDF sampling of the Gaussian, placed on a golden-angle spiral. 3547 float stratum = ( float( i ) + 0.5 ) / float( SAMPLES ); 3548 float theta = sigma * sqrt( - 2.0 * log( 1.0 - stratum * truncation ) ); 3549 float phi = float( i ) * GOLDEN_ANGLE; 3550 3551 vec3 offset = cos( phi ) * tangent + sin( phi ) * bitangent; 3552 vec3 sampleDirection = cos( theta ) * outputDirection + sin( theta ) * offset; 3553 3554 // Correct the planar sample density to solid angle. 3555 float weight = sin( theta ) / theta; 3556 3557 accumColor += weight * bilinearCubeUV( envMap, sampleDirection, mipInt ); 3558 accumWeight += weight; 3559 3560 } 3561 3562 gl_FragColor = vec4( accumColor / accumWeight, 1.0 ); 3563 3564 } 3565 `, 3566 3567 blending: NoBlending, 3568 depthTest: false, 3569 depthWrite: false 3570 3571 } ); 3572 3573 return shaderMaterial; 3574 3575} 3576 3577function _getEquirectMaterial() { 3578 3579 return new ShaderMaterial( { 3580 3581 name: 'EquirectangularToCubeUV', 3582 3583 uniforms: { 3584 'envMap': { value: null } 3585 }, 3586 3587 vertexShader: _getCommonVertexShader(), 3588 3589 fragmentShader: /* glsl */` 3590 3591 precision mediump float; 3592 precision mediump int; 3593 3594 varying vec3 vOutputDirection; 3595 3596 uniform sampler2D envMap; 3597 3598 #include <common> 3599 3600 void main() { 3601 3602 vec3 outputDirection = normalize( vOutputDirection ); 3603 vec2 uv = equirectUv( outputDirection ); 3604 3605 gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); 3606 3607 } 3608 `, 3609 3610 blending: NoBlending, 3611 depthTest: false, 3612 depthWrite: false 3613 3614 } ); 3615 3616} 3617 3618function _getCubemapMaterial() { 3619 3620 return new ShaderMaterial( { 3621 3622 name: 'CubemapToCubeUV', 3623 3624 uniforms: { 3625 'envMap': { value: null }, 3626 'flipEnvMap': { value: -1 } 3627 }, 3628 3629 vertexShader: _getCommonVertexShader(), 3630 3631 fragmentShader: /* glsl */` 3632 3633 precision mediump float; 3634 precision mediump int; 3635 3636 uniform float flipEnvMap; 3637 3638 varying vec3 vOutputDirection; 3639 3640 uniform samplerCube envMap; 3641 3642 void main() { 3643 3644 gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); 3645 3646 } 3647 `, 3648 3649 blending: NoBlending, 3650 depthTest: false, 3651 depthWrite: false 3652 3653 } ); 3654 3655} 3656 3657function _getCommonVertexShader() { 3658 3659 return /* glsl */` 3660 3661 precision mediump float; 3662 precision mediump int; 3663 3664 attribute vec3 outputDirection; 3665 3666 varying vec3 vOutputDirection; 3667 3668 void main() { 3669 3670 vOutputDirection = outputDirection; 3671 gl_Position = vec4( position, 1.0 ); 3672 3673 } 3674 `; 3675 3676} 3677 3678/** 3679 * A cube render target used in context of {@link WebGLRenderer}. 3680 * 3681 * @augments WebGLRenderTarget 3682 */ 3683class WebGLCubeRenderTarget extends WebGLRenderTarget { 3684 3685 /** 3686 * Constructs a new cube render target. 3687 * 3688 * @param {number} [size=1] - The size of the render target. 3689 * @param {RenderTarget~Options} [options] - The configuration object. 3690 */ 3691 constructor( size = 1, options = {} ) { 3692 3693 super( size, size, options ); 3694 3695 /** 3696 * This flag can be used for type testing. 3697 * 3698 * @type {boolean} 3699 * @readonly 3700 * @default true 3701 */ 3702 this.isWebGLCubeRenderTarget = true; 3703 3704 const image = { width: size, height: size, depth: 1 }; 3705 const images = [ image, image, image, image, image, image ]; 3706 3707 /** 3708 * Overwritten with a different texture type. 3709 * 3710 * @type {DataArrayTexture} 3711 */ 3712 this.texture = new CubeTexture( images ); 3713 this._setTextureOptions( options ); 3714 3715 // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) 3716 // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, 3717 // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. 3718 3719 // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped 3720 // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture 3721 // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). 3722 3723 this.texture.isRenderTargetTexture = true; 3724 3725 } 3726 3727 /** 3728 * Converts the given equirectangular texture to a cube map. 3729 * 3730 * @param {WebGLRenderer} renderer - The renderer. 3731 * @param {Texture} texture - The equirectangular texture. 3732 * @return {WebGLCubeRenderTarget} A reference to this cube render target. 3733 */ 3734 fromEquirectangularTexture( renderer, texture ) { 3735 3736 this.texture.type = texture.type; 3737 this.texture.colorSpace = texture.colorSpace; 3738 3739 this.texture.generateMipmaps = texture.generateMipmaps; 3740 this.texture.minFilter = texture.minFilter; 3741 this.texture.magFilter = texture.magFilter; 3742 3743 const shader = { 3744 3745 uniforms: { 3746 tEquirect: { value: null }, 3747 }, 3748 3749 vertexShader: /* glsl */` 3750 3751 varying vec3 vWorldDirection; 3752 3753 vec3 transformDirection( in vec3 dir, in mat4 matrix ) { 3754 3755 return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); 3756 3757 } 3758 3759 void main() { 3760 3761 vWorldDirection = transformDirection( position, modelMatrix ); 3762 3763 #include <begin_vertex> 3764 #include <project_vertex> 3765 3766 } 3767 `, 3768 3769 fragmentShader: /* glsl */` 3770 3771 uniform sampler2D tEquirect; 3772 3773 varying vec3 vWorldDirection; 3774 3775 #include <common> 3776 3777 void main() { 3778 3779 vec3 direction = normalize( vWorldDirection ); 3780 3781 vec2 sampleUV = equirectUv( direction ); 3782 3783 gl_FragColor = texture2D( tEquirect, sampleUV ); 3784 3785 } 3786 ` 3787 }; 3788 3789 const geometry = new BoxGeometry( 5, 5, 5 ); 3790 3791 const material = new ShaderMaterial( { 3792 3793 name: 'CubemapFromEquirect', 3794 3795 uniforms: cloneUniforms( shader.uniforms ), 3796 vertexShader: shader.vertexShader, 3797 fragmentShader: shader.fragmentShader, 3798 side: BackSide, 3799 blending: NoBlending 3800 3801 } ); 3802 3803 material.uniforms.tEquirect.value = texture; 3804 3805 const mesh = new Mesh( geometry, material ); 3806 3807 const currentMinFilter = texture.minFilter; 3808 3809 // Avoid blurred poles 3810 if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter; 3811 3812 const camera = new CubeCamera( 1, 10, this ); 3813 camera.update( renderer, mesh ); 3814 3815 texture.minFilter = currentMinFilter; 3816 3817 mesh.geometry.dispose(); 3818 mesh.material.dispose(); 3819 3820 return this; 3821 3822 } 3823 3824 /** 3825 * Clears this cube render target. 3826 * 3827 * @param {WebGLRenderer} renderer - The renderer. 3828 * @param {boolean} [color=true] - Whether the color buffer should be cleared or not. 3829 * @param {boolean} [depth=true] - Whether the depth buffer should be cleared or not. 3830 * @param {boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. 3831 */ 3832 clear( renderer, color = true, depth = true, stencil = true ) { 3833 3834 const currentRenderTarget = renderer.getRenderTarget(); 3835 3836 for ( let i = 0; i < 6; i ++ ) { 3837 3838 renderer.setRenderTarget( this, i ); 3839 3840 renderer.clear( color, depth, stencil ); 3841 3842 } 3843 3844 renderer.setRenderTarget( currentRenderTarget ); 3845 3846 } 3847 3848} 3849 3850function WebGLEnvironments( renderer ) { 3851 3852 let cubeMaps = new WeakMap(); 3853 let pmremMaps = new WeakMap(); 3854 3855 let pmremGenerator = null; 3856 3857 function get( texture, usePMREM = false ) { 3858 3859 if ( texture === null || texture === undefined ) return null; 3860 3861 if ( usePMREM ) { 3862 3863 return getPMREM( texture ); 3864 3865 } 3866 3867 return getCube( texture ); 3868 3869 } 3870 3871 function getCube( texture ) { 3872 3873 if ( texture && texture.isTexture ) { 3874 3875 const mapping = texture.mapping; 3876 3877 if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { 3878 3879 if ( cubeMaps.has( texture ) ) { 3880 3881 const cubemap = cubeMaps.get( texture ).texture; 3882 return mapTextureMapping( cubemap, texture.mapping ); 3883 3884 } else { 3885 3886 const image = texture.image; 3887 3888 if ( image && image.height > 0 ) { 3889 3890 const renderTarget = new WebGLCubeRenderTarget( image.height ); 3891 renderTarget.fromEquirectangularTexture( renderer, texture ); 3892 cubeMaps.set( texture, renderTarget ); 3893 3894 texture.addEventListener( 'dispose', onCubemapDispose ); 3895 3896 return mapTextureMapping( renderTarget.texture, texture.mapping ); 3897 3898 } else { 3899 3900 // image not yet ready. try the conversion next frame 3901 3902 return null; 3903 3904 } 3905 3906 } 3907 3908 } 3909 3910 } 3911 3912 return texture; 3913 3914 } 3915 3916 function getPMREM( texture ) { 3917 3918 if ( texture && texture.isTexture ) { 3919 3920 const mapping = texture.mapping; 3921 3922 const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ); 3923 const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); 3924 3925 // equirect/cube map to cubeUV conversion 3926 3927 if ( isEquirectMap || isCubeMap ) { 3928 3929 let renderTarget = pmremMaps.get( texture ); 3930 3931 const currentPMREMVersion = renderTarget !== undefined ? renderTarget.texture.pmremVersion : 0; 3932 3933 if ( texture.isRenderTargetTexture && texture.pmremVersion !== currentPMREMVersion ) { 3934 3935 if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); 3936 3937 renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget ); 3938 renderTarget.texture.pmremVersion = texture.pmremVersion; 3939 3940 pmremMaps.set( texture, renderTarget ); 3941 3942 return renderTarget.texture; 3943 3944 } else { 3945 3946 if ( renderTarget !== undefined ) { 3947 3948 return renderTarget.texture; 3949 3950 } else { 3951 3952 const image = texture.image; 3953 3954 if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) { 3955 3956 if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); 3957 3958 renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture ); 3959 renderTarget.texture.pmremVersion = texture.pmremVersion; 3960 3961 pmremMaps.set( texture, renderTarget ); 3962 3963 texture.addEventListener( 'dispose', onPMREMDispose ); 3964 3965 return renderTarget.texture; 3966 3967 } else { 3968 3969 // image not yet ready. try the conversion next frame 3970 3971 return null; 3972 3973 } 3974 3975 } 3976 3977 } 3978 3979 } 3980 3981 } 3982 3983 return texture; 3984 3985 } 3986 3987 function mapTextureMapping( texture, mapping ) { 3988 3989 if ( mapping === EquirectangularReflectionMapping ) { 3990 3991 texture.mapping = CubeReflectionMapping; 3992 3993 } else if ( mapping === EquirectangularRefractionMapping ) { 3994 3995 texture.mapping = CubeRefractionMapping; 3996 3997 } 3998 3999 return texture; 4000 4001 } 4002 4003 function isCubeTextureComplete( image ) { 4004 4005 let count = 0; 4006 const length = 6; 4007 4008 for ( let i = 0; i < length; i ++ ) { 4009 4010 if ( image[ i ] !== undefined ) count ++; 4011 4012 } 4013 4014 return count === length; 4015 4016 } 4017 4018 function onCubemapDispose( event ) { 4019 4020 const texture = event.target; 4021 4022 texture.removeEventListener( 'dispose', onCubemapDispose ); 4023 4024 const cubemap = cubeMaps.get( texture ); 4025 4026 if ( cubemap !== undefined ) { 4027 4028 cubeMaps.delete( texture ); 4029 cubemap.dispose(); 4030 4031 } 4032 4033 } 4034 4035 function onPMREMDispose( event ) { 4036 4037 const texture = event.target; 4038 4039 texture.removeEventListener( 'dispose', onPMREMDispose ); 4040 4041 const pmrem = pmremMaps.get( texture ); 4042 4043 if ( pmrem !== undefined ) { 4044 4045 pmremMaps.delete( texture ); 4046 pmrem.dispose(); 4047 4048 } 4049 4050 } 4051 4052 function dispose() { 4053 4054 cubeMaps = new WeakMap(); 4055 pmremMaps = new WeakMap(); 4056 4057 if ( pmremGenerator !== null ) { 4058 4059 pmremGenerator.dispose(); 4060 pmremGenerator = null; 4061 4062 } 4063 4064 } 4065 4066 return { 4067 get: get, 4068 dispose: dispose 4069 }; 4070 4071} 4072 4073function WebGLExtensions( gl ) { 4074 4075 const extensions = {}; 4076 4077 function getExtension( name ) { 4078 4079 if ( extensions[ name ] !== undefined ) { 4080 4081 return extensions[ name ]; 4082 4083 } 4084 4085 const extension = gl.getExtension( name ); 4086 4087 extensions[ name ] = extension; 4088 4089 return extension; 4090 4091 } 4092 4093 return { 4094 4095 has: function ( name ) { 4096 4097 return getExtension( name ) !== null; 4098 4099 }, 4100 4101 init: function () { 4102 4103 getExtension( 'EXT_color_buffer_float' ); 4104 getExtension( 'WEBGL_clip_cull_distance' ); 4105 getExtension( 'OES_texture_float_linear' ); 4106 getExtension( 'EXT_color_buffer_half_float' ); 4107 getExtension( 'WEBGL_multisampled_render_to_texture' ); 4108 getExtension( 'WEBGL_render_shared_exponent' ); 4109 4110 }, 4111 4112 get: function ( name ) { 4113 4114 const extension = getExtension( name ); 4115 4116 if ( extension === null ) { 4117 4118 warnOnce( 'WebGLRenderer: ' + name + ' extension not supported.' ); 4119 4120 } 4121 4122 return extension; 4123 4124 } 4125 4126 }; 4127 4128} 4129 4130function WebGLGeometries( gl, attributes, info, bindingStates ) { 4131 4132 const geometries = {}; 4133 const wireframeAttributes = new WeakMap(); 4134 4135 function onGeometryDispose( event ) { 4136 4137 const geometry = event.target; 4138 4139 if ( geometry.index !== null ) { 4140 4141 attributes.remove( geometry.index ); 4142 4143 } 4144 4145 for ( const name in geometry.attributes ) { 4146 4147 attributes.remove( geometry.attributes[ name ] ); 4148 4149 } 4150 4151 geometry.removeEventListener( 'dispose', onGeometryDispose ); 4152 4153 delete geometries[ geometry.id ]; 4154 4155 const attribute = wireframeAttributes.get( geometry ); 4156 4157 if ( attribute ) { 4158 4159 attributes.remove( attribute ); 4160 wireframeAttributes.delete( geometry ); 4161 4162 } 4163 4164 bindingStates.releaseStatesOfGeometry( geometry ); 4165 4166 if ( geometry.isInstancedBufferGeometry === true ) { 4167 4168 delete geometry._maxInstanceCount; 4169 4170 } 4171 4172 // 4173 4174 info.memory.geometries --; 4175 4176 } 4177 4178 function get( object, geometry ) { 4179 4180 if ( geometries[ geometry.id ] === true ) return geometry; 4181 4182 geometry.addEventListener( 'dispose', onGeometryDispose ); 4183 4184 geometries[ geometry.id ] = true; 4185 4186 info.memory.geometries ++; 4187 4188 return geometry; 4189 4190 } 4191 4192 function update( geometry ) { 4193 4194 const geometryAttributes = geometry.attributes; 4195 4196 // Updating index buffer in VAO now. See WebGLBindingStates. 4197 4198 for ( const name in geometryAttributes ) { 4199 4200 attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); 4201 4202 } 4203 4204 } 4205 4206 function updateWireframeAttribute( geometry ) { 4207 4208 const indices = []; 4209 4210 const geometryIndex = geometry.index; 4211 const geometryPosition = geometry.attributes.position; 4212 let version = 0; 4213 4214 if ( geometryPosition === undefined ) { 4215 4216 return; 4217 4218 } 4219 4220 if ( geometryIndex !== null ) { 4221 4222 const array = geometryIndex.array; 4223 version = geometryIndex.version; 4224 4225 for ( let i = 0, l = array.length; i < l; i += 3 ) { 4226 4227 const a = array[ i + 0 ]; 4228 const b = array[ i + 1 ]; 4229 const c = array[ i + 2 ]; 4230 4231 indices.push( a, b, b, c, c, a ); 4232 4233 } 4234 4235 } else { 4236 4237 const array = geometryPosition.array; 4238 version = geometryPosition.version; 4239 4240 for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { 4241 4242 const a = i + 0; 4243 const b = i + 1; 4244 const c = i + 2; 4245 4246 indices.push( a, b, b, c, c, a ); 4247 4248 } 4249 4250 } 4251 4252 // check whether a 32 bit or 16 bit buffer is required to store the indices 4253 // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 4254 const attribute = new ( geometryPosition.count >= 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); 4255 attribute.version = version; 4256 4257 // Updating index buffer in VAO now. See WebGLBindingStates 4258 4259 // 4260 4261 const previousAttribute = wireframeAttributes.get( geometry ); 4262 4263 if ( previousAttribute ) attributes.remove( previousAttribute ); 4264 4265 // 4266 4267 wireframeAttributes.set( geometry, attribute ); 4268 4269 } 4270 4271 function getWireframeAttribute( geometry ) { 4272 4273 const currentAttribute = wireframeAttributes.get( geometry ); 4274 4275 if ( currentAttribute ) { 4276 4277 const geometryIndex = geometry.index; 4278 4279 if ( geometryIndex !== null ) { 4280 4281 // if the attribute is obsolete, create a new one 4282 4283 if ( currentAttribute.version < geometryIndex.version ) { 4284 4285 updateWireframeAttribute( geometry ); 4286 4287 } 4288 4289 } 4290 4291 } else { 4292 4293 updateWireframeAttribute( geometry ); 4294 4295 } 4296 4297 return wireframeAttributes.get( geometry ); 4298 4299 } 4300 4301 return { 4302 4303 get: get, 4304 update: update, 4305 4306 getWireframeAttribute: getWireframeAttribute 4307 4308 }; 4309 4310} 4311 4312function WebGLIndexedBufferRenderer( gl, extensions, info ) { 4313 4314 let mode; 4315 4316 function setMode( value ) { 4317 4318 mode = value; 4319 4320 } 4321 4322 let type, bytesPerElement; 4323 4324 function setIndex( value ) { 4325 4326 type = value.type; 4327 bytesPerElement = value.bytesPerElement; 4328 4329 } 4330 4331 function render( start, count ) { 4332 4333 gl.drawElements( mode, count, type, start * bytesPerElement ); 4334 4335 info.update( count, mode, 1 ); 4336 4337 } 4338 4339 function renderInstances( start, count, primcount ) { 4340 4341 if ( primcount === 0 ) return; 4342 4343 gl.drawElementsInstanced( mode, count, type, start * bytesPerElement, primcount ); 4344 4345 info.update( count, mode, primcount ); 4346 4347 } 4348 4349 function renderMultiDraw( starts, counts, drawCount ) { 4350 4351 if ( drawCount === 0 ) return; 4352 4353 const extension = extensions.get( 'WEBGL_multi_draw' ); 4354 extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount ); 4355 4356 let elementCount = 0; 4357 for ( let i = 0; i < drawCount; i ++ ) { 4358 4359 elementCount += counts[ i ]; 4360 4361 } 4362 4363 info.update( elementCount, mode, 1 ); 4364 4365 4366 } 4367 4368 // 4369 4370 this.setMode = setMode; 4371 this.setIndex = setIndex; 4372 this.render = render; 4373 this.renderInstances = renderInstances; 4374 this.renderMultiDraw = renderMultiDraw; 4375 4376} 4377 4378function WebGLInfo( gl ) { 4379 4380 const memory = { 4381 geometries: 0, 4382 textures: 0 4383 }; 4384 4385 const render = { 4386 frame: 0, 4387 calls: 0, 4388 triangles: 0, 4389 points: 0, 4390 lines: 0 4391 }; 4392 4393 function update( count, mode, instanceCount ) { 4394 4395 render.calls ++; 4396 4397 switch ( mode ) { 4398 4399 case gl.TRIANGLES: 4400 render.triangles += instanceCount * ( count / 3 ); 4401 break; 4402 4403 case gl.LINES: 4404 render.lines += instanceCount * ( count / 2 ); 4405 break; 4406 4407 case gl.LINE_STRIP: 4408 render.lines += instanceCount * ( count - 1 ); 4409 break; 4410 4411 case gl.LINE_LOOP: 4412 render.lines += instanceCount * count; 4413 break; 4414 4415 case gl.POINTS: 4416 render.points += instanceCount * count; 4417 break; 4418 4419 default: 4420 error( 'WebGLInfo: Unknown draw mode:', mode ); 4421 break; 4422 4423 } 4424 4425 } 4426 4427 function reset() { 4428 4429 render.calls = 0; 4430 render.triangles = 0; 4431 render.points = 0; 4432 render.lines = 0; 4433 4434 } 4435 4436 return { 4437 memory: memory, 4438 render: render, 4439 programs: null, 4440 autoReset: true, 4441 reset: reset, 4442 update: update 4443 }; 4444 4445} 4446 4447function WebGLMorphtargets( gl, capabilities, textures ) { 4448 4449 const morphTextures = new WeakMap(); 4450 const morph = new Vector4(); 4451 4452 function update( object, geometry, program ) { 4453 4454 const objectInfluences = object.morphTargetInfluences; 4455 4456 // the following encodes morph targets into an array of data textures. Each layer represents a single morph target. 4457 4458 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 4459 const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; 4460 4461 let entry = morphTextures.get( geometry ); 4462 4463 if ( entry === undefined || entry.count !== morphTargetsCount ) { 4464 4465 if ( entry !== undefined ) entry.texture.dispose(); 4466 4467 const hasMorphPosition = geometry.morphAttributes.position !== undefined; 4468 const hasMorphNormals = geometry.morphAttributes.normal !== undefined; 4469 const hasMorphColors = geometry.morphAttributes.color !== undefined; 4470 4471 const morphTargets = geometry.morphAttributes.position || []; 4472 const morphNormals = geometry.morphAttributes.normal || []; 4473 const morphColors = geometry.morphAttributes.color || []; 4474 4475 let vertexDataCount = 0; 4476 4477 if ( hasMorphPosition === true ) vertexDataCount = 1; 4478 if ( hasMorphNormals === true ) vertexDataCount = 2; 4479 if ( hasMorphColors === true ) vertexDataCount = 3; 4480 4481 let width = geometry.attributes.position.count * vertexDataCount; 4482 let height = 1; 4483 4484 if ( width > capabilities.maxTextureSize ) { 4485 4486 height = Math.ceil( width / capabilities.maxTextureSize ); 4487 width = capabilities.maxTextureSize; 4488 4489 } 4490 4491 const buffer = new Float32Array( width * height * 4 * morphTargetsCount ); 4492 4493 const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount ); 4494 texture.type = FloatType; 4495 texture.needsUpdate = true; 4496 4497 // fill buffer 4498 4499 const vertexDataStride = vertexDataCount * 4; 4500 4501 for ( let i = 0; i < morphTargetsCount; i ++ ) { 4502 4503 const morphTarget = morphTargets[ i ]; 4504 const morphNormal = morphNormals[ i ]; 4505 const morphColor = morphColors[ i ]; 4506 4507 const offset = width * height * 4 * i; 4508 4509 for ( let j = 0; j < morphTarget.count; j ++ ) { 4510 4511 const stride = j * vertexDataStride; 4512 4513 if ( hasMorphPosition === true ) { 4514 4515 morph.fromBufferAttribute( morphTarget, j ); 4516 4517 buffer[ offset + stride + 0 ] = morph.x; 4518 buffer[ offset + stride + 1 ] = morph.y; 4519 buffer[ offset + stride + 2 ] = morph.z; 4520 buffer[ offset + stride + 3 ] = 0; 4521 4522 } 4523 4524 if ( hasMorphNormals === true ) { 4525 4526 morph.fromBufferAttribute( morphNormal, j ); 4527 4528 buffer[ offset + stride + 4 ] = morph.x; 4529 buffer[ offset + stride + 5 ] = morph.y; 4530 buffer[ offset + stride + 6 ] = morph.z; 4531 buffer[ offset + stride + 7 ] = 0; 4532 4533 } 4534 4535 if ( hasMorphColors === true ) { 4536 4537 morph.fromBufferAttribute( morphColor, j ); 4538 4539 buffer[ offset + stride + 8 ] = morph.x; 4540 buffer[ offset + stride + 9 ] = morph.y; 4541 buffer[ offset + stride + 10 ] = morph.z; 4542 buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1; 4543 4544 } 4545 4546 } 4547 4548 } 4549 4550 entry = { 4551 count: morphTargetsCount, 4552 texture: texture, 4553 size: new Vector2( width, height ) 4554 }; 4555 4556 morphTextures.set( geometry, entry ); 4557 4558 function disposeTexture() { 4559 4560 texture.dispose(); 4561 4562 morphTextures.delete( geometry ); 4563 4564 geometry.removeEventListener( 'dispose', disposeTexture ); 4565 4566 } 4567 4568 geometry.addEventListener( 'dispose', disposeTexture ); 4569 4570 } 4571 4572 // 4573 if ( object.isInstancedMesh === true && object.morphTexture !== null ) { 4574 4575 program.getUniforms().setValue( gl, 'morphTexture', object.morphTexture, textures ); 4576 4577 } else { 4578 4579 let morphInfluencesSum = 0; 4580 4581 for ( let i = 0; i < objectInfluences.length; i ++ ) { 4582 4583 morphInfluencesSum += objectInfluences[ i ]; 4584 4585 } 4586 4587 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; 4588 4589 4590 program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); 4591 program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences ); 4592 4593 } 4594 4595 program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures ); 4596 program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size ); 4597 4598 } 4599 4600 return { 4601 4602 update: update 4603 4604 }; 4605 4606} 4607 4608function WebGLObjects( gl, geometries, attributes, bindingStates, info ) { 4609 4610 let updateMap = new WeakMap(); 4611 4612 function update( object ) { 4613 4614 const frame = info.render.frame; 4615 4616 const geometry = object.geometry; 4617 const buffergeometry = geometries.get( object, geometry ); 4618 4619 // Update once per frame 4620 4621 if ( updateMap.get( buffergeometry ) !== frame ) { 4622 4623 geometries.update( buffergeometry ); 4624 4625 updateMap.set( buffergeometry, frame ); 4626 4627 } 4628 4629 if ( object.isInstancedMesh ) { 4630 4631 if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) { 4632 4633 object.addEventListener( 'dispose', onInstancedMeshDispose ); 4634 4635 } 4636 4637 if ( updateMap.get( object ) !== frame ) { 4638 4639 attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER ); 4640 4641 if ( object.instanceColor !== null ) { 4642 4643 attributes.update( object.instanceColor, gl.ARRAY_BUFFER ); 4644 4645 } 4646 4647 updateMap.set( object, frame ); 4648 4649 } 4650 4651 } 4652 4653 if ( object.isSkinnedMesh ) { 4654 4655 const skeleton = object.skeleton; 4656 4657 if ( updateMap.get( skeleton ) !== frame ) { 4658 4659 skeleton.update(); 4660 4661 updateMap.set( skeleton, frame ); 4662 4663 } 4664 4665 } 4666 4667 return buffergeometry; 4668 4669 } 4670 4671 function dispose() { 4672 4673 updateMap = new WeakMap(); 4674 4675 } 4676 4677 function onInstancedMeshDispose( event ) { 4678 4679 const instancedMesh = event.target; 4680 4681 instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose ); 4682 4683 bindingStates.releaseStatesOfObject( instancedMesh ); 4684 4685 attributes.remove( instancedMesh.instanceMatrix ); 4686 4687 if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor ); 4688 4689 } 4690 4691 return { 4692 4693 update: update, 4694 dispose: dispose 4695 4696 }; 4697 4698} 4699 4700const toneMappingMap = { 4701 [ LinearToneMapping ]: 'LINEAR_TONE_MAPPING', 4702 [ ReinhardToneMapping ]: 'REINHARD_TONE_MAPPING', 4703 [ CineonToneMapping ]: 'CINEON_TONE_MAPPING', 4704 [ ACESFilmicToneMapping ]: 'ACES_FILMIC_TONE_MAPPING', 4705 [ AgXToneMapping ]: 'AGX_TONE_MAPPING', 4706 [ NeutralToneMapping ]: 'NEUTRAL_TONE_MAPPING', 4707 [ CustomToneMapping ]: 'CUSTOM_TONE_MAPPING' 4708}; 4709 4710function WebGLOutput( type, width, height, antialias, depth, stencil ) { 4711 4712 // render target for the scene pass (potentially multisampled) 4713 const targetScene = new WebGLRenderTarget( width, height, { 4714 type: type, 4715 depthBuffer: depth, 4716 stencilBuffer: stencil, 4717 samples: antialias ? 4 : 0, 4718 storeMultisampledDepthBuffer: false, 4719 storeMultisampledStencilBuffer: false, 4720 resolveDepthBuffer: false, 4721 resolveStencilBuffer: false 4722 } ); 4723 4724 // single-sampled ping-pong buffers for post-processing effects, allocated on demand 4725 let targetA = null; 4726 let targetB = null; 4727 4728 // create fullscreen triangle geometry 4729 const geometry = new BufferGeometry(); 4730 geometry.setAttribute( 'position', new Float32BufferAttribute( [ -1, 3, 0, -1, -1, 0, 3, -1, 0 ], 3 ) ); 4731 geometry.setAttribute( 'uv', new Float32BufferAttribute( [ 0, 2, 0, 0, 2, 0 ], 2 ) ); 4732 4733 // create output material with tone mapping support 4734 const material = new RawShaderMaterial( { 4735 uniforms: { 4736 tDiffuse: { value: null } 4737 }, 4738 vertexShader: /* glsl */` 4739 precision highp float; 4740 4741 uniform mat4 modelViewMatrix; 4742 uniform mat4 projectionMatrix; 4743 4744 attribute vec3 position; 4745 attribute vec2 uv; 4746 4747 varying vec2 vUv; 4748 4749 void main() { 4750 vUv = uv; 4751 gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 4752 }`, 4753 fragmentShader: /* glsl */` 4754 precision highp float; 4755 4756 uniform sampler2D tDiffuse; 4757 4758 varying vec2 vUv; 4759 4760 #include <tonemapping_pars_fragment> 4761 #include <colorspace_pars_fragment> 4762 4763 void main() { 4764 gl_FragColor = texture2D( tDiffuse, vUv ); 4765 4766 #ifdef LINEAR_TONE_MAPPING 4767 gl_FragColor.rgb = LinearToneMapping( gl_FragColor.rgb ); 4768 #elif defined( REINHARD_TONE_MAPPING ) 4769 gl_FragColor.rgb = ReinhardToneMapping( gl_FragColor.rgb ); 4770 #elif defined( CINEON_TONE_MAPPING ) 4771 gl_FragColor.rgb = CineonToneMapping( gl_FragColor.rgb ); 4772 #elif defined( ACES_FILMIC_TONE_MAPPING ) 4773 gl_FragColor.rgb = ACESFilmicToneMapping( gl_FragColor.rgb ); 4774 #elif defined( AGX_TONE_MAPPING ) 4775 gl_FragColor.rgb = AgXToneMapping( gl_FragColor.rgb ); 4776 #elif defined( NEUTRAL_TONE_MAPPING ) 4777 gl_FragColor.rgb = NeutralToneMapping( gl_FragColor.rgb ); 4778 #elif defined( CUSTOM_TONE_MAPPING ) 4779 gl_FragColor.rgb = CustomToneMapping( gl_FragColor.rgb ); 4780 #endif 4781 4782 #ifdef SRGB_TRANSFER 4783 gl_FragColor = sRGBTransferOETF( gl_FragColor ); 4784 #endif 4785 }`, 4786 depthTest: false, 4787 depthWrite: false 4788 } ); 4789 4790 const mesh = new Mesh( geometry, material ); 4791 const camera = new OrthographicCamera( -1, 1, 1, -1, 0, 1 ); 4792 4793 let _outputColorSpace = null; 4794 let _outputToneMapping = null; 4795 let _isCompositing = false; 4796 let _savedToneMapping; 4797 let _savedRenderTarget = null; 4798 let _effects = []; 4799 let _hasRenderPass = false; 4800 4801 this.setSize = function ( width, height ) { 4802 4803 targetScene.setSize( width, height ); 4804 4805 if ( targetA !== null ) targetA.setSize( width, height ); 4806 if ( targetB !== null ) targetB.setSize( width, height ); 4807 4808 for ( let i = 0; i < _effects.length; i ++ ) { 4809 4810 const effect = _effects[ i ]; 4811 if ( effect.setSize ) effect.setSize( width, height ); 4812 4813 } 4814 4815 }; 4816 4817 this.setEffects = function ( effects ) { 4818 4819 _effects = effects; 4820 _hasRenderPass = _effects.length > 0 && _effects[ 0 ].isRenderPass === true; 4821 4822 const width = targetScene.width; 4823 const height = targetScene.height; 4824 4825 if ( _effects.length > 0 && targetA === null ) { 4826 4827 targetA = new WebGLRenderTarget( width, height, { type: HalfFloatType, depthBuffer: false, stencilBuffer: false } ); 4828 targetB = new WebGLRenderTarget( width, height, { type: HalfFloatType, depthBuffer: false, stencilBuffer: false } ); 4829 4830 } 4831 4832 for ( let i = 0; i < _effects.length; i ++ ) { 4833 4834 const effect = _effects[ i ]; 4835 if ( effect.setSize ) effect.setSize( width, height ); 4836 4837 } 4838 4839 }; 4840 4841 this.begin = function ( renderer, renderTarget ) { 4842 4843 // Don't begin during compositing phase (post-processing effects call render()) 4844 if ( _isCompositing ) return false; 4845 4846 if ( renderer.toneMapping === NoToneMapping && _effects.length === 0 ) return false; 4847 4848 _savedRenderTarget = renderTarget; 4849 4850 // resize internal buffers to match render target (e.g. XR resolution) 4851 if ( renderTarget !== null ) { 4852 4853 const width = renderTarget.width; 4854 const height = renderTarget.height; 4855 4856 if ( targetScene.width !== width || targetScene.height !== height ) { 4857 4858 this.setSize( width, height ); 4859 4860 } 4861 4862 } 4863 4864 // if the first effect is a RenderPass, it renders the scene itself (see end()) 4865 if ( _hasRenderPass === false ) { 4866 4867 renderer.setRenderTarget( targetScene ); 4868 4869 } 4870 4871 // disable tone mapping during render - it will be applied in end() 4872 _savedToneMapping = renderer.toneMapping; 4873 renderer.toneMapping = NoToneMapping; 4874 4875 return true; 4876 4877 }; 4878 4879 this.hasRenderPass = function () { 4880 4881 return _hasRenderPass; 4882 4883 }; 4884 4885 this.end = function ( renderer, deltaTime ) { 4886 4887 // restore tone mapping 4888 renderer.toneMapping = _savedToneMapping; 4889 4890 _isCompositing = true; 4891 4892 // run post-processing effects - the scene lives in the multisampled targetScene, 4893 // effects ping-pong between the single-sampled targetA and targetB 4894 let readBuffer = targetScene; 4895 let writeBuffer = targetA; 4896 4897 for ( let i = 0; i < _effects.length; i ++ ) { 4898 4899 const effect = _effects[ i ]; 4900 4901 if ( effect.enabled === false ) continue; 4902 4903 effect.render( renderer, writeBuffer, readBuffer, deltaTime ); 4904 4905 if ( effect.needsSwap !== false ) { 4906 4907 // keep targetScene out of the rotation so only the scene pass is multisampled 4908 readBuffer = writeBuffer; 4909 writeBuffer = ( writeBuffer === targetA ) ? targetB : targetA; 4910 4911 } 4912 4913 } 4914 4915 // update output material defines if settings changed 4916 if ( _outputColorSpace !== renderer.outputColorSpace || _outputToneMapping !== renderer.toneMapping ) { 4917 4918 _outputColorSpace = renderer.outputColorSpace; 4919 _outputToneMapping = renderer.toneMapping; 4920 4921 material.defines = {}; 4922 4923 if ( ColorManagement.getTransfer( _outputColorSpace ) === SRGBTransfer ) material.defines.SRGB_TRANSFER = ''; 4924 4925 const toneMapping = toneMappingMap[ _outputToneMapping ]; 4926 if ( toneMapping ) material.defines[ toneMapping ] = ''; 4927 4928 material.needsUpdate = true; 4929 4930 } 4931 4932 // final output to canvas (or XR render target) 4933 material.uniforms.tDiffuse.value = readBuffer.texture; 4934 renderer.setRenderTarget( _savedRenderTarget ); 4935 renderer.render( mesh, camera ); 4936 4937 _savedRenderTarget = null; 4938 _isCompositing = false; 4939 4940 }; 4941 4942 this.isCompositing = function () { 4943 4944 return _isCompositing; 4945 4946 }; 4947 4948 this.dispose = function () { 4949 4950 targetScene.dispose(); 4951 4952 if ( targetA !== null ) targetA.dispose(); 4953 if ( targetB !== null ) targetB.dispose(); 4954 4955 geometry.dispose(); 4956 material.dispose(); 4957 4958 }; 4959 4960} 4961 4962/** 4963 * Uniforms of a program. 4964 * Those form a tree structure with a special top-level container for the root, 4965 * which you get by calling 'new WebGLUniforms( gl, program )'. 4966 * 4967 * 4968 * Properties of inner nodes including the top-level container: 4969 * 4970 * .seq - array of nested uniforms 4971 * .map - nested uniforms by name 4972 * 4973 * 4974 * Methods of all nodes except the top-level container: 4975 * 4976 * .setValue( gl, value, [textures] ) 4977 * 4978 * uploads a uniform value(s) 4979 * the 'textures' parameter is needed for sampler uniforms 4980 * 4981 * 4982 * Static methods of the top-level container (textures factorizations): 4983 * 4984 * .upload( gl, seq, values, textures ) 4985 * 4986 * sets uniforms in 'seq' to 'values[id].value' 4987 * 4988 * .seqWithValue( seq, values ) : filteredSeq 4989 * 4990 * filters 'seq' entries with corresponding entry in values 4991 * 4992 * 4993 * Methods of the top-level container (textures factorizations): 4994 * 4995 * .setValue( gl, name, value, textures ) 4996 * 4997 * sets uniform with name 'name' to 'value' 4998 * 4999 * .setOptional( gl, obj, prop ) 5000 * 5001 * like .set for an optional property of the object 5002 * 5003 */ 5004 5005 5006const emptyTexture = /*@__PURE__*/ new Texture(); 5007 5008const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 ); 5009 5010const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); 5011const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); 5012const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); 5013 5014// --- Utilities --- 5015 5016// Array Caches (provide typed arrays for temporary by size) 5017 5018const arrayCacheF32 = []; 5019const arrayCacheI32 = []; 5020 5021// Float32Array caches used for uploading Matrix uniforms 5022 5023const mat4array = new Float32Array( 16 ); 5024const mat3array = new Float32Array( 9 ); 5025const mat2array = new Float32Array( 4 ); 5026 5027// Flattening for arrays of vectors and matrices 5028 5029function flatten( array, nBlocks, blockSize ) { 5030 5031 const firstElem = array[ 0 ]; 5032 5033 if ( firstElem <= 0 || firstElem > 0 ) return array; 5034 // unoptimized: ! isNaN( firstElem ) 5035 // see http://jacksondunstan.com/articles/983 5036 5037 const n = nBlocks * blockSize; 5038 let r = arrayCacheF32[ n ]; 5039 5040 if ( r === undefined ) { 5041 5042 r = new Float32Array( n ); 5043 arrayCacheF32[ n ] = r; 5044 5045 } 5046 5047 if ( nBlocks !== 0 ) { 5048 5049 firstElem.toArray( r, 0 ); 5050 5051 for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) { 5052 5053 offset += blockSize; 5054 array[ i ].toArray( r, offset ); 5055 5056 } 5057 5058 } 5059 5060 return r; 5061 5062} 5063 5064function arraysEqual( a, b ) { 5065 5066 if ( a.length !== b.length ) return false; 5067 5068 for ( let i = 0, l = a.length; i < l; i ++ ) { 5069 5070 if ( a[ i ] !== b[ i ] ) return false; 5071 5072 } 5073 5074 return true; 5075 5076} 5077 5078function copyArray( a, b ) { 5079 5080 for ( let i = 0, l = b.length; i < l; i ++ ) { 5081 5082 a[ i ] = b[ i ]; 5083 5084 } 5085 5086} 5087 5088// Texture unit allocation 5089 5090function allocTexUnits( textures, n ) { 5091 5092 let r = arrayCacheI32[ n ]; 5093 5094 if ( r === undefined ) { 5095 5096 r = new Int32Array( n ); 5097 arrayCacheI32[ n ] = r; 5098 5099 } 5100 5101 for ( let i = 0; i !== n; ++ i ) { 5102 5103 r[ i ] = textures.allocateTextureUnit(); 5104 5105 } 5106 5107 return r; 5108 5109} 5110 5111// --- Setters --- 5112 5113// Note: Defining these methods externally, because they come in a bunch 5114// and this way their names minify. 5115 5116// Single scalar 5117 5118function setValueV1f( gl, v ) { 5119 5120 const cache = this.cache; 5121 5122 if ( cache[ 0 ] === v ) return; 5123 5124 gl.uniform1f( this.addr, v ); 5125 5126 cache[ 0 ] = v; 5127 5128} 5129 5130// Single float vector (from flat array or THREE.VectorN) 5131 5132function setValueV2f( gl, v ) { 5133 5134 const cache = this.cache; 5135 5136 if ( v.x !== undefined ) { 5137 5138 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { 5139 5140 gl.uniform2f( this.addr, v.x, v.y ); 5141 5142 cache[ 0 ] = v.x; 5143 cache[ 1 ] = v.y; 5144 5145 } 5146 5147 } else { 5148 5149 if ( arraysEqual( cache, v ) ) return; 5150 5151 gl.uniform2fv( this.addr, v ); 5152 5153 copyArray( cache, v ); 5154 5155 } 5156 5157} 5158 5159function setValueV3f( gl, v ) { 5160 5161 const cache = this.cache; 5162 5163 if ( v.x !== undefined ) { 5164 5165 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { 5166 5167 gl.uniform3f( this.addr, v.x, v.y, v.z ); 5168 5169 cache[ 0 ] = v.x; 5170 cache[ 1 ] = v.y; 5171 cache[ 2 ] = v.z; 5172 5173 } 5174 5175 } else if ( v.r !== undefined ) { 5176 5177 if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { 5178 5179 gl.uniform3f( this.addr, v.r, v.g, v.b ); 5180 5181 cache[ 0 ] = v.r; 5182 cache[ 1 ] = v.g; 5183 cache[ 2 ] = v.b; 5184 5185 } 5186 5187 } else { 5188 5189 if ( arraysEqual( cache, v ) ) return; 5190 5191 gl.uniform3fv( this.addr, v ); 5192 5193 copyArray( cache, v ); 5194 5195 } 5196 5197} 5198 5199function setValueV4f( gl, v ) { 5200 5201 const cache = this.cache; 5202 5203 if ( v.x !== undefined ) { 5204 5205 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { 5206 5207 gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); 5208 5209 cache[ 0 ] = v.x; 5210 cache[ 1 ] = v.y; 5211 cache[ 2 ] = v.z; 5212 cache[ 3 ] = v.w; 5213 5214 } 5215 5216 } else { 5217 5218 if ( arraysEqual( cache, v ) ) return; 5219 5220 gl.uniform4fv( this.addr, v ); 5221 5222 copyArray( cache, v ); 5223 5224 } 5225 5226} 5227 5228// Single matrix (from flat array or THREE.MatrixN) 5229 5230function setValueM2( gl, v ) { 5231 5232 const cache = this.cache; 5233 const elements = v.elements; 5234 5235 if ( elements === undefined ) { 5236 5237 if ( arraysEqual( cache, v ) ) return; 5238 5239 gl.uniformMatrix2fv( this.addr, false, v ); 5240 5241 copyArray( cache, v ); 5242 5243 } else { 5244 5245 if ( arraysEqual( cache, elements ) ) return; 5246 5247 mat2array.set( elements ); 5248 5249 gl.uniformMatrix2fv( this.addr, false, mat2array ); 5250 5251 copyArray( cache, elements ); 5252 5253 } 5254 5255} 5256 5257function setValueM3( gl, v ) { 5258 5259 const cache = this.cache; 5260 const elements = v.elements; 5261 5262 if ( elements === undefined ) { 5263 5264 if ( arraysEqual( cache, v ) ) return; 5265 5266 gl.uniformMatrix3fv( this.addr, false, v ); 5267 5268 copyArray( cache, v ); 5269 5270 } else { 5271 5272 if ( arraysEqual( cache, elements ) ) return; 5273 5274 mat3array.set( elements ); 5275 5276 gl.uniformMatrix3fv( this.addr, false, mat3array ); 5277 5278 copyArray( cache, elements ); 5279 5280 } 5281 5282} 5283 5284function setValueM4( gl, v ) { 5285 5286 const cache = this.cache; 5287 const elements = v.elements; 5288 5289 if ( elements === undefined ) { 5290 5291 if ( arraysEqual( cache, v ) ) return; 5292 5293 gl.uniformMatrix4fv( this.addr, false, v ); 5294 5295 copyArray( cache, v ); 5296 5297 } else { 5298 5299 if ( arraysEqual( cache, elements ) ) return; 5300 5301 mat4array.set( elements ); 5302 5303 gl.uniformMatrix4fv( this.addr, false, mat4array ); 5304 5305 copyArray( cache, elements ); 5306 5307 } 5308 5309} 5310 5311// Single integer / boolean 5312 5313function setValueV1i( gl, v ) { 5314 5315 const cache = this.cache; 5316 5317 if ( cache[ 0 ] === v ) return; 5318 5319 gl.uniform1i( this.addr, v ); 5320 5321 cache[ 0 ] = v; 5322 5323} 5324 5325// Single integer / boolean vector (from flat array or THREE.VectorN) 5326 5327function setValueV2i( gl, v ) { 5328 5329 const cache = this.cache; 5330 5331 if ( v.x !== undefined ) { 5332 5333 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { 5334 5335 gl.uniform2i( this.addr, v.x, v.y ); 5336 5337 cache[ 0 ] = v.x; 5338 cache[ 1 ] = v.y; 5339 5340 } 5341 5342 } else { 5343 5344 if ( arraysEqual( cache, v ) ) return; 5345 5346 gl.uniform2iv( this.addr, v ); 5347 5348 copyArray( cache, v ); 5349 5350 } 5351 5352} 5353 5354function setValueV3i( gl, v ) { 5355 5356 const cache = this.cache; 5357 5358 if ( v.x !== undefined ) { 5359 5360 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { 5361 5362 gl.uniform3i( this.addr, v.x, v.y, v.z ); 5363 5364 cache[ 0 ] = v.x; 5365 cache[ 1 ] = v.y; 5366 cache[ 2 ] = v.z; 5367 5368 } 5369 5370 } else { 5371 5372 if ( arraysEqual( cache, v ) ) return; 5373 5374 gl.uniform3iv( this.addr, v ); 5375 5376 copyArray( cache, v ); 5377 5378 } 5379 5380} 5381 5382function setValueV4i( gl, v ) { 5383 5384 const cache = this.cache; 5385 5386 if ( v.x !== undefined ) { 5387 5388 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { 5389 5390 gl.uniform4i( this.addr, v.x, v.y, v.z, v.w ); 5391 5392 cache[ 0 ] = v.x; 5393 cache[ 1 ] = v.y; 5394 cache[ 2 ] = v.z; 5395 cache[ 3 ] = v.w; 5396 5397 } 5398 5399 } else { 5400 5401 if ( arraysEqual( cache, v ) ) return; 5402 5403 gl.uniform4iv( this.addr, v ); 5404 5405 copyArray( cache, v ); 5406 5407 } 5408 5409} 5410 5411// Single unsigned integer 5412 5413function setValueV1ui( gl, v ) { 5414 5415 const cache = this.cache; 5416 5417 if ( cache[ 0 ] === v ) return; 5418 5419 gl.uniform1ui( this.addr, v ); 5420 5421 cache[ 0 ] = v; 5422 5423} 5424 5425// Single unsigned integer vector (from flat array or THREE.VectorN) 5426 5427function setValueV2ui( gl, v ) { 5428 5429 const cache = this.cache; 5430 5431 if ( v.x !== undefined ) { 5432 5433 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { 5434 5435 gl.uniform2ui( this.addr, v.x, v.y ); 5436 5437 cache[ 0 ] = v.x; 5438 cache[ 1 ] = v.y; 5439 5440 } 5441 5442 } else { 5443 5444 if ( arraysEqual( cache, v ) ) return; 5445 5446 gl.uniform2uiv( this.addr, v ); 5447 5448 copyArray( cache, v ); 5449 5450 } 5451 5452} 5453 5454function setValueV3ui( gl, v ) { 5455 5456 const cache = this.cache; 5457 5458 if ( v.x !== undefined ) { 5459 5460 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { 5461 5462 gl.uniform3ui( this.addr, v.x, v.y, v.z ); 5463 5464 cache[ 0 ] = v.x; 5465 cache[ 1 ] = v.y; 5466 cache[ 2 ] = v.z; 5467 5468 } 5469 5470 } else { 5471 5472 if ( arraysEqual( cache, v ) ) return; 5473 5474 gl.uniform3uiv( this.addr, v ); 5475 5476 copyArray( cache, v ); 5477 5478 } 5479 5480} 5481 5482function setValueV4ui( gl, v ) { 5483 5484 const cache = this.cache; 5485 5486 if ( v.x !== undefined ) { 5487 5488 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { 5489 5490 gl.uniform4ui( this.addr, v.x, v.y, v.z, v.w ); 5491 5492 cache[ 0 ] = v.x; 5493 cache[ 1 ] = v.y; 5494 cache[ 2 ] = v.z; 5495 cache[ 3 ] = v.w; 5496 5497 } 5498 5499 } else { 5500 5501 if ( arraysEqual( cache, v ) ) return; 5502 5503 gl.uniform4uiv( this.addr, v ); 5504 5505 copyArray( cache, v ); 5506 5507 } 5508 5509} 5510 5511 5512// Single texture (2D / Cube) 5513 5514function setValueT1( gl, v, textures ) { 5515 5516 const cache = this.cache; 5517 const unit = textures.allocateTextureUnit(); 5518 5519 if ( cache[ 0 ] !== unit ) { 5520 5521 gl.uniform1i( this.addr, unit ); 5522 cache[ 0 ] = unit; 5523 5524 } 5525 5526 let emptyTexture2D; 5527 5528 if ( this.type === gl.SAMPLER_2D_SHADOW ) { 5529 5530 emptyShadowTexture.compareFunction = textures.isReversedDepthBuffer() ? GreaterEqualCompare : LessEqualCompare; 5531 emptyTexture2D = emptyShadowTexture; 5532 5533 } else { 5534 5535 emptyTexture2D = emptyTexture; 5536 5537 } 5538 5539 textures.setTexture2D( v || emptyTexture2D, unit ); 5540 5541} 5542 5543function setValueT3D1( gl, v, textures ) { 5544 5545 const cache = this.cache; 5546 const unit = textures.allocateTextureUnit(); 5547 5548 if ( cache[ 0 ] !== unit ) { 5549 5550 gl.uniform1i( this.addr, unit ); 5551 cache[ 0 ] = unit; 5552 5553 } 5554 5555 textures.setTexture3D( v || empty3dTexture, unit ); 5556 5557} 5558 5559function setValueT6( gl, v, textures ) { 5560 5561 const cache = this.cache; 5562 const unit = textures.allocateTextureUnit(); 5563 5564 if ( cache[ 0 ] !== unit ) { 5565 5566 gl.uniform1i( this.addr, unit ); 5567 cache[ 0 ] = unit; 5568 5569 } 5570 5571 textures.setTextureCube( v || emptyCubeTexture, unit ); 5572 5573} 5574 5575function setValueT2DArray1( gl, v, textures ) { 5576 5577 const cache = this.cache; 5578 const unit = textures.allocateTextureUnit(); 5579 5580 if ( cache[ 0 ] !== unit ) { 5581 5582 gl.uniform1i( this.addr, unit ); 5583 cache[ 0 ] = unit; 5584 5585 } 5586 5587 textures.setTexture2DArray( v || emptyArrayTexture, unit ); 5588 5589} 5590 5591// Helper to pick the right setter for the singular case 5592 5593function getSingularSetter( type ) { 5594 5595 switch ( type ) { 5596 5597 case 0x1406: return setValueV1f; // FLOAT 5598 case 0x8b50: return setValueV2f; // _VEC2 5599 case 0x8b51: return setValueV3f; // _VEC3 5600 case 0x8b52: return setValueV4f; // _VEC4 5601 5602 case 0x8b5a: return setValueM2; // _MAT2 5603 case 0x8b5b: return setValueM3; // _MAT3 5604 case 0x8b5c: return setValueM4; // _MAT4 5605 5606 case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL 5607 case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2 5608 case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3 5609 case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4 5610 5611 case 0x1405: return setValueV1ui; // UINT 5612 case 0x8dc6: return setValueV2ui; // _VEC2 5613 case 0x8dc7: return setValueV3ui; // _VEC3 5614 case 0x8dc8: return setValueV4ui; // _VEC4 5615 5616 case 0x8b5e: // SAMPLER_2D 5617 case 0x8d66: // SAMPLER_EXTERNAL_OES 5618 case 0x8dca: // INT_SAMPLER_2D 5619 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D 5620 case 0x8b62: // SAMPLER_2D_SHADOW 5621 return setValueT1; 5622 5623 case 0x8b5f: // SAMPLER_3D 5624 case 0x8dcb: // INT_SAMPLER_3D 5625 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D 5626 return setValueT3D1; 5627 5628 case 0x8b60: // SAMPLER_CUBE 5629 case 0x8dcc: // INT_SAMPLER_CUBE 5630 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE 5631 case 0x8dc5: // SAMPLER_CUBE_SHADOW 5632 return setValueT6; 5633 5634 case 0x8dc1: // SAMPLER_2D_ARRAY 5635 case 0x8dcf: // INT_SAMPLER_2D_ARRAY 5636 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY 5637 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW 5638 return setValueT2DArray1; 5639 5640 } 5641 5642} 5643 5644 5645// Array of scalars 5646 5647function setValueV1fArray( gl, v ) { 5648 5649 gl.uniform1fv( this.addr, v ); 5650 5651} 5652 5653// Array of vectors (from flat array or array of THREE.VectorN) 5654 5655function setValueV2fArray( gl, v ) { 5656 5657 const data = flatten( v, this.size, 2 ); 5658 5659 gl.uniform2fv( this.addr, data ); 5660 5661} 5662 5663function setValueV3fArray( gl, v ) { 5664 5665 const data = flatten( v, this.size, 3 ); 5666 5667 gl.uniform3fv( this.addr, data ); 5668 5669} 5670 5671function setValueV4fArray( gl, v ) { 5672 5673 const data = flatten( v, this.size, 4 ); 5674 5675 gl.uniform4fv( this.addr, data ); 5676 5677} 5678 5679// Array of matrices (from flat array or array of THREE.MatrixN) 5680 5681function setValueM2Array( gl, v ) { 5682 5683 const data = flatten( v, this.size, 4 ); 5684 5685 gl.uniformMatrix2fv( this.addr, false, data ); 5686 5687} 5688 5689function setValueM3Array( gl, v ) { 5690 5691 const data = flatten( v, this.size, 9 ); 5692 5693 gl.uniformMatrix3fv( this.addr, false, data ); 5694 5695} 5696 5697function setValueM4Array( gl, v ) { 5698 5699 const data = flatten( v, this.size, 16 ); 5700 5701 gl.uniformMatrix4fv( this.addr, false, data ); 5702 5703} 5704 5705// Array of integer / boolean 5706 5707function setValueV1iArray( gl, v ) { 5708 5709 gl.uniform1iv( this.addr, v ); 5710 5711} 5712 5713// Array of integer / boolean vectors (from flat array) 5714 5715function setValueV2iArray( gl, v ) { 5716 5717 gl.uniform2iv( this.addr, v ); 5718 5719} 5720 5721function setValueV3iArray( gl, v ) { 5722 5723 gl.uniform3iv( this.addr, v ); 5724 5725} 5726 5727function setValueV4iArray( gl, v ) { 5728 5729 gl.uniform4iv( this.addr, v ); 5730 5731} 5732 5733// Array of unsigned integer 5734 5735function setValueV1uiArray( gl, v ) { 5736 5737 gl.uniform1uiv( this.addr, v ); 5738 5739} 5740 5741// Array of unsigned integer vectors (from flat array) 5742 5743function setValueV2uiArray( gl, v ) { 5744 5745 gl.uniform2uiv( this.addr, v ); 5746 5747} 5748 5749function setValueV3uiArray( gl, v ) { 5750 5751 gl.uniform3uiv( this.addr, v ); 5752 5753} 5754 5755function setValueV4uiArray( gl, v ) { 5756 5757 gl.uniform4uiv( this.addr, v ); 5758 5759} 5760 5761 5762// Array of textures (2D / 3D / Cube / 2DArray) 5763 5764function setValueT1Array( gl, v, textures ) { 5765 5766 const cache = this.cache; 5767 5768 const n = v.length; 5769 5770 const units = allocTexUnits( textures, n ); 5771 5772 if ( ! arraysEqual( cache, units ) ) { 5773 5774 gl.uniform1iv( this.addr, units ); 5775 5776 copyArray( cache, units ); 5777 5778 } 5779 5780 let emptyTexture2D; 5781 5782 if ( this.type === gl.SAMPLER_2D_SHADOW ) { 5783 5784 emptyTexture2D = emptyShadowTexture; 5785 5786 } else { 5787 5788 emptyTexture2D = emptyTexture; 5789 5790 } 5791 5792 for ( let i = 0; i !== n; ++ i ) { 5793 5794 textures.setTexture2D( v[ i ] || emptyTexture2D, units[ i ] ); 5795 5796 } 5797 5798} 5799 5800function setValueT3DArray( gl, v, textures ) { 5801 5802 const cache = this.cache; 5803 5804 const n = v.length; 5805 5806 const units = allocTexUnits( textures, n ); 5807 5808 if ( ! arraysEqual( cache, units ) ) { 5809 5810 gl.uniform1iv( this.addr, units ); 5811 5812 copyArray( cache, units ); 5813 5814 } 5815 5816 for ( let i = 0; i !== n; ++ i ) { 5817 5818 textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] ); 5819 5820 } 5821 5822} 5823 5824function setValueT6Array( gl, v, textures ) { 5825 5826 const cache = this.cache; 5827 5828 const n = v.length; 5829 5830 const units = allocTexUnits( textures, n ); 5831 5832 if ( ! arraysEqual( cache, units ) ) { 5833 5834 gl.uniform1iv( this.addr, units ); 5835 5836 copyArray( cache, units ); 5837 5838 } 5839 5840 for ( let i = 0; i !== n; ++ i ) { 5841 5842 textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); 5843 5844 } 5845 5846} 5847 5848function setValueT2DArrayArray( gl, v, textures ) { 5849 5850 const cache = this.cache; 5851 5852 const n = v.length; 5853 5854 const units = allocTexUnits( textures, n ); 5855 5856 if ( ! arraysEqual( cache, units ) ) { 5857 5858 gl.uniform1iv( this.addr, units ); 5859 5860 copyArray( cache, units ); 5861 5862 } 5863 5864 for ( let i = 0; i !== n; ++ i ) { 5865 5866 textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] ); 5867 5868 } 5869 5870} 5871 5872 5873// Helper to pick the right setter for a pure (bottom-level) array 5874 5875function getPureArraySetter( type ) { 5876 5877 switch ( type ) { 5878 5879 case 0x1406: return setValueV1fArray; // FLOAT 5880 case 0x8b50: return setValueV2fArray; // _VEC2 5881 case 0x8b51: return setValueV3fArray; // _VEC3 5882 case 0x8b52: return setValueV4fArray; // _VEC4 5883 5884 case 0x8b5a: return setValueM2Array; // _MAT2 5885 case 0x8b5b: return setValueM3Array; // _MAT3 5886 case 0x8b5c: return setValueM4Array; // _MAT4 5887 5888 case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL 5889 case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2 5890 case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3 5891 case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4 5892 5893 case 0x1405: return setValueV1uiArray; // UINT 5894 case 0x8dc6: return setValueV2uiArray; // _VEC2 5895 case 0x8dc7: return setValueV3uiArray; // _VEC3 5896 case 0x8dc8: return setValueV4uiArray; // _VEC4 5897 5898 case 0x8b5e: // SAMPLER_2D 5899 case 0x8d66: // SAMPLER_EXTERNAL_OES 5900 case 0x8dca: // INT_SAMPLER_2D 5901 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D 5902 case 0x8b62: // SAMPLER_2D_SHADOW 5903 return setValueT1Array; 5904 5905 case 0x8b5f: // SAMPLER_3D 5906 case 0x8dcb: // INT_SAMPLER_3D 5907 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D 5908 return setValueT3DArray; 5909 5910 case 0x8b60: // SAMPLER_CUBE 5911 case 0x8dcc: // INT_SAMPLER_CUBE 5912 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE 5913 case 0x8dc5: // SAMPLER_CUBE_SHADOW 5914 return setValueT6Array; 5915 5916 case 0x8dc1: // SAMPLER_2D_ARRAY 5917 case 0x8dcf: // INT_SAMPLER_2D_ARRAY 5918 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY 5919 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW 5920 return setValueT2DArrayArray; 5921 5922 } 5923 5924} 5925 5926// --- Uniform Classes --- 5927 5928class SingleUniform { 5929 5930 constructor( id, activeInfo, addr ) { 5931 5932 this.id = id; 5933 this.addr = addr; 5934 this.cache = []; 5935 this.type = activeInfo.type; 5936 this.setValue = getSingularSetter( activeInfo.type ); 5937 5938 // this.path = activeInfo.name; // DEBUG 5939 5940 } 5941 5942} 5943 5944class PureArrayUniform { 5945 5946 constructor( id, activeInfo, addr ) { 5947 5948 this.id = id; 5949 this.addr = addr; 5950 this.cache = []; 5951 this.type = activeInfo.type; 5952 this.size = activeInfo.size; 5953 this.setValue = getPureArraySetter( activeInfo.type ); 5954 5955 // this.path = activeInfo.name; // DEBUG 5956 5957 } 5958 5959} 5960 5961class StructuredUniform { 5962 5963 constructor( id ) { 5964 5965 this.id = id; 5966 5967 this.seq = []; 5968 this.map = {}; 5969 5970 } 5971 5972 setValue( gl, value, textures ) { 5973 5974 const seq = this.seq; 5975 5976 for ( let i = 0, n = seq.length; i !== n; ++ i ) { 5977 5978 const u = seq[ i ]; 5979 u.setValue( gl, value[ u.id ], textures ); 5980 5981 } 5982 5983 } 5984 5985} 5986 5987// --- Top-level --- 5988 5989// Parser - builds up the property tree from the path strings 5990 5991const RePathPart = /(\w+)(\])?(\[|\.)?/g; 5992 5993// extracts 5994// - the identifier (member name or array index) 5995// - followed by an optional right bracket (found when array index) 5996// - followed by an optional left bracket or dot (type of subscript) 5997// 5998// Note: These portions can be read in a non-overlapping fashion and 5999// allow straightforward parsing of the hierarchy that WebGL encodes 6000// in the uniform names. 6001 6002function addUniform( container, uniformObject ) { 6003 6004 container.seq.push( uniformObject ); 6005 container.map[ uniformObject.id ] = uniformObject; 6006 6007} 6008 6009function parseUniform( activeInfo, addr, container ) { 6010 6011 const path = activeInfo.name, 6012 pathLength = path.length; 6013 6014 // reset RegExp object, because of the early exit of a previous run 6015 RePathPart.lastIndex = 0; 6016 6017 while ( true ) { 6018 6019 const match = RePathPart.exec( path ), 6020 matchEnd = RePathPart.lastIndex; 6021 6022 let id = match[ 1 ]; 6023 const idIsIndex = match[ 2 ] === ']', 6024 subscript = match[ 3 ]; 6025 6026 if ( idIsIndex ) id = id | 0; // convert to integer 6027 6028 if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { 6029 6030 // bare name or "pure" bottom-level array "[0]" suffix 6031 6032 addUniform( container, subscript === undefined ? 6033 new SingleUniform( id, activeInfo, addr ) : 6034 new PureArrayUniform( id, activeInfo, addr ) ); 6035 6036 break; 6037 6038 } else { 6039 6040 // step into inner node / create it in case it doesn't exist 6041 6042 const map = container.map; 6043 let next = map[ id ]; 6044 6045 if ( next === undefined ) { 6046 6047 next = new StructuredUniform( id ); 6048 addUniform( container, next ); 6049 6050 } 6051 6052 container = next; 6053 6054 } 6055 6056 } 6057 6058} 6059 6060// Root Container 6061 6062class WebGLUniforms { 6063 6064 constructor( gl, program ) { 6065 6066 this.seq = []; 6067 this.map = {}; 6068 6069 const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); 6070 6071 for ( let i = 0; i < n; ++ i ) { 6072 6073 const info = gl.getActiveUniform( program, i ), 6074 addr = gl.getUniformLocation( program, info.name ); 6075 6076 parseUniform( info, addr, this ); 6077 6078 } 6079 6080 // Sort uniforms to prioritize shadow samplers first (for optimal texture unit allocation) 6081 6082 const shadowSamplers = []; 6083 const otherUniforms = []; 6084 6085 for ( const u of this.seq ) { 6086 6087 if ( u.type === gl.SAMPLER_2D_SHADOW || u.type === gl.SAMPLER_CUBE_SHADOW || u.type === gl.SAMPLER_2D_ARRAY_SHADOW ) { 6088 6089 shadowSamplers.push( u ); 6090 6091 } else { 6092 6093 otherUniforms.push( u ); 6094 6095 } 6096 6097 } 6098 6099 if ( shadowSamplers.length > 0 ) { 6100 6101 this.seq = shadowSamplers.concat( otherUniforms ); 6102 6103 } 6104 6105 } 6106 6107 setValue( gl, name, value, textures ) { 6108 6109 const u = this.map[ name ]; 6110 6111 if ( u !== undefined ) u.setValue( gl, value, textures ); 6112 6113 } 6114 6115 setOptional( gl, object, name ) { 6116 6117 const v = object[ name ]; 6118 6119 if ( v !== undefined ) this.setValue( gl, name, v ); 6120 6121 } 6122 6123 static upload( gl, seq, values, textures ) { 6124 6125 for ( let i = 0, n = seq.length; i !== n; ++ i ) { 6126 6127 const u = seq[ i ], 6128 v = values[ u.id ]; 6129 6130 if ( v.needsUpdate !== false ) { 6131 6132 // note: always updating when .needsUpdate is undefined 6133 u.setValue( gl, v.value, textures ); 6134 6135 } 6136 6137 } 6138 6139 } 6140 6141 static seqWithValue( seq, values ) { 6142 6143 const r = []; 6144 6145 for ( let i = 0, n = seq.length; i !== n; ++ i ) { 6146 6147 const u = seq[ i ]; 6148 if ( u.id in values ) r.push( u ); 6149 6150 } 6151 6152 return r; 6153 6154 } 6155 6156} 6157 6158function WebGLShader( gl, type, string ) { 6159 6160 const shader = gl.createShader( type ); 6161 6162 gl.shaderSource( shader, string ); 6163 gl.compileShader( shader ); 6164 6165 return shader; 6166 6167} 6168 6169// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ 6170const COMPLETION_STATUS_KHR = 0x91B1; 6171 6172let programIdCount = 0; 6173 6174function handleSource( string, errorLine ) { 6175 6176 const lines = string.split( '\n' ); 6177 const lines2 = []; 6178 6179 const from = Math.max( errorLine - 6, 0 ); 6180 const to = Math.min( errorLine + 6, lines.length ); 6181 6182 for ( let i = from; i < to; i ++ ) { 6183 6184 const line = i + 1; 6185 lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` ); 6186 6187 } 6188 6189 return lines2.join( '\n' ); 6190 6191} 6192 6193const _m0 = /*@__PURE__*/ new Matrix3(); 6194 6195function getEncodingComponents( colorSpace ) { 6196 6197 ColorManagement._getMatrix( _m0, ColorManagement.workingColorSpace, colorSpace ); 6198 6199 const encodingMatrix = `mat3( ${ _m0.elements.map( ( v ) => v.toFixed( 4 ) ) } )`; 6200 6201 switch ( ColorManagement.getTransfer( colorSpace ) ) { 6202 6203 case LinearTransfer: 6204 return [ encodingMatrix, 'LinearTransferOETF' ]; 6205 6206 case SRGBTransfer: 6207 return [ encodingMatrix, 'sRGBTransferOETF' ]; 6208 6209 default: 6210 warn( 'WebGLProgram: Unsupported color space: ', colorSpace ); 6211 return [ encodingMatrix, 'LinearTransferOETF' ]; 6212 6213 } 6214 6215} 6216 6217function getShaderErrors( gl, shader, type ) { 6218 6219 const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); 6220 6221 const shaderInfoLog = gl.getShaderInfoLog( shader ) || ''; 6222 const errors = shaderInfoLog.trim(); 6223 6224 if ( status && errors === '' ) return ''; 6225 6226 const errorMatches = /ERROR: 0:(\d+)/.exec( errors ); 6227 if ( errorMatches ) { 6228 6229 // --enable-privileged-webgl-extension 6230 // log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); 6231 6232 const errorLine = parseInt( errorMatches[ 1 ] ); 6233 return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine ); 6234 6235 } else { 6236 6237 return errors; 6238 6239 } 6240 6241} 6242 6243function getTexelEncodingFunction( functionName, colorSpace ) { 6244 6245 const components = getEncodingComponents( colorSpace ); 6246 6247 return [ 6248 6249 `vec4 ${functionName}( vec4 value ) {`, 6250 6251 ` return ${components[ 1 ]}( vec4( value.rgb * ${components[ 0 ]}, value.a ) );`, 6252 6253 '}', 6254 6255 ].join( '\n' ); 6256 6257} 6258 6259const toneMappingFunctions = { 6260 [ LinearToneMapping ]: 'Linear', 6261 [ ReinhardToneMapping ]: 'Reinhard', 6262 [ CineonToneMapping ]: 'Cineon', 6263 [ ACESFilmicToneMapping ]: 'ACESFilmic', 6264 [ AgXToneMapping ]: 'AgX', 6265 [ NeutralToneMapping ]: 'Neutral', 6266 [ CustomToneMapping ]: 'Custom' 6267}; 6268 6269function getToneMappingFunction( functionName, toneMapping ) { 6270 6271 const toneMappingName = toneMappingFunctions[ toneMapping ]; 6272 6273 if ( toneMappingName === undefined ) { 6274 6275 warn( 'WebGLProgram: Unsupported toneMapping:', toneMapping ); 6276 return 'vec3 ' + functionName + '( vec3 color ) { return LinearToneMapping( color ); }'; 6277 6278 } 6279 6280 return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; 6281 6282} 6283 6284const _v0 = /*@__PURE__*/ new Vector3(); 6285 6286function getLuminanceFunction() { 6287 6288 ColorManagement.getLuminanceCoefficients( _v0 ); 6289 6290 const r = _v0.x.toFixed( 4 ); 6291 const g = _v0.y.toFixed( 4 ); 6292 const b = _v0.z.toFixed( 4 ); 6293 6294 return [ 6295 6296 'float luminance( const in vec3 rgb ) {', 6297 6298 ` const vec3 weights = vec3( ${ r }, ${ g }, ${ b } );`, 6299 6300 ' return dot( weights, rgb );', 6301 6302 '}' 6303 6304 ].join( '\n' ); 6305 6306} 6307 6308function generateVertexExtensions( parameters ) { 6309 6310 const chunks = [ 6311 parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '', 6312 parameters.extensionMultiDraw ? '#extension GL_ANGLE_multi_draw : require' : '', 6313 ]; 6314 6315 return chunks.filter( filterEmptyLine ).join( '\n' ); 6316 6317} 6318 6319function generateDefines( defines ) { 6320 6321 const chunks = []; 6322 6323 for ( const name in defines ) { 6324 6325 const value = defines[ name ]; 6326 6327 if ( value === false ) continue; 6328 6329 chunks.push( '#define ' + name + ' ' + value ); 6330 6331 } 6332 6333 return chunks.join( '\n' ); 6334 6335} 6336 6337function fetchAttributeLocations( gl, program ) { 6338 6339 const attributes = {}; 6340 6341 const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); 6342 6343 for ( let i = 0; i < n; i ++ ) { 6344 6345 const info = gl.getActiveAttrib( program, i ); 6346 const name = info.name; 6347 6348 let locationSize = 1; 6349 if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2; 6350 if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3; 6351 if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4; 6352 6353 // log( 'WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); 6354 6355 attributes[ name ] = { 6356 type: info.type, 6357 location: gl.getAttribLocation( program, name ), 6358 locationSize: locationSize 6359 }; 6360 6361 } 6362 6363 return attributes; 6364 6365} 6366 6367function filterEmptyLine( string ) { 6368 6369 return string !== ''; 6370 6371} 6372 6373function replaceLightNums( string, parameters ) { 6374 6375 const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps; 6376 6377 return string 6378 .replace( /NUM_SUN_LIGHTS/g, parameters.numSunLights ) 6379 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) 6380 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) 6381 .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps ) 6382 .replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords ) 6383 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) 6384 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) 6385 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ) 6386 .replace( /NUM_SUN_LIGHT_SHADOWS/g, parameters.numSunLightShadows ) 6387 .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows ) 6388 .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps ) 6389 .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows ) 6390 .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows ); 6391 6392} 6393 6394function replaceClippingPlaneNums( string, parameters ) { 6395 6396 return string 6397 .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) 6398 .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); 6399 6400} 6401 6402// Resolve Includes 6403 6404const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; 6405 6406function resolveIncludes( string ) { 6407 6408 return string.replace( includePattern, includeReplacer ); 6409 6410} 6411 6412const shaderChunkMap = new Map(); 6413 6414function includeReplacer( match, include ) { 6415 6416 let string = ShaderChunk[ include ]; 6417 6418 if ( string === undefined ) { 6419 6420 const newInclude = shaderChunkMap.get( include ); 6421 6422 if ( newInclude !== undefined ) { 6423 6424 string = ShaderChunk[ newInclude ]; 6425 warn( 'WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude ); 6426 6427 } else { 6428 6429 throw new Error( 'THREE.WebGLProgram: Can not resolve #include <' + include + '>' ); 6430 6431 } 6432 6433 } 6434 6435 return resolveIncludes( string ); 6436 6437} 6438 6439// Unroll Loops 6440 6441const unrollLoopPattern = /#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; 6442 6443function unrollLoops( string ) { 6444 6445 return string.replace( unrollLoopPattern, loopReplacer ); 6446 6447} 6448 6449function loopReplacer( match, start, end, snippet ) { 6450 6451 let string = ''; 6452 6453 for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) { 6454 6455 string += snippet 6456 .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' ) 6457 .replace( /UNROLLED_LOOP_INDEX/g, i ); 6458 6459 } 6460 6461 return string; 6462 6463} 6464 6465// 6466 6467function generatePrecision( parameters ) { 6468 6469 let precisionstring = `precision ${parameters.precision} float; 6470 precision ${parameters.precision} int; 6471 precision ${parameters.precision} sampler2D; 6472 precision ${parameters.precision} samplerCube; 6473 precision ${parameters.precision} sampler3D; 6474 precision ${parameters.precision} sampler2DArray; 6475 precision ${parameters.precision} sampler2DShadow; 6476 precision ${parameters.precision} samplerCubeShadow; 6477 precision ${parameters.precision} sampler2DArrayShadow; 6478 precision ${parameters.precision} isampler2D; 6479 precision ${parameters.precision} isampler3D; 6480 precision ${parameters.precision} isamplerCube; 6481 precision ${parameters.precision} isampler2DArray; 6482 precision ${parameters.precision} usampler2D; 6483 precision ${parameters.precision} usampler3D; 6484 precision ${parameters.precision} usamplerCube; 6485 precision ${parameters.precision} usampler2DArray; 6486 `; 6487 6488 if ( parameters.precision === 'highp' ) { 6489 6490 precisionstring += '\n#define HIGH_PRECISION'; 6491 6492 } else if ( parameters.precision === 'mediump' ) { 6493 6494 precisionstring += '\n#define MEDIUM_PRECISION'; 6495 6496 } else if ( parameters.precision === 'lowp' ) { 6497 6498 precisionstring += '\n#define LOW_PRECISION'; 6499 6500 } 6501 6502 return precisionstring; 6503 6504} 6505 6506const shadowMapTypeDefines = { 6507 [ PCFShadowMap ]: 'SHADOWMAP_TYPE_PCF', 6508 [ VSMShadowMap ]: 'SHADOWMAP_TYPE_VSM' 6509}; 6510 6511function generateShadowMapTypeDefine( parameters ) { 6512 6513 return shadowMapTypeDefines[ parameters.shadowMapType ] || 'SHADOWMAP_TYPE_BASIC'; 6514 6515} 6516 6517const envMapTypeDefines = { 6518 [ CubeReflectionMapping ]: 'ENVMAP_TYPE_CUBE', 6519 [ CubeRefractionMapping ]: 'ENVMAP_TYPE_CUBE', 6520 [ CubeUVReflectionMapping ]: 'ENVMAP_TYPE_CUBE_UV' 6521}; 6522 6523function generateEnvMapTypeDefine( parameters ) { 6524 6525 if ( parameters.envMap === false ) return 'ENVMAP_TYPE_CUBE'; 6526 6527 return envMapTypeDefines[ parameters.envMapMode ] || 'ENVMAP_TYPE_CUBE'; 6528 6529} 6530 6531const envMapModeDefines = { 6532 [ CubeRefractionMapping ]: 'ENVMAP_MODE_REFRACTION' 6533}; 6534 6535function generateEnvMapModeDefine( parameters ) { 6536 6537 if ( parameters.envMap === false ) return 'ENVMAP_MODE_REFLECTION'; 6538 6539 return envMapModeDefines[ parameters.envMapMode ] || 'ENVMAP_MODE_REFLECTION'; 6540 6541} 6542 6543const envMapBlendingDefines = { 6544 [ MultiplyOperation ]: 'ENVMAP_BLENDING_MULTIPLY', 6545 [ MixOperation ]: 'ENVMAP_BLENDING_MIX', 6546 [ AddOperation ]: 'ENVMAP_BLENDING_ADD' 6547}; 6548 6549function generateEnvMapBlendingDefine( parameters ) { 6550 6551 if ( parameters.envMap === false ) return 'ENVMAP_BLENDING_NONE'; 6552 6553 return envMapBlendingDefines[ parameters.combine ] || 'ENVMAP_BLENDING_NONE'; 6554 6555} 6556 6557function generateCubeUVSize( parameters ) { 6558 6559 const imageHeight = parameters.envMapCubeUVHeight; 6560 6561 if ( imageHeight === null ) return null; 6562 6563 const maxMip = Math.log2( imageHeight ) - 2; 6564 6565 const texelHeight = 1.0 / imageHeight; 6566 6567 const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) ); 6568 6569 return { texelWidth, texelHeight, maxMip }; 6570 6571} 6572 6573function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { 6574 6575 // TODO Send this event to Three.js DevTools 6576 // log( 'WebGLProgram', cacheKey ); 6577 6578 const gl = renderer.getContext(); 6579 6580 const defines = parameters.defines; 6581 6582 let vertexShader = parameters.vertexShader; 6583 let fragmentShader = parameters.fragmentShader; 6584 6585 const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters ); 6586 const envMapTypeDefine = generateEnvMapTypeDefine( parameters ); 6587 const envMapModeDefine = generateEnvMapModeDefine( parameters ); 6588 const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters ); 6589 const envMapCubeUVSize = generateCubeUVSize( parameters ); 6590 6591 const customVertexExtensions = generateVertexExtensions( parameters ); 6592 6593 const customDefines = generateDefines( defines ); 6594 6595 const program = gl.createProgram(); 6596 6597 let prefixVertex, prefixFragment; 6598 let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''; 6599 6600 if ( parameters.isRawShaderMaterial ) { 6601 6602 prefixVertex = [ 6603 6604 '#define SHADER_TYPE ' + parameters.shaderType, 6605 '#define SHADER_NAME ' + parameters.shaderName, 6606 6607 customDefines 6608 6609 ].filter( filterEmptyLine ).join( '\n' ); 6610 6611 if ( prefixVertex.length > 0 ) { 6612 6613 prefixVertex += '\n'; 6614 6615 } 6616 6617 prefixFragment = [ 6618 6619 '#define SHADER_TYPE ' + parameters.shaderType, 6620 '#define SHADER_NAME ' + parameters.shaderName, 6621 6622 customDefines 6623 6624 ].filter( filterEmptyLine ).join( '\n' ); 6625 6626 if ( prefixFragment.length > 0 ) { 6627 6628 prefixFragment += '\n'; 6629 6630 } 6631 6632 } else { 6633 6634 prefixVertex = [ 6635 6636 generatePrecision( parameters ), 6637 6638 '#define SHADER_TYPE ' + parameters.shaderType, 6639 '#define SHADER_NAME ' + parameters.shaderName, 6640 6641 customDefines, 6642 6643 parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '', 6644 parameters.batching ? '#define USE_BATCHING' : '', 6645 parameters.batchingColor ? '#define USE_BATCHING_COLOR' : '', 6646 parameters.instancing ? '#define USE_INSTANCING' : '', 6647 parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', 6648 parameters.instancingMorph ? '#define USE_INSTANCING_MORPH' : '', 6649 6650 parameters.useFog && parameters.fog ? '#define USE_FOG' : '', 6651 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', 6652 6653 parameters.map ? '#define USE_MAP' : '', 6654 parameters.envMap ? '#define USE_ENVMAP' : '', 6655 parameters.envMap ? '#define ' + envMapModeDefine : '', 6656 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 6657 parameters.aoMap ? '#define USE_AOMAP' : '', 6658 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 6659 parameters.normalMap ? '#define USE_NORMALMAP' : '', 6660 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', 6661 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', 6662 parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '', 6663 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 6664 6665 parameters.anisotropy ? '#define USE_ANISOTROPY' : '', 6666 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', 6667 6668 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', 6669 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', 6670 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', 6671 6672 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', 6673 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', 6674 6675 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 6676 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', 6677 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', 6678 6679 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 6680 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 6681 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 6682 parameters.alphaHash ? '#define USE_ALPHAHASH' : '', 6683 6684 parameters.transmission ? '#define USE_TRANSMISSION' : '', 6685 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', 6686 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', 6687 6688 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', 6689 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', 6690 6691 // 6692 6693 parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '', 6694 parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '', 6695 parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '', 6696 parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '', 6697 parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '', 6698 parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '', 6699 parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '', 6700 parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '', 6701 6702 parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '', 6703 parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '', 6704 6705 parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '', 6706 6707 parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '', 6708 parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '', 6709 parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '', 6710 6711 parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '', 6712 parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '', 6713 6714 parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '', 6715 parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '', 6716 6717 parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '', 6718 parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '', 6719 parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '', 6720 6721 parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '', 6722 parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '', 6723 6724 // 6725 6726 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', 6727 parameters.vertexNormals ? '#define HAS_NORMAL' : '', 6728 parameters.vertexColors ? '#define USE_COLOR' : '', 6729 parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', 6730 parameters.vertexUv1s ? '#define USE_UV1' : '', 6731 parameters.vertexUv2s ? '#define USE_UV2' : '', 6732 parameters.vertexUv3s ? '#define USE_UV3' : '', 6733 6734 parameters.pointsUvs ? '#define USE_POINTS_UV' : '', 6735 6736 parameters.flatShading ? '#define FLAT_SHADED' : '', 6737 6738 parameters.skinning ? '#define USE_SKINNING' : '', 6739 6740 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', 6741 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', 6742 ( parameters.morphColors ) ? '#define USE_MORPHCOLORS' : '', 6743 ( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '', 6744 ( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '', 6745 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 6746 parameters.flipSided ? '#define FLIP_SIDED' : '', 6747 6748 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 6749 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 6750 6751 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', 6752 6753 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', 6754 6755 parameters.logarithmicDepthBuffer ? '#define USE_LOGARITHMIC_DEPTH_BUFFER' : '', 6756 parameters.reversedDepthBuffer ? '#define USE_REVERSED_DEPTH_BUFFER' : '', 6757 6758 'uniform mat4 modelMatrix;', 6759 'uniform mat4 modelViewMatrix;', 6760 'uniform mat4 projectionMatrix;', 6761 'uniform mat4 viewMatrix;', 6762 'uniform mat3 normalMatrix;', 6763 'uniform vec3 cameraPosition;', 6764 'uniform bool isOrthographic;', 6765 6766 '#ifdef USE_INSTANCING', 6767 6768 ' attribute mat4 instanceMatrix;', 6769 6770 '#endif', 6771 6772 '#ifdef USE_INSTANCING_COLOR', 6773 6774 ' attribute vec3 instanceColor;', 6775 6776 '#endif', 6777 6778 '#ifdef USE_INSTANCING_MORPH', 6779 6780 ' uniform sampler2D morphTexture;', 6781 6782 '#endif', 6783 6784 'attribute vec3 position;', 6785 'attribute vec3 normal;', 6786 'attribute vec2 uv;', 6787 6788 '#ifdef USE_UV1', 6789 6790 ' attribute vec2 uv1;', 6791 6792 '#endif', 6793 6794 '#ifdef USE_UV2', 6795 6796 ' attribute vec2 uv2;', 6797 6798 '#endif', 6799 6800 '#ifdef USE_UV3', 6801 6802 ' attribute vec2 uv3;', 6803 6804 '#endif', 6805 6806 '#ifdef USE_TANGENT', 6807 6808 ' attribute vec4 tangent;', 6809 6810 '#endif', 6811 6812 '#if defined( USE_COLOR_ALPHA )', 6813 6814 ' attribute vec4 color;', 6815 6816 '#elif defined( USE_COLOR )', 6817 6818 ' attribute vec3 color;', 6819 6820 '#endif', 6821 6822 '#ifdef USE_SKINNING', 6823 6824 ' attribute vec4 skinIndex;', 6825 ' attribute vec4 skinWeight;', 6826 6827 '#endif', 6828 6829 '\n' 6830 6831 ].filter( filterEmptyLine ).join( '\n' ); 6832 6833 prefixFragment = [ 6834 6835 generatePrecision( parameters ), 6836 6837 '#define SHADER_TYPE ' + parameters.shaderType, 6838 '#define SHADER_NAME ' + parameters.shaderName, 6839 6840 customDefines, 6841 6842 parameters.useFog && parameters.fog ? '#define USE_FOG' : '', 6843 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', 6844 6845 parameters.alphaToCoverage ? '#define ALPHA_TO_COVERAGE' : '', 6846 parameters.map ? '#define USE_MAP' : '', 6847 parameters.matcap ? '#define USE_MATCAP' : '', 6848 parameters.envMap ? '#define USE_ENVMAP' : '', 6849 parameters.envMap ? '#define ' + envMapTypeDefine : '', 6850 parameters.envMap ? '#define ' + envMapModeDefine : '', 6851 parameters.envMap ? '#define ' + envMapBlendingDefine : '', 6852 envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '', 6853 envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '', 6854 envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', 6855 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 6856 parameters.aoMap ? '#define USE_AOMAP' : '', 6857 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 6858 parameters.normalMap ? '#define USE_NORMALMAP' : '', 6859 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', 6860 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', 6861 parameters.packedNormalMap ? '#define USE_PACKED_NORMALMAP' : '', 6862 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 6863 6864 parameters.anisotropy ? '#define USE_ANISOTROPY' : '', 6865 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', 6866 6867 parameters.clearcoat ? '#define USE_CLEARCOAT' : '', 6868 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', 6869 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', 6870 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', 6871 6872 parameters.dispersion ? '#define USE_DISPERSION' : '', 6873 parameters.retroreflection ? '#define USE_RETROREFLECTION' : '', 6874 6875 parameters.iridescence ? '#define USE_IRIDESCENCE' : '', 6876 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', 6877 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', 6878 6879 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 6880 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', 6881 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', 6882 6883 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 6884 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 6885 6886 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 6887 parameters.alphaTest ? '#define USE_ALPHATEST' : '', 6888 parameters.alphaHash ? '#define USE_ALPHAHASH' : '', 6889 6890 parameters.sheen ? '#define USE_SHEEN' : '', 6891 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', 6892 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', 6893 6894 parameters.transmission ? '#define USE_TRANSMISSION' : '', 6895 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', 6896 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', 6897 6898 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', 6899 parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', 6900 parameters.vertexAlphas || parameters.batchingColor ? '#define USE_COLOR_ALPHA' : '', 6901 parameters.vertexUv1s ? '#define USE_UV1' : '', 6902 parameters.vertexUv2s ? '#define USE_UV2' : '', 6903 parameters.vertexUv3s ? '#define USE_UV3' : '', 6904 6905 parameters.pointsUvs ? '#define USE_POINTS_UV' : '', 6906 6907 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', 6908 6909 parameters.flatShading ? '#define FLAT_SHADED' : '', 6910 6911 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 6912 parameters.flipSided ? '#define FLIP_SIDED' : '', 6913 6914 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 6915 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 6916 6917 parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', 6918 6919 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', 6920 6921 parameters.numLightProbeGrids > 0 ? '#define USE_LIGHT_PROBES_GRID' : '', 6922 6923 parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', 6924 parameters.decodeVideoTextureEmissive ? '#define DECODE_VIDEO_TEXTURE_EMISSIVE' : '', 6925 6926 parameters.logarithmicDepthBuffer ? '#define USE_LOGARITHMIC_DEPTH_BUFFER' : '', 6927 parameters.reversedDepthBuffer ? '#define USE_REVERSED_DEPTH_BUFFER' : '', 6928 6929 'uniform mat4 viewMatrix;', 6930 'uniform vec3 cameraPosition;', 6931 'uniform bool isOrthographic;', 6932 6933 ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '', 6934 ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below 6935 ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '', 6936 6937 parameters.dithering ? '#define DITHERING' : '', 6938 parameters.opaque ? '#define OPAQUE' : '', 6939 6940 ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below 6941 getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ), 6942 getLuminanceFunction(), 6943 6944 parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', 6945 6946 '\n' 6947 6948 ].filter( filterEmptyLine ).join( '\n' ); 6949 6950 } 6951 6952 vertexShader = resolveIncludes( vertexShader ); 6953 vertexShader = replaceLightNums( vertexShader, parameters ); 6954 vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); 6955 6956 fragmentShader = resolveIncludes( fragmentShader ); 6957 fragmentShader = replaceLightNums( fragmentShader, parameters ); 6958 fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); 6959 6960 vertexShader = unrollLoops( vertexShader ); 6961 fragmentShader = unrollLoops( fragmentShader ); 6962 6963 if ( parameters.isRawShaderMaterial !== true ) { 6964 6965 // GLSL 3.0 conversion for built-in materials and ShaderMaterial 6966 6967 versionString = '#version 300 es\n'; 6968 6969 prefixVertex = [ 6970 customVertexExtensions, 6971 '#define attribute in', 6972 '#define varying out', 6973 '#define texture2D texture' 6974 ].join( '\n' ) + '\n' + prefixVertex; 6975 6976 prefixFragment = [ 6977 '#define varying in', 6978 ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', 6979 ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', 6980 '#define gl_FragDepthEXT gl_FragDepth', 6981 '#define texture2D texture', 6982 '#define textureCube texture', 6983 '#define texture2DProj textureProj', 6984 '#define texture2DLodEXT textureLod', 6985 '#define texture2DProjLodEXT textureProjLod', 6986 '#define textureCubeLodEXT textureLod', 6987 '#define texture2DGradEXT textureGrad', 6988 '#define texture2DProjGradEXT textureProjGrad', 6989 '#define textureCubeGradEXT textureGrad' 6990 ].join( '\n' ) + '\n' + prefixFragment; 6991 6992 } 6993 6994 const vertexGlsl = versionString + prefixVertex + vertexShader; 6995 const fragmentGlsl = versionString + prefixFragment + fragmentShader; 6996 6997 // log( '*VERTEX*', vertexGlsl ); 6998 // log( '*FRAGMENT*', fragmentGlsl ); 6999 7000 const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); 7001 const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); 7002 7003 gl.attachShader( program, glVertexShader ); 7004 gl.attachShader( program, glFragmentShader ); 7005 7006 // Force a particular attribute to index 0. 7007 7008 if ( parameters.index0AttributeName !== undefined ) { 7009 7010 gl.bindAttribLocation( program, 0, parameters.index0AttributeName ); 7011 7012 } else if ( parameters.hasPositionAttribute === true ) { 7013 7014 // below avoids the "Attribute 0 is disabled" performance penalty 7015 7016 gl.bindAttribLocation( program, 0, 'position' ); 7017 7018 } 7019 7020 gl.linkProgram( program ); 7021 7022 function onFirstUse( self ) { 7023 7024 // check for link errors 7025 if ( renderer.debug.checkShaderErrors ) { 7026 7027 const programInfoLog = gl.getProgramInfoLog( program ) || ''; 7028 const vertexShaderInfoLog = gl.getShaderInfoLog( glVertexShader ) || ''; 7029 const fragmentShaderInfoLog = gl.getShaderInfoLog( glFragmentShader ) || ''; 7030 7031 const programLog = programInfoLog.trim(); 7032 const vertexLog = vertexShaderInfoLog.trim(); 7033 const fragmentLog = fragmentShaderInfoLog.trim(); 7034 7035 let runnable = true; 7036 let haveDiagnostics = true; 7037 7038 if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { 7039 7040 runnable = false; 7041 7042 if ( typeof renderer.debug.onShaderError === 'function' ) { 7043 7044 renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader ); 7045 7046 } else { 7047 7048 // default error reporting 7049 7050 const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); 7051 const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); 7052 7053 error( 7054 'WebGLProgram: Shader Error ' + gl.getError() + ' - ' + 7055 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' + 7056 'Material Name: ' + self.name + '\n' + 7057 'Material Type: ' + self.type + '\n\n' + 7058 'Program Info Log: ' + programLog + '\n' + 7059 vertexErrors + '\n' + 7060 fragmentErrors 7061 ); 7062 7063 } 7064 7065 } else if ( programLog !== '' ) { 7066 7067 warn( 'WebGLProgram: Program Info Log:', programLog ); 7068 7069 } else if ( vertexLog === '' || fragmentLog === '' ) { 7070 7071 haveDiagnostics = false; 7072 7073 } 7074 7075 if ( haveDiagnostics ) { 7076 7077 self.diagnostics = { 7078 7079 runnable: runnable, 7080 7081 programLog: programLog, 7082 7083 vertexShader: { 7084 7085 log: vertexLog, 7086 prefix: prefixVertex 7087 7088 }, 7089 7090 fragmentShader: { 7091 7092 log: fragmentLog, 7093 prefix: prefixFragment 7094 7095 } 7096 7097 }; 7098 7099 } 7100 7101 } 7102 7103 // Clean up 7104 7105 // Crashes in iOS9 and iOS10. #18402 7106 // gl.detachShader( program, glVertexShader ); 7107 // gl.detachShader( program, glFragmentShader ); 7108 7109 gl.deleteShader( glVertexShader ); 7110 gl.deleteShader( glFragmentShader ); 7111 7112 cachedUniforms = new WebGLUniforms( gl, program ); 7113 cachedAttributes = fetchAttributeLocations( gl, program ); 7114 7115 } 7116 7117 // set up caching for uniform locations 7118 7119 let cachedUniforms; 7120 7121 this.getUniforms = function () { 7122 7123 if ( cachedUniforms === undefined ) { 7124 7125 // Populates cachedUniforms and cachedAttributes 7126 onFirstUse( this ); 7127 7128 } 7129 7130 return cachedUniforms; 7131 7132 }; 7133 7134 // set up caching for attribute locations 7135 7136 let cachedAttributes; 7137 7138 this.getAttributes = function () { 7139 7140 if ( cachedAttributes === undefined ) { 7141 7142 // Populates cachedAttributes and cachedUniforms 7143 onFirstUse( this ); 7144 7145 } 7146 7147 return cachedAttributes; 7148 7149 }; 7150 7151 // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, 7152 // flag the program as ready immediately. It may cause a stall when it's first used. 7153 7154 let programReady = ( parameters.rendererExtensionParallelShaderCompile === false ); 7155 7156 this.isReady = function () { 7157 7158 if ( programReady === false ) { 7159 7160 programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR ); 7161 7162 } 7163 7164 return programReady; 7165 7166 }; 7167 7168 // free resource 7169 7170 this.destroy = function () { 7171 7172 bindingStates.releaseStatesOfProgram( this ); 7173 7174 gl.deleteProgram( program ); 7175 this.program = undefined; 7176 7177 }; 7178 7179 // 7180 7181 this.type = parameters.shaderType; 7182 this.name = parameters.shaderName; 7183 this.id = programIdCount ++; 7184 this.cacheKey = cacheKey; 7185 this.usedTimes = 1; 7186 this.program = program; 7187 this.vertexShader = glVertexShader; 7188 this.fragmentShader = glFragmentShader; 7189 7190 return this; 7191 7192} 7193 7194let _id = 0; 7195 7196class WebGLShaderCache { 7197 7198 constructor() { 7199 7200 this.shaderCache = new Map(); 7201 this.materialCache = new Map(); 7202 7203 } 7204 7205 update( material, vertexShaderStage, fragmentShaderStage ) { 7206 7207 const materialShaders = this._getShaderCacheForMaterial( material ); 7208 7209 if ( materialShaders.has( vertexShaderStage ) === false ) { 7210 7211 materialShaders.add( vertexShaderStage ); 7212 vertexShaderStage.usedTimes ++; 7213 7214 } 7215 7216 if ( materialShaders.has( fragmentShaderStage ) === false ) { 7217 7218 materialShaders.add( fragmentShaderStage ); 7219 fragmentShaderStage.usedTimes ++; 7220 7221 } 7222 7223 return this; 7224 7225 } 7226 7227 remove( material ) { 7228 7229 const materialShaders = this.materialCache.get( material ); 7230 7231 for ( const shaderStage of materialShaders ) { 7232 7233 shaderStage.usedTimes --; 7234 7235 if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code ); 7236 7237 } 7238 7239 this.materialCache.delete( material ); 7240 7241 return this; 7242 7243 } 7244 7245 getVertexShaderStage( material ) { 7246 7247 return this._getShaderStage( material.vertexShader ); 7248 7249 } 7250 7251 getFragmentShaderStage( material ) { 7252 7253 return this._getShaderStage( material.fragmentShader ); 7254 7255 } 7256 7257 dispose() { 7258 7259 this.shaderCache.clear(); 7260 this.materialCache.clear(); 7261 7262 } 7263 7264 _getShaderCacheForMaterial( material ) { 7265 7266 const cache = this.materialCache; 7267 let set = cache.get( material ); 7268 7269 if ( set === undefined ) { 7270 7271 set = new Set(); 7272 cache.set( material, set ); 7273 7274 } 7275 7276 return set; 7277 7278 } 7279 7280 _getShaderStage( code ) { 7281 7282 const cache = this.shaderCache; 7283 let stage = cache.get( code ); 7284 7285 if ( stage === undefined ) { 7286 7287 stage = new WebGLShaderStage( code ); 7288 cache.set( code, stage ); 7289 7290 } 7291 7292 return stage; 7293 7294 } 7295 7296} 7297 7298class WebGLShaderStage { 7299 7300 constructor( code ) { 7301 7302 this.id = _id ++; 7303 7304 this.code = code; 7305 this.usedTimes = 0; 7306 7307 } 7308 7309} 7310 7311function isPackedRGFormat( format ) { 7312 7313 return format === RGFormat || format === RG11_EAC_Format || format === RED_GREEN_RGTC2_Format; 7314 7315} 7316 7317function WebGLPrograms( renderer, environments, extensions, capabilities, bindingStates, clipping ) { 7318 7319 const _programLayers = new Layers(); 7320 const _customShaders = new WebGLShaderCache(); 7321 const _activeChannels = new Set(); 7322 const programs = []; 7323 const programsMap = new Map(); 7324 7325 const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; 7326 7327 let precision = capabilities.precision; 7328 7329 const shaderIDs = { 7330 MeshDepthMaterial: 'depth', 7331 MeshDistanceMaterial: 'distance', 7332 MeshNormalMaterial: 'normal', 7333 MeshBasicMaterial: 'basic', 7334 MeshLambertMaterial: 'lambert', 7335 MeshPhongMaterial: 'phong', 7336 MeshToonMaterial: 'toon', 7337 MeshStandardMaterial: 'physical', 7338 MeshPhysicalMaterial: 'physical', 7339 MeshMatcapMaterial: 'matcap', 7340 LineBasicMaterial: 'basic', 7341 LineDashedMaterial: 'dashed', 7342 PointsMaterial: 'points', 7343 ShadowMaterial: 'shadow', 7344 SpriteMaterial: 'sprite' 7345 }; 7346 7347 function getChannel( value ) { 7348 7349 _activeChannels.add( value ); 7350 7351 if ( value === 0 ) return 'uv'; 7352 7353 return `uv${ value }`; 7354 7355 } 7356 7357 function getParameters( material, lights, shadows, scene, object, lightProbeGrids ) { 7358 7359 const fog = scene.fog; 7360 const geometry = object.geometry; 7361 const environment = ( material.isMeshStandardMaterial || material.isMeshLambertMaterial || material.isMeshPhongMaterial ) ? scene.environment : null; 7362 7363 const usePMREM = material.isMeshStandardMaterial || ( material.isMeshLambertMaterial && ! material.envMap ) || ( material.isMeshPhongMaterial && ! material.envMap ); 7364 const envMap = environments.get( material.envMap || environment, usePMREM ); 7365 const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null; 7366 7367 const shaderID = shaderIDs[ material.type ]; 7368 7369 // heuristics to create shader parameters according to lights in the scene 7370 // (not to blow over maxLights budget) 7371 7372 if ( material.precision !== null ) { 7373 7374 precision = capabilities.getMaxPrecision( material.precision ); 7375 7376 if ( precision !== material.precision ) { 7377 7378 warn( 'WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); 7379 7380 } 7381 7382 } 7383 7384 // 7385 7386 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 7387 const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; 7388 7389 let morphTextureStride = 0; 7390 7391 if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1; 7392 if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2; 7393 if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3; 7394 7395 // 7396 7397 let vertexShader, fragmentShader; 7398 let customVertexShaderID, customFragmentShaderID; 7399 7400 if ( shaderID ) { 7401 7402 const shader = ShaderLib[ shaderID ]; 7403 7404 vertexShader = shader.vertexShader; 7405 fragmentShader = shader.fragmentShader; 7406 7407 } else { 7408 7409 vertexShader = material.vertexShader; 7410 fragmentShader = material.fragmentShader; 7411 7412 const vertexShaderStage = _customShaders.getVertexShaderStage( material ); 7413 const fragmentShaderStage = _customShaders.getFragmentShaderStage( material ); 7414 7415 _customShaders.update( material, vertexShaderStage, fragmentShaderStage ); 7416 7417 customVertexShaderID = vertexShaderStage.id; 7418 customFragmentShaderID = fragmentShaderStage.id; 7419 7420 } 7421 7422 const currentRenderTarget = renderer.getRenderTarget(); 7423 const reversedDepthBuffer = renderer.state.buffers.depth.getReversed(); 7424 7425 const IS_INSTANCEDMESH = object.isInstancedMesh === true; 7426 const IS_BATCHEDMESH = object.isBatchedMesh === true; 7427 7428 const HAS_MAP = !! material.map; 7429 const HAS_MATCAP = !! material.matcap; 7430 const HAS_ENVMAP = !! envMap; 7431 const HAS_AOMAP = !! material.aoMap; 7432 const HAS_LIGHTMAP = !! material.lightMap; 7433 const HAS_BUMPMAP = !! material.bumpMap && material.wireframe === false; 7434 const HAS_NORMALMAP = !! material.normalMap; 7435 const HAS_DISPLACEMENTMAP = !! material.displacementMap; 7436 const HAS_EMISSIVEMAP = !! material.emissiveMap; 7437 7438 const HAS_METALNESSMAP = !! material.metalnessMap; 7439 const HAS_ROUGHNESSMAP = !! material.roughnessMap; 7440 7441 const HAS_ANISOTROPY = material.anisotropy > 0; 7442 const HAS_CLEARCOAT = material.clearcoat > 0; 7443 const HAS_DISPERSION = material.dispersion > 0; 7444 const HAS_RETROREFLECTION = material.retroreflectivity > 0; 7445 const HAS_IRIDESCENCE = material.iridescence > 0; 7446 const HAS_SHEEN = material.sheen > 0; 7447 const HAS_TRANSMISSION = material.transmission > 0; 7448 7449 const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap; 7450 7451 const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap; 7452 const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap; 7453 const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap; 7454 7455 const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap; 7456 const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap; 7457 7458 const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap; 7459 const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap; 7460 7461 const HAS_SPECULARMAP = !! material.specularMap; 7462 const HAS_SPECULAR_COLORMAP = !! material.specularColorMap; 7463 const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap; 7464 7465 const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap; 7466 const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap; 7467 7468 const HAS_GRADIENTMAP = !! material.gradientMap; 7469 7470 const HAS_ALPHAMAP = !! material.alphaMap; 7471 7472 const HAS_ALPHATEST = material.alphaTest > 0; 7473 7474 const HAS_ALPHAHASH = !! material.alphaHash; 7475 7476 const HAS_EXTENSIONS = !! material.extensions; 7477 7478 let toneMapping = NoToneMapping; 7479 7480 if ( material.toneMapped ) { 7481 7482 if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) { 7483 7484 toneMapping = renderer.toneMapping; 7485 7486 } 7487 7488 } 7489 7490 const parameters = { 7491 7492 shaderID: shaderID, 7493 shaderType: material.type, 7494 shaderName: material.name, 7495 7496 vertexShader: vertexShader, 7497 fragmentShader: fragmentShader, 7498 defines: material.defines, 7499 7500 customVertexShaderID: customVertexShaderID, 7501 customFragmentShaderID: customFragmentShaderID, 7502 7503 isRawShaderMaterial: material.isRawShaderMaterial === true, 7504 glslVersion: material.glslVersion, 7505 7506 precision: precision, 7507 7508 batching: IS_BATCHEDMESH, 7509 batchingColor: IS_BATCHEDMESH && object._colorsTexture !== null, 7510 instancing: IS_INSTANCEDMESH, 7511 instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, 7512 instancingMorph: IS_INSTANCEDMESH && object.morphTexture !== null, 7513 7514 outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : ColorManagement.workingColorSpace ), 7515 alphaToCoverage: !! material.alphaToCoverage, 7516 7517 map: HAS_MAP, 7518 matcap: HAS_MATCAP, 7519 envMap: HAS_ENVMAP, 7520 envMapMode: HAS_ENVMAP && envMap.mapping, 7521 envMapCubeUVHeight: envMapCubeUVHeight, 7522 aoMap: HAS_AOMAP, 7523 lightMap: HAS_LIGHTMAP, 7524 bumpMap: HAS_BUMPMAP, 7525 normalMap: HAS_NORMALMAP, 7526 displacementMap: HAS_DISPLACEMENTMAP, 7527 emissiveMap: HAS_EMISSIVEMAP, 7528 7529 normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap, 7530 normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap, 7531 packedNormalMap: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap && isPackedRGFormat( material.normalMap.format ), 7532 7533 metalnessMap: HAS_METALNESSMAP, 7534 roughnessMap: HAS_ROUGHNESSMAP, 7535 7536 anisotropy: HAS_ANISOTROPY, 7537 anisotropyMap: HAS_ANISOTROPYMAP, 7538 7539 clearcoat: HAS_CLEARCOAT, 7540 clearcoatMap: HAS_CLEARCOATMAP, 7541 clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP, 7542 clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP, 7543 7544 dispersion: HAS_DISPERSION, 7545 retroreflection: HAS_RETROREFLECTION, 7546 7547 iridescence: HAS_IRIDESCENCE, 7548 iridescenceMap: HAS_IRIDESCENCEMAP, 7549 iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP, 7550 7551 sheen: HAS_SHEEN, 7552 sheenColorMap: HAS_SHEEN_COLORMAP, 7553 sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP, 7554 7555 specularMap: HAS_SPECULARMAP, 7556 specularColorMap: HAS_SPECULAR_COLORMAP, 7557 specularIntensityMap: HAS_SPECULAR_INTENSITYMAP, 7558 7559 transmission: HAS_TRANSMISSION, 7560 transmissionMap: HAS_TRANSMISSIONMAP, 7561 thicknessMap: HAS_THICKNESSMAP, 7562 7563 gradientMap: HAS_GRADIENTMAP, 7564 7565 opaque: material.transparent === false && material.blending === NormalBlending && material.alphaToCoverage === false, 7566 7567 alphaMap: HAS_ALPHAMAP, 7568 alphaTest: HAS_ALPHATEST, 7569 alphaHash: HAS_ALPHAHASH, 7570 7571 combine: material.combine, 7572 7573 // 7574 7575 mapUv: HAS_MAP && getChannel( material.map.channel ), 7576 aoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ), 7577 lightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ), 7578 bumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ), 7579 normalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ), 7580 displacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ), 7581 emissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ), 7582 7583 metalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ), 7584 roughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ), 7585 7586 anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ), 7587 7588 clearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ), 7589 clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ), 7590 clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ), 7591 7592 iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ), 7593 iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ), 7594 7595 sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ), 7596 sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ), 7597 7598 specularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ), 7599 specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ), 7600 specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ), 7601 7602 transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ), 7603 thicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ), 7604 7605 alphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ), 7606 7607 // 7608 7609 vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ), 7610 vertexNormals: !! geometry.attributes.normal, 7611 vertexColors: material.vertexColors, 7612 vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4, 7613 7614 pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ), 7615 7616 fog: !! fog, 7617 useFog: material.fog === true, 7618 fogExp2: ( !! fog && fog.isFogExp2 ), 7619 7620 flatShading: material.wireframe === false && ( 7621 material.flatShading === true || 7622 ( geometry.attributes.normal === undefined && HAS_NORMALMAP === false && 7623 ( material.isMeshLambertMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial || material.isMeshPhysicalMaterial ) 7624 ) 7625 ), 7626 7627 sizeAttenuation: material.sizeAttenuation === true, 7628 logarithmicDepthBuffer: logarithmicDepthBuffer, 7629 reversedDepthBuffer: reversedDepthBuffer, 7630 7631 skinning: object.isSkinnedMesh === true, 7632 7633 hasPositionAttribute: geometry.attributes.position !== undefined, 7634 7635 morphTargets: geometry.morphAttributes.position !== undefined, 7636 morphNormals: geometry.morphAttributes.normal !== undefined, 7637 morphColors: geometry.morphAttributes.color !== undefined, 7638 morphTargetsCount: morphTargetsCount, 7639 morphTextureStride: morphTextureStride, 7640 7641 numSunLights: lights.sun.length, 7642 numDirLights: lights.directional.length, 7643 numPointLights: lights.point.length, 7644 numSpotLights: lights.spot.length, 7645 numSpotLightMaps: lights.spotLightMap.length, 7646 numRectAreaLights: lights.rectArea.length, 7647 numHemiLights: lights.hemi.length, 7648 7649 numSunLightShadows: lights.sunShadowMap.length, 7650 numDirLightShadows: lights.directionalShadowMap.length, 7651 numPointLightShadows: lights.pointShadowMap.length, 7652 numSpotLightShadows: lights.spotShadowMap.length, 7653 numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, 7654 7655 numLightProbes: lights.numLightProbes, 7656 7657 numLightProbeGrids: lightProbeGrids.length, 7658 7659 numClippingPlanes: clipping.numPlanes, 7660 numClipIntersection: clipping.numIntersection, 7661 7662 dithering: material.dithering, 7663 7664 shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, 7665 shadowMapType: renderer.shadowMap.type, 7666 7667 toneMapping: toneMapping, 7668 7669 decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ), 7670 decodeVideoTextureEmissive: HAS_EMISSIVEMAP && ( material.emissiveMap.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.emissiveMap.colorSpace ) === SRGBTransfer ), 7671 7672 premultipliedAlpha: material.premultipliedAlpha, 7673 7674 doubleSided: material.side === DoubleSide, 7675 flipSided: material.side === BackSide, 7676 7677 useDepthPacking: material.depthPacking >= 0, 7678 depthPacking: material.depthPacking || 0, 7679 7680 index0AttributeName: material.index0AttributeName, 7681 7682 extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance === true && extensions.has( 'WEBGL_clip_cull_distance' ), 7683 extensionMultiDraw: ( HAS_EXTENSIONS && material.extensions.multiDraw === true || IS_BATCHEDMESH ) && extensions.has( 'WEBGL_multi_draw' ), 7684 7685 rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ), 7686 7687 customProgramCacheKey: material.customProgramCacheKey() 7688 7689 }; 7690 7691 // the usage of getChannel() determines the active texture channels for this shader 7692 7693 parameters.vertexUv1s = _activeChannels.has( 1 ); 7694 parameters.vertexUv2s = _activeChannels.has( 2 ); 7695 parameters.vertexUv3s = _activeChannels.has( 3 ); 7696 7697 _activeChannels.clear(); 7698 7699 return parameters; 7700 7701 } 7702 7703 function getProgramCacheKey( parameters ) { 7704 7705 const array = []; 7706 7707 if ( parameters.shaderID ) { 7708 7709 array.push( parameters.shaderID ); 7710 7711 } else { 7712 7713 array.push( parameters.customVertexShaderID ); 7714 array.push( parameters.customFragmentShaderID ); 7715 7716 } 7717 7718 if ( parameters.defines !== undefined ) { 7719 7720 for ( const name in parameters.defines ) { 7721 7722 array.push( name ); 7723 array.push( parameters.defines[ name ] ); 7724 7725 } 7726 7727 } 7728 7729 if ( parameters.isRawShaderMaterial === false ) { 7730 7731 getProgramCacheKeyParameters( array, parameters ); 7732 getProgramCacheKeyBooleans( array, parameters ); 7733 array.push( renderer.outputColorSpace ); 7734 7735 } 7736 7737 array.push( parameters.customProgramCacheKey ); 7738 7739 return array.join(); 7740 7741 } 7742 7743 function getProgramCacheKeyParameters( array, parameters ) { 7744 7745 array.push( parameters.precision ); 7746 array.push( parameters.outputColorSpace ); 7747 array.push( parameters.envMapMode ); 7748 array.push( parameters.envMapCubeUVHeight ); 7749 array.push( parameters.mapUv ); 7750 array.push( parameters.alphaMapUv ); 7751 array.push( parameters.lightMapUv ); 7752 array.push( parameters.aoMapUv ); 7753 array.push( parameters.bumpMapUv ); 7754 array.push( parameters.normalMapUv ); 7755 array.push( parameters.displacementMapUv ); 7756 array.push( parameters.emissiveMapUv ); 7757 array.push( parameters.metalnessMapUv ); 7758 array.push( parameters.roughnessMapUv ); 7759 array.push( parameters.anisotropyMapUv ); 7760 array.push( parameters.clearcoatMapUv ); 7761 array.push( parameters.clearcoatNormalMapUv ); 7762 array.push( parameters.clearcoatRoughnessMapUv ); 7763 array.push( parameters.iridescenceMapUv ); 7764 array.push( parameters.iridescenceThicknessMapUv ); 7765 array.push( parameters.sheenColorMapUv ); 7766 array.push( parameters.sheenRoughnessMapUv ); 7767 array.push( parameters.specularMapUv ); 7768 array.push( parameters.specularColorMapUv ); 7769 array.push( parameters.specularIntensityMapUv ); 7770 array.push( parameters.transmissionMapUv ); 7771 array.push( parameters.thicknessMapUv ); 7772 array.push( parameters.combine ); 7773 array.push( parameters.fogExp2 ); 7774 array.push( parameters.sizeAttenuation ); 7775 array.push( parameters.morphTargetsCount ); 7776 array.push( parameters.morphAttributeCount ); 7777 array.push( parameters.numSunLights ); 7778 array.push( parameters.numDirLights ); 7779 array.push( parameters.numPointLights ); 7780 array.push( parameters.numSpotLights ); 7781 array.push( parameters.numSpotLightMaps ); 7782 array.push( parameters.numHemiLights ); 7783 array.push( parameters.numRectAreaLights ); 7784 array.push( parameters.numSunLightShadows ); 7785 array.push( parameters.numDirLightShadows ); 7786 array.push( parameters.numPointLightShadows ); 7787 array.push( parameters.numSpotLightShadows ); 7788 array.push( parameters.numSpotLightShadowsWithMaps ); 7789 array.push( parameters.numLightProbes ); 7790 array.push( parameters.shadowMapType ); 7791 array.push( parameters.toneMapping ); 7792 array.push( parameters.numClippingPlanes ); 7793 array.push( parameters.numClipIntersection ); 7794 array.push( parameters.depthPacking ); 7795 7796 } 7797 7798 function getProgramCacheKeyBooleans( array, parameters ) { 7799 7800 _programLayers.disableAll(); 7801 7802 if ( parameters.instancing ) 7803 _programLayers.enable( 0 ); 7804 if ( parameters.instancingColor ) 7805 _programLayers.enable( 1 ); 7806 if ( parameters.instancingMorph ) 7807 _programLayers.enable( 2 ); 7808 if ( parameters.matcap ) 7809 _programLayers.enable( 3 ); 7810 if ( parameters.envMap ) 7811 _programLayers.enable( 4 ); 7812 if ( parameters.normalMapObjectSpace ) 7813 _programLayers.enable( 5 ); 7814 if ( parameters.normalMapTangentSpace ) 7815 _programLayers.enable( 6 ); 7816 if ( parameters.clearcoat ) 7817 _programLayers.enable( 7 ); 7818 if ( parameters.iridescence ) 7819 _programLayers.enable( 8 ); 7820 if ( parameters.alphaTest ) 7821 _programLayers.enable( 9 ); 7822 if ( parameters.vertexColors ) 7823 _programLayers.enable( 10 ); 7824 if ( parameters.vertexAlphas ) 7825 _programLayers.enable( 11 ); 7826 if ( parameters.vertexUv1s ) 7827 _programLayers.enable( 12 ); 7828 if ( parameters.vertexUv2s ) 7829 _programLayers.enable( 13 ); 7830 if ( parameters.vertexUv3s ) 7831 _programLayers.enable( 14 ); 7832 if ( parameters.vertexTangents ) 7833 _programLayers.enable( 15 ); 7834 if ( parameters.anisotropy ) 7835 _programLayers.enable( 16 ); 7836 if ( parameters.alphaHash ) 7837 _programLayers.enable( 17 ); 7838 if ( parameters.batching ) 7839 _programLayers.enable( 18 ); 7840 if ( parameters.dispersion ) 7841 _programLayers.enable( 19 ); 7842 if ( parameters.retroreflection ) 7843 _programLayers.enable( 24 ); 7844 if ( parameters.batchingColor ) 7845 _programLayers.enable( 20 ); 7846 if ( parameters.gradientMap ) 7847 _programLayers.enable( 21 ); 7848 if ( parameters.packedNormalMap ) 7849 _programLayers.enable( 22 ); 7850 if ( parameters.vertexNormals ) 7851 _programLayers.enable( 23 ); 7852 7853 array.push( _programLayers.mask ); 7854 _programLayers.disableAll(); 7855 7856 if ( parameters.fog ) 7857 _programLayers.enable( 0 ); 7858 if ( parameters.useFog ) 7859 _programLayers.enable( 1 ); 7860 if ( parameters.flatShading ) 7861 _programLayers.enable( 2 ); 7862 if ( parameters.logarithmicDepthBuffer ) 7863 _programLayers.enable( 3 ); 7864 if ( parameters.reversedDepthBuffer ) 7865 _programLayers.enable( 4 ); 7866 if ( parameters.skinning ) 7867 _programLayers.enable( 5 ); 7868 if ( parameters.morphTargets ) 7869 _programLayers.enable( 6 ); 7870 if ( parameters.morphNormals ) 7871 _programLayers.enable( 7 ); 7872 if ( parameters.morphColors ) 7873 _programLayers.enable( 8 ); 7874 if ( parameters.premultipliedAlpha ) 7875 _programLayers.enable( 9 ); 7876 if ( parameters.shadowMapEnabled ) 7877 _programLayers.enable( 10 ); 7878 if ( parameters.doubleSided ) 7879 _programLayers.enable( 11 ); 7880 if ( parameters.flipSided ) 7881 _programLayers.enable( 12 ); 7882 if ( parameters.useDepthPacking ) 7883 _programLayers.enable( 13 ); 7884 if ( parameters.dithering ) 7885 _programLayers.enable( 14 ); 7886 if ( parameters.transmission ) 7887 _programLayers.enable( 15 ); 7888 if ( parameters.sheen ) 7889 _programLayers.enable( 16 ); 7890 if ( parameters.opaque ) 7891 _programLayers.enable( 17 ); 7892 if ( parameters.pointsUvs ) 7893 _programLayers.enable( 18 ); 7894 if ( parameters.decodeVideoTexture ) 7895 _programLayers.enable( 19 ); 7896 if ( parameters.decodeVideoTextureEmissive ) 7897 _programLayers.enable( 20 ); 7898 if ( parameters.alphaToCoverage ) 7899 _programLayers.enable( 21 ); 7900 if ( parameters.numLightProbeGrids > 0 ) 7901 _programLayers.enable( 22 ); 7902 if ( parameters.hasPositionAttribute ) 7903 _programLayers.enable( 23 ); 7904 7905 array.push( _programLayers.mask ); 7906 7907 } 7908 7909 function getUniforms( material ) { 7910 7911 const shaderID = shaderIDs[ material.type ]; 7912 let uniforms; 7913 7914 if ( shaderID ) { 7915 7916 const shader = ShaderLib[ shaderID ]; 7917 uniforms = UniformsUtils.clone( shader.uniforms ); 7918 7919 } else { 7920 7921 uniforms = material.uniforms; 7922 7923 } 7924 7925 return uniforms; 7926 7927 } 7928 7929 function acquireProgram( parameters, cacheKey ) { 7930 7931 let program = programsMap.get( cacheKey ); 7932 7933 if ( program !== undefined ) { 7934 7935 ++ program.usedTimes; 7936 7937 } else { 7938 7939 program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates ); 7940 programs.push( program ); 7941 7942 programsMap.set( cacheKey, program ); 7943 7944 } 7945 7946 return program; 7947 7948 } 7949 7950 function releaseProgram( program ) { 7951 7952 if ( -- program.usedTimes === 0 ) { 7953 7954 // Remove from unordered set 7955 const i = programs.indexOf( program ); 7956 programs[ i ] = programs[ programs.length - 1 ]; 7957 programs.pop(); 7958 7959 // Remove from map 7960 programsMap.delete( program.cacheKey ); 7961 7962 // Free WebGL resources 7963 program.destroy(); 7964 7965 } 7966 7967 } 7968 7969 function releaseShaderCache( material ) { 7970 7971 _customShaders.remove( material ); 7972 7973 } 7974 7975 function dispose() { 7976 7977 _customShaders.dispose(); 7978 7979 } 7980 7981 return { 7982 getParameters: getParameters, 7983 getProgramCacheKey: getProgramCacheKey, 7984 getUniforms: getUniforms, 7985 acquireProgram: acquireProgram, 7986 releaseProgram: releaseProgram, 7987 releaseShaderCache: releaseShaderCache, 7988 // Exposed for resource monitoring & error feedback via renderer.info: 7989 programs: programs, 7990 dispose: dispose 7991 }; 7992 7993} 7994 7995function WebGLProperties() { 7996 7997 let properties = new WeakMap(); 7998 7999 function has( object ) { 8000 8001 return properties.has( object ); 8002 8003 } 8004 8005 function get( object ) { 8006 8007 let map = properties.get( object ); 8008 8009 if ( map === undefined ) { 8010 8011 map = {}; 8012 properties.set( object, map ); 8013 8014 } 8015 8016 return map; 8017 8018 } 8019 8020 function remove( object ) { 8021 8022 properties.delete( object ); 8023 8024 } 8025 8026 function update( object, key, value ) { 8027 8028 properties.get( object )[ key ] = value; 8029 8030 } 8031 8032 function dispose() { 8033 8034 properties = new WeakMap(); 8035 8036 } 8037 8038 return { 8039 has: has, 8040 get: get, 8041 remove: remove, 8042 update: update, 8043 dispose: dispose 8044 }; 8045 8046} 8047 8048function painterSortStable( a, b ) { 8049 8050 if ( a.groupOrder !== b.groupOrder ) { 8051 8052 return a.groupOrder - b.groupOrder; 8053 8054 } else if ( a.renderOrder !== b.renderOrder ) { 8055 8056 return a.renderOrder - b.renderOrder; 8057 8058 } else if ( a.material.id !== b.material.id ) { 8059 8060 return a.material.id - b.material.id; 8061 8062 } else if ( a.materialVariant !== b.materialVariant ) { 8063 8064 return a.materialVariant - b.materialVariant; 8065 8066 } else if ( a.z !== b.z ) { 8067 8068 return a.z - b.z; 8069 8070 } else { 8071 8072 return a.id - b.id; 8073 8074 } 8075 8076} 8077 8078function reversePainterSortStable( a, b ) { 8079 8080 if ( a.groupOrder !== b.groupOrder ) { 8081 8082 return a.groupOrder - b.groupOrder; 8083 8084 } else if ( a.renderOrder !== b.renderOrder ) { 8085 8086 return a.renderOrder - b.renderOrder; 8087 8088 } else if ( a.z !== b.z ) { 8089 8090 return b.z - a.z; 8091 8092 } else { 8093 8094 return a.id - b.id; 8095 8096 } 8097 8098} 8099 8100 8101function WebGLRenderList() { 8102 8103 const renderItems = []; 8104 let renderItemsIndex = 0; 8105 8106 const opaque = []; 8107 const transmissive = []; 8108 const transparent = []; 8109 8110 function init() { 8111 8112 renderItemsIndex = 0; 8113 8114 opaque.length = 0; 8115 transmissive.length = 0; 8116 transparent.length = 0; 8117 8118 } 8119 8120 function materialVariant( object ) { 8121 8122 let variant = 0; 8123 if ( object.isInstancedMesh ) variant += 2; 8124 if ( object.isSkinnedMesh ) variant += 1; 8125 return variant; 8126 8127 } 8128 8129 function getNextRenderItem( object, geometry, material, groupOrder, z, group ) { 8130 8131 let renderItem = renderItems[ renderItemsIndex ]; 8132 8133 if ( renderItem === undefined ) { 8134 8135 renderItem = { 8136 id: object.id, 8137 object: object, 8138 geometry: geometry, 8139 material: material, 8140 materialVariant: materialVariant( object ), 8141 groupOrder: groupOrder, 8142 renderOrder: object.renderOrder, 8143 z: z, 8144 group: group 8145 }; 8146 8147 renderItems[ renderItemsIndex ] = renderItem; 8148 8149 } else { 8150 8151 renderItem.id = object.id; 8152 renderItem.object = object; 8153 renderItem.geometry = geometry; 8154 renderItem.material = material; 8155 renderItem.materialVariant = materialVariant( object ); 8156 renderItem.groupOrder = groupOrder; 8157 renderItem.renderOrder = object.renderOrder; 8158 renderItem.z = z; 8159 renderItem.group = group; 8160 8161 } 8162 8163 renderItemsIndex ++; 8164 8165 return renderItem; 8166 8167 } 8168 8169 function push( object, geometry, material, groupOrder, z, group, camera ) { 8170 8171 // with a reversed depth buffer the projected z is inverted 8172 8173 if ( camera.reversedDepth === true ) z = - z; 8174 8175 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); 8176 8177 if ( material.transmission > 0.0 ) { 8178 8179 transmissive.push( renderItem ); 8180 8181 } else if ( material.transparent === true ) { 8182 8183 transparent.push( renderItem ); 8184 8185 } else { 8186 8187 opaque.push( renderItem ); 8188 8189 } 8190 8191 } 8192 8193 function unshift( object, geometry, material, groupOrder, z, group ) { 8194 8195 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); 8196 8197 if ( material.transmission > 0.0 ) { 8198 8199 transmissive.unshift( renderItem ); 8200 8201 } else if ( material.transparent === true ) { 8202 8203 transparent.unshift( renderItem ); 8204 8205 } else { 8206 8207 opaque.unshift( renderItem ); 8208 8209 } 8210 8211 } 8212 8213 function sort( customOpaqueSort, customTransparentSort ) { 8214 8215 if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable ); 8216 if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable ); 8217 if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable ); 8218 8219 } 8220 8221 function finish() { 8222 8223 // Clear references from inactive renderItems in the list 8224 8225 for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) { 8226 8227 const renderItem = renderItems[ i ]; 8228 8229 if ( renderItem.id === null ) break; 8230 8231 renderItem.id = null; 8232 renderItem.object = null; 8233 renderItem.geometry = null; 8234 renderItem.material = null; 8235 renderItem.group = null; 8236 8237 } 8238 8239 } 8240 8241 return { 8242 8243 opaque: opaque, 8244 transmissive: transmissive, 8245 transparent: transparent, 8246 8247 init: init, 8248 push: push, 8249 unshift: unshift, 8250 finish: finish, 8251 8252 sort: sort 8253 }; 8254 8255} 8256 8257function WebGLRenderLists() { 8258 8259 let lists = new WeakMap(); 8260 8261 function get( scene, renderCallDepth ) { 8262 8263 const listArray = lists.get( scene ); 8264 let list; 8265 8266 if ( listArray === undefined ) { 8267 8268 list = new WebGLRenderList(); 8269 lists.set( scene, [ list ] ); 8270 8271 } else { 8272 8273 if ( renderCallDepth >= listArray.length ) { 8274 8275 list = new WebGLRenderList(); 8276 listArray.push( list ); 8277 8278 } else { 8279 8280 list = listArray[ renderCallDepth ]; 8281 8282 } 8283 8284 } 8285 8286 return list; 8287 8288 } 8289 8290 function dispose() { 8291 8292 lists = new WeakMap(); 8293 8294 } 8295 8296 return { 8297 get: get, 8298 dispose: dispose 8299 }; 8300 8301} 8302 8303function UniformsCache() { 8304 8305 const lights = {}; 8306 8307 return { 8308 8309 get: function ( light ) { 8310 8311 if ( lights[ light.id ] !== undefined ) { 8312 8313 return lights[ light.id ]; 8314 8315 } 8316 8317 let uniforms; 8318 8319 switch ( light.type ) { 8320 8321 case 'SunLight': 8322 case 'DirectionalLight': 8323 uniforms = { 8324 direction: new Vector3(), 8325 color: new Color() 8326 }; 8327 break; 8328 8329 case 'SpotLight': 8330 uniforms = { 8331 position: new Vector3(), 8332 direction: new Vector3(), 8333 color: new Color(), 8334 distance: 0, 8335 coneCos: 0, 8336 penumbraCos: 0, 8337 decay: 0 8338 }; 8339 break; 8340 8341 case 'PointLight': 8342 uniforms = { 8343 position: new Vector3(), 8344 color: new Color(), 8345 distance: 0, 8346 decay: 0 8347 }; 8348 break; 8349 8350 case 'HemisphereLight': 8351 uniforms = { 8352 direction: new Vector3(), 8353 skyColor: new Color(), 8354 groundColor: new Color() 8355 }; 8356 break; 8357 8358 case 'RectAreaLight': 8359 uniforms = { 8360 color: new Color(), 8361 position: new Vector3(), 8362 halfWidth: new Vector3(), 8363 halfHeight: new Vector3() 8364 }; 8365 break; 8366 8367 } 8368 8369 lights[ light.id ] = uniforms; 8370 8371 return uniforms; 8372 8373 } 8374 8375 }; 8376 8377} 8378 8379function ShadowUniformsCache() { 8380 8381 const lights = {}; 8382 8383 return { 8384 8385 get: function ( light ) { 8386 8387 if ( lights[ light.id ] !== undefined ) { 8388 8389 return lights[ light.id ]; 8390 8391 } 8392 8393 let uniforms; 8394 8395 switch ( light.type ) { 8396 8397 case 'SunLight': 8398 case 'DirectionalLight': 8399 uniforms = { 8400 shadowIntensity: 1, 8401 shadowBias: 0, 8402 shadowNormalBias: 0, 8403 shadowRadius: 1, 8404 shadowMapSize: new Vector2() 8405 }; 8406 break; 8407 8408 case 'SpotLight': 8409 uniforms = { 8410 shadowIntensity: 1, 8411 shadowBias: 0, 8412 shadowNormalBias: 0, 8413 shadowRadius: 1, 8414 shadowMapSize: new Vector2() 8415 }; 8416 break; 8417 8418 case 'PointLight': 8419 uniforms = { 8420 shadowIntensity: 1, 8421 shadowBias: 0, 8422 shadowNormalBias: 0, 8423 shadowRadius: 1, 8424 shadowMapSize: new Vector2(), 8425 shadowCameraNear: 1, 8426 shadowCameraFar: 1000 8427 }; 8428 break; 8429 8430 // TODO (abelnation): set RectAreaLight shadow uniforms 8431 8432 } 8433 8434 lights[ light.id ] = uniforms; 8435 8436 return uniforms; 8437 8438 } 8439 8440 }; 8441 8442} 8443 8444 8445 8446let nextVersion = 0; 8447 8448function shadowCastingAndTexturingLightsFirst( lightA, lightB ) { 8449 8450 return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 ); 8451 8452} 8453 8454function WebGLLights( extensions ) { 8455 8456 const cache = new UniformsCache(); 8457 8458 const shadowCache = ShadowUniformsCache(); 8459 8460 const state = { 8461 8462 version: 0, 8463 8464 hash: { 8465 sunLength: -1, 8466 directionalLength: -1, 8467 pointLength: -1, 8468 spotLength: -1, 8469 rectAreaLength: -1, 8470 hemiLength: -1, 8471 8472 numSunShadows: -1, 8473 numDirectionalShadows: -1, 8474 numPointShadows: -1, 8475 numSpotShadows: -1, 8476 numSpotMaps: -1, 8477 8478 numLightProbes: -1 8479 }, 8480 8481 ambient: [ 0, 0, 0 ], 8482 probe: [], 8483 sun: [], 8484 sunShadow: [], 8485 sunShadowMap: [], 8486 sunShadowMatrix: [], 8487 sunShadowCascade: [], 8488 directional: [], 8489 directionalShadow: [], 8490 directionalShadowMap: [], 8491 directionalShadowMatrix: [], 8492 spot: [], 8493 spotLightMap: [], 8494 spotShadow: [], 8495 spotShadowMap: [], 8496 spotLightMatrix: [], 8497 rectArea: [], 8498 rectAreaLTC1: null, 8499 rectAreaLTC2: null, 8500 point: [], 8501 pointShadow: [], 8502 pointShadowMap: [], 8503 pointShadowMatrix: [], 8504 hemi: [], 8505 numSpotLightShadowsWithMaps: 0, 8506 numLightProbes: 0 8507 8508 }; 8509 8510 for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() ); 8511 8512 const vector3 = new Vector3(); 8513 const matrix4 = new Matrix4(); 8514 const matrix42 = new Matrix4(); 8515 8516 function setup( lights ) { 8517 8518 let r = 0, g = 0, b = 0; 8519 8520 for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 ); 8521 8522 let sunLength = 0; 8523 let numSunShadows = 0; 8524 let numSunShadowCascades = 0; 8525 let directionalLength = 0; 8526 let pointLength = 0; 8527 let spotLength = 0; 8528 let rectAreaLength = 0; 8529 let hemiLength = 0; 8530 8531 let numDirectionalShadows = 0; 8532 let numPointShadows = 0; 8533 let numSpotShadows = 0; 8534 let numSpotMaps = 0; 8535 let numSpotShadowsWithMaps = 0; 8536 8537 let numLightProbes = 0; 8538 8539 // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] 8540 lights.sort( shadowCastingAndTexturingLightsFirst ); 8541 8542 for ( let i = 0, l = lights.length; i < l; i ++ ) { 8543 8544 const light = lights[ i ]; 8545 8546 const color = light.color; 8547 const intensity = light.intensity; 8548 const distance = light.distance; 8549 8550 let shadowMap = null; 8551 8552 if ( light.shadow && light.shadow.map ) { 8553 8554 if ( light.shadow.map.texture.format === RGFormat ) { 8555 8556 // VSM uses color texture with blurred mean/std_dev 8557 shadowMap = light.shadow.map.texture; 8558 8559 } else { 8560 8561 // Other types use depth texture 8562 shadowMap = light.shadow.map.depthTexture || light.shadow.map.texture; 8563 8564 } 8565 8566 } 8567 8568 if ( light.isAmbientLight ) { 8569 8570 r += color.r * intensity; 8571 g += color.g * intensity; 8572 b += color.b * intensity; 8573 8574 } else if ( light.isLightProbe ) { 8575 8576 for ( let j = 0; j < 9; j ++ ) { 8577 8578 state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity ); 8579 8580 } 8581 8582 numLightProbes ++; 8583 8584 } else if ( light.isSunLight ) { 8585 8586 const uniforms = cache.get( light ); 8587 8588 uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); 8589 8590 if ( light.castShadow ) { 8591 8592 const shadow = light.shadow; 8593 8594 const shadowUniforms = shadowCache.get( light ); 8595 8596 shadowUniforms.shadowIntensity = shadow.intensity; 8597 shadowUniforms.shadowBias = shadow.bias; 8598 shadowUniforms.shadowNormalBias = shadow.normalBias; 8599 shadowUniforms.shadowRadius = shadow.radius; 8600 shadowUniforms.shadowMapSize.copy( shadow.mapSize ).multiply( shadow.getFrameExtents() ); 8601 8602 state.sunShadow[ numSunShadows ] = shadowUniforms; 8603 state.sunShadowMap[ numSunShadows ] = shadowMap; 8604 8605 const cascadeCount = shadow.getViewportCount(); 8606 8607 for ( let j = 0; j < cascadeCount; j ++ ) { 8608 8609 state.sunShadowMatrix[ numSunShadowCascades + j ] = shadow.getMatrix( j ); 8610 state.sunShadowCascade[ numSunShadowCascades + j ] = shadow._cascadeData[ j ]; 8611 8612 } 8613 8614 numSunShadowCascades += cascadeCount; 8615 numSunShadows ++; 8616 8617 } 8618 8619 state.sun[ sunLength ] = uniforms; 8620 8621 sunLength ++; 8622 8623 } else if ( light.isDirectionalLight ) { 8624 8625 const uniforms = cache.get( light ); 8626 8627 uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); 8628 8629 if ( light.castShadow ) { 8630 8631 const shadow = light.shadow; 8632 8633 const shadowUniforms = shadowCache.get( light ); 8634 8635 shadowUniforms.shadowIntensity = shadow.intensity; 8636 shadowUniforms.shadowBias = shadow.bias; 8637 shadowUniforms.shadowNormalBias = shadow.normalBias; 8638 shadowUniforms.shadowRadius = shadow.radius; 8639 shadowUniforms.shadowMapSize = shadow.mapSize; 8640 8641 state.directionalShadow[ directionalLength ] = shadowUniforms; 8642 state.directionalShadowMap[ directionalLength ] = shadowMap; 8643 state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; 8644 8645 numDirectionalShadows ++; 8646 8647 } 8648 8649 state.directional[ directionalLength ] = uniforms; 8650 8651 directionalLength ++; 8652 8653 } else if ( light.isSpotLight ) { 8654 8655 const uniforms = cache.get( light ); 8656 8657 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 8658 8659 uniforms.color.copy( color ).multiplyScalar( intensity ); 8660 uniforms.distance = distance; 8661 8662 uniforms.coneCos = Math.cos( light.angle ); 8663 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); 8664 uniforms.decay = light.decay; 8665 8666 state.spot[ spotLength ] = uniforms; 8667 8668 const shadow = light.shadow; 8669 8670 if ( light.map ) { 8671 8672 state.spotLightMap[ numSpotMaps ] = light.map; 8673 numSpotMaps ++; 8674 8675 // make sure the lightMatrix is up to date 8676 // TODO : do it if required only 8677 shadow.updateMatrices( light ); 8678 8679 if ( light.castShadow ) numSpotShadowsWithMaps ++; 8680 8681 } 8682 8683 state.spotLightMatrix[ spotLength ] = shadow.matrix; 8684 8685 if ( light.castShadow ) { 8686 8687 const shadowUniforms = shadowCache.get( light ); 8688 8689 shadowUniforms.shadowIntensity = shadow.intensity; 8690 shadowUniforms.shadowBias = shadow.bias; 8691 shadowUniforms.shadowNormalBias = shadow.normalBias; 8692 shadowUniforms.shadowRadius = shadow.radius; 8693 shadowUniforms.shadowMapSize = shadow.mapSize; 8694 8695 state.spotShadow[ spotLength ] = shadowUniforms; 8696 state.spotShadowMap[ spotLength ] = shadowMap; 8697 8698 numSpotShadows ++; 8699 8700 } 8701 8702 spotLength ++; 8703 8704 } else if ( light.isRectAreaLight ) { 8705 8706 const uniforms = cache.get( light ); 8707 8708 uniforms.color.copy( color ).multiplyScalar( intensity ); 8709 8710 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); 8711 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); 8712 8713 state.rectArea[ rectAreaLength ] = uniforms; 8714 8715 rectAreaLength ++; 8716 8717 } else if ( light.isPointLight ) { 8718 8719 const uniforms = cache.get( light ); 8720 8721 uniforms.color.copy( light.color ).multiplyScalar( light.intensity ); 8722 uniforms.distance = light.distance; 8723 uniforms.decay = light.decay; 8724 8725 if ( light.castShadow ) { 8726 8727 const shadow = light.shadow; 8728 8729 const shadowUniforms = shadowCache.get( light ); 8730 8731 shadowUniforms.shadowIntensity = shadow.intensity; 8732 shadowUniforms.shadowBias = shadow.bias; 8733 shadowUniforms.shadowNormalBias = shadow.normalBias; 8734 shadowUniforms.shadowRadius = shadow.radius; 8735 shadowUniforms.shadowMapSize = shadow.mapSize; 8736 shadowUniforms.shadowCameraNear = shadow.camera.near; 8737 shadowUniforms.shadowCameraFar = shadow.camera.far; 8738 8739 state.pointShadow[ pointLength ] = shadowUniforms; 8740 state.pointShadowMap[ pointLength ] = shadowMap; 8741 state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; 8742 8743 numPointShadows ++; 8744 8745 } 8746 8747 state.point[ pointLength ] = uniforms; 8748 8749 pointLength ++; 8750 8751 } else if ( light.isHemisphereLight ) { 8752 8753 const uniforms = cache.get( light ); 8754 8755 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity ); 8756 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity ); 8757 8758 state.hemi[ hemiLength ] = uniforms; 8759 8760 hemiLength ++; 8761 8762 } 8763 8764 } 8765 8766 if ( rectAreaLength > 0 ) { 8767 8768 if ( extensions.has( 'OES_texture_float_linear' ) === true ) { 8769 8770 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; 8771 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; 8772 8773 } else { 8774 8775 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; 8776 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; 8777 8778 } 8779 8780 } 8781 8782 state.ambient[ 0 ] = r; 8783 state.ambient[ 1 ] = g; 8784 state.ambient[ 2 ] = b; 8785 8786 const hash = state.hash; 8787 8788 if ( hash.sunLength !== sunLength || 8789 hash.directionalLength !== directionalLength || 8790 hash.pointLength !== pointLength || 8791 hash.spotLength !== spotLength || 8792 hash.rectAreaLength !== rectAreaLength || 8793 hash.hemiLength !== hemiLength || 8794 hash.numSunShadows !== numSunShadows || 8795 hash.numDirectionalShadows !== numDirectionalShadows || 8796 hash.numPointShadows !== numPointShadows || 8797 hash.numSpotShadows !== numSpotShadows || 8798 hash.numSpotMaps !== numSpotMaps || 8799 hash.numLightProbes !== numLightProbes ) { 8800 8801 state.sun.length = sunLength; 8802 state.directional.length = directionalLength; 8803 state.spot.length = spotLength; 8804 state.rectArea.length = rectAreaLength; 8805 state.point.length = pointLength; 8806 state.hemi.length = hemiLength; 8807 8808 state.sunShadow.length = numSunShadows; 8809 state.sunShadowMap.length = numSunShadows; 8810 state.sunShadowMatrix.length = numSunShadowCascades; 8811 state.sunShadowCascade.length = numSunShadowCascades; 8812 state.directionalShadow.length = numDirectionalShadows; 8813 state.directionalShadowMap.length = numDirectionalShadows; 8814 state.directionalShadowMatrix.length = numDirectionalShadows; 8815 state.pointShadow.length = numPointShadows; 8816 state.pointShadowMap.length = numPointShadows; 8817 state.pointShadowMatrix.length = numPointShadows; 8818 state.spotShadow.length = numSpotShadows; 8819 state.spotShadowMap.length = numSpotShadows; 8820 state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; 8821 state.spotLightMap.length = numSpotMaps; 8822 state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; 8823 state.numLightProbes = numLightProbes; 8824 8825 hash.sunLength = sunLength; 8826 hash.directionalLength = directionalLength; 8827 hash.pointLength = pointLength; 8828 hash.spotLength = spotLength; 8829 hash.rectAreaLength = rectAreaLength; 8830 hash.hemiLength = hemiLength; 8831 8832 hash.numSunShadows = numSunShadows; 8833 hash.numDirectionalShadows = numDirectionalShadows; 8834 hash.numPointShadows = numPointShadows; 8835 hash.numSpotShadows = numSpotShadows; 8836 hash.numSpotMaps = numSpotMaps; 8837 8838 hash.numLightProbes = numLightProbes; 8839 8840 state.version = nextVersion ++; 8841 8842 } 8843 8844 } 8845 8846 function setupView( lights, camera ) { 8847 8848 let sunLength = 0; 8849 let directionalLength = 0; 8850 let pointLength = 0; 8851 let spotLength = 0; 8852 let rectAreaLength = 0; 8853 let hemiLength = 0; 8854 8855 const viewMatrix = camera.matrixWorldInverse; 8856 8857 for ( let i = 0, l = lights.length; i < l; i ++ ) { 8858 8859 const light = lights[ i ]; 8860 8861 if ( light.isSunLight ) { 8862 8863 const uniforms = state.sun[ sunLength ]; 8864 8865 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 8866 uniforms.direction.transformDirection( viewMatrix ); 8867 8868 sunLength ++; 8869 8870 } else if ( light.isDirectionalLight ) { 8871 8872 const uniforms = state.directional[ directionalLength ]; 8873 8874 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 8875 vector3.setFromMatrixPosition( light.target.matrixWorld ); 8876 uniforms.direction.sub( vector3 ); 8877 uniforms.direction.transformDirection( viewMatrix ); 8878 8879 directionalLength ++; 8880 8881 } else if ( light.isSpotLight ) { 8882 8883 const uniforms = state.spot[ spotLength ]; 8884 8885 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 8886 uniforms.position.applyMatrix4( viewMatrix ); 8887 8888 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 8889 vector3.setFromMatrixPosition( light.target.matrixWorld ); 8890 uniforms.direction.sub( vector3 ); 8891 uniforms.direction.transformDirection( viewMatrix ); 8892 8893 spotLength ++; 8894 8895 } else if ( light.isRectAreaLight ) { 8896 8897 const uniforms = state.rectArea[ rectAreaLength ]; 8898 8899 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 8900 uniforms.position.applyMatrix4( viewMatrix ); 8901 8902 // extract local rotation of light to derive width/height half vectors 8903 matrix42.identity(); 8904 matrix4.copy( light.matrixWorld ); 8905 matrix4.premultiply( viewMatrix ); 8906 matrix42.extractRotation( matrix4 ); 8907 8908 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); 8909 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); 8910 8911 uniforms.halfWidth.applyMatrix4( matrix42 ); 8912 uniforms.halfHeight.applyMatrix4( matrix42 ); 8913 8914 rectAreaLength ++; 8915 8916 } else if ( light.isPointLight ) { 8917 8918 const uniforms = state.point[ pointLength ]; 8919 8920 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 8921 uniforms.position.applyMatrix4( viewMatrix ); 8922 8923 pointLength ++; 8924 8925 } else if ( light.isHemisphereLight ) { 8926 8927 const uniforms = state.hemi[ hemiLength ]; 8928 8929 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 8930 uniforms.direction.transformDirection( viewMatrix ); 8931 8932 hemiLength ++; 8933 8934 } 8935 8936 } 8937 8938 } 8939 8940 return { 8941 setup: setup, 8942 setupView: setupView, 8943 state: state 8944 }; 8945 8946} 8947 8948function WebGLRenderState( extensions ) { 8949 8950 const lights = new WebGLLights( extensions ); 8951 8952 const lightsArray = []; 8953 const shadowsArray = []; 8954 const lightProbeGridArray = []; 8955 8956 function init( camera ) { 8957 8958 state.camera = camera; 8959 8960 lightsArray.length = 0; 8961 shadowsArray.length = 0; 8962 lightProbeGridArray.length = 0; 8963 8964 } 8965 8966 function pushLight( light ) { 8967 8968 lightsArray.push( light ); 8969 8970 } 8971 8972 function pushShadow( shadowLight ) { 8973 8974 shadowsArray.push( shadowLight ); 8975 8976 } 8977 8978 function pushLightProbeGrid( volume ) { 8979 8980 lightProbeGridArray.push( volume ); 8981 8982 } 8983 8984 function setupLights() { 8985 8986 lights.setup( lightsArray ); 8987 8988 } 8989 8990 function setupLightsView( camera ) { 8991 8992 lights.setupView( lightsArray, camera ); 8993 8994 } 8995 8996 const state = { 8997 lightsArray: lightsArray, 8998 shadowsArray: shadowsArray, 8999 lightProbeGridArray: lightProbeGridArray, 9000 9001 camera: null, 9002 9003 lights: lights, 9004 9005 transmissionRenderTarget: {}, 9006 textureUnits: 0 9007 }; 9008 9009 return { 9010 init: init, 9011 state: state, 9012 setupLights: setupLights, 9013 setupLightsView: setupLightsView, 9014 9015 pushLight: pushLight, 9016 pushShadow: pushShadow, 9017 pushLightProbeGrid: pushLightProbeGrid 9018 }; 9019 9020} 9021 9022function WebGLRenderStates( extensions ) { 9023 9024 let renderStates = new WeakMap(); 9025 9026 function get( scene, renderCallDepth = 0 ) { 9027 9028 const renderStateArray = renderStates.get( scene ); 9029 let renderState; 9030 9031 if ( renderStateArray === undefined ) { 9032 9033 renderState = new WebGLRenderState( extensions ); 9034 renderStates.set( scene, [ renderState ] ); 9035 9036 } else { 9037 9038 if ( renderCallDepth >= renderStateArray.length ) { 9039 9040 renderState = new WebGLRenderState( extensions ); 9041 renderStateArray.push( renderState ); 9042 9043 } else { 9044 9045 renderState = renderStateArray[ renderCallDepth ]; 9046 9047 } 9048 9049 } 9050 9051 return renderState; 9052 9053 } 9054 9055 function dispose() { 9056 9057 renderStates = new WeakMap(); 9058 9059 } 9060 9061 return { 9062 get: get, 9063 dispose: dispose 9064 }; 9065 9066} 9067 9068const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; 9069 9070const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\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 = texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ).rg;\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 = texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ).r;\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( max( 0.0, squared_mean - mean * mean ) );\n\tgl_FragColor = vec4( mean, std_dev, 0.0, 1.0 );\n}"; 9071 9072const _cubeDirections = [ 9073 /*@__PURE__*/ new Vector3( 1, 0, 0 ), /*@__PURE__*/ new Vector3( -1, 0, 0 ), /*@__PURE__*/ new Vector3( 0, 1, 0 ), 9074 /*@__PURE__*/ new Vector3( 0, -1, 0 ), /*@__PURE__*/ new Vector3( 0, 0, 1 ), /*@__PURE__*/ new Vector3( 0, 0, -1 ) 9075]; 9076 9077const _cubeUps = [ 9078 /*@__PURE__*/ new Vector3( 0, -1, 0 ), /*@__PURE__*/ new Vector3( 0, -1, 0 ), /*@__PURE__*/ new Vector3( 0, 0, 1 ), 9079 /*@__PURE__*/ new Vector3( 0, 0, -1 ), /*@__PURE__*/ new Vector3( 0, -1, 0 ), /*@__PURE__*/ new Vector3( 0, -1, 0 ) 9080]; 9081 9082const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); 9083const _lightPositionWorld = /*@__PURE__*/ new Vector3(); 9084const _lookTarget = /*@__PURE__*/ new Vector3(); 9085 9086function WebGLShadowMap( renderer, objects, capabilities ) { 9087 9088 let _frustum = new Frustum(); 9089 9090 const _shadowMapSize = new Vector2(), 9091 _viewportSize = new Vector2(), 9092 9093 _viewport = new Vector4(), 9094 9095 _depthMaterial = new MeshDepthMaterial(), 9096 _distanceMaterial = new MeshDistanceMaterial(), 9097 9098 _materialCache = {}, 9099 9100 _maxTextureSize = capabilities.maxTextureSize; 9101 9102 const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide }; 9103 9104 const shadowMaterialVertical = new ShaderMaterial( { 9105 defines: { 9106 VSM_SAMPLES: 8 9107 }, 9108 uniforms: { 9109 shadow_pass: { value: null }, 9110 resolution: { value: new Vector2() }, 9111 radius: { value: 4.0 } 9112 }, 9113 9114 vertexShader: vertex, 9115 fragmentShader: fragment 9116 9117 } ); 9118 9119 const shadowMaterialHorizontal = shadowMaterialVertical.clone(); 9120 shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1; 9121 9122 const fullScreenTri = new BufferGeometry(); 9123 fullScreenTri.setAttribute( 9124 'position', 9125 new BufferAttribute( 9126 new Float32Array( [ -1, -1, 0.5, 3, -1, 0.5, -1, 3, 0.5 ] ), 9127 3 9128 ) 9129 ); 9130 9131 const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical ); 9132 9133 const scope = this; 9134 9135 this.enabled = false; 9136 9137 this.autoUpdate = true; 9138 this.needsUpdate = false; 9139 9140 this.type = PCFShadowMap; 9141 let _previousType = this.type; 9142 9143 this.render = function ( lights, scene, camera ) { 9144 9145 if ( scope.enabled === false ) return; 9146 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; 9147 9148 if ( lights.length === 0 ) return; 9149 9150 if ( this.type === PCFSoftShadowMap ) { 9151 9152 warn( 'WebGLShadowMap: PCFSoftShadowMap has been removed. Using PCFShadowMap instead.' ); 9153 this.type = PCFShadowMap; 9154 9155 } 9156 9157 const currentRenderTarget = renderer.getRenderTarget(); 9158 const activeCubeFace = renderer.getActiveCubeFace(); 9159 const activeMipmapLevel = renderer.getActiveMipmapLevel(); 9160 9161 const _state = renderer.state; 9162 9163 // Set GL state for depth map. 9164 _state.setBlending( NoBlending ); 9165 9166 if ( _state.buffers.depth.getReversed() === true ) { 9167 9168 _state.buffers.color.setClear( 0, 0, 0, 0 ); 9169 9170 } else { 9171 9172 _state.buffers.color.setClear( 1, 1, 1, 1 ); 9173 9174 } 9175 9176 _state.buffers.depth.setTest( true ); 9177 _state.setScissorTest( false ); 9178 9179 // check for shadow map type changes 9180 9181 const typeChanged = _previousType !== this.type; 9182 9183 // When shadow map type changes, materials need recompilation because sampler types change 9184 // (sampler2DShadow for PCF vs sampler2D for Basic) 9185 if ( typeChanged ) { 9186 9187 scene.traverse( function ( object ) { 9188 9189 if ( object.material ) { 9190 9191 if ( Array.isArray( object.material ) ) { 9192 9193 object.material.forEach( mat => mat.needsUpdate = true ); 9194 9195 } else { 9196 9197 object.material.needsUpdate = true; 9198 9199 } 9200 9201 } 9202 9203 } ); 9204 9205 } 9206 9207 // render depth map 9208 9209 for ( let i = 0, il = lights.length; i < il; i ++ ) { 9210 9211 const light = lights[ i ]; 9212 const shadow = light.shadow; 9213 9214 if ( shadow === undefined ) { 9215 9216 warn( 'WebGLShadowMap:', light, 'has no shadow.' ); 9217 continue; 9218 9219 } 9220 9221 if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue; 9222 9223 _shadowMapSize.copy( shadow.mapSize ); 9224 9225 const shadowFrameExtents = shadow.getFrameExtents(); 9226 9227 _shadowMapSize.multiply( shadowFrameExtents ); 9228 9229 _viewportSize.copy( shadow.mapSize ); 9230 9231 if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) { 9232 9233 if ( _shadowMapSize.x > _maxTextureSize ) { 9234 9235 _viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x ); 9236 _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; 9237 shadow.mapSize.x = _viewportSize.x; 9238 9239 } 9240 9241 if ( _shadowMapSize.y > _maxTextureSize ) { 9242 9243 _viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y ); 9244 _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; 9245 shadow.mapSize.y = _viewportSize.y; 9246 9247 } 9248 9249 } 9250 9251 const reversedDepthBuffer = renderer.state.buffers.depth.getReversed(); 9252 shadow.camera._reversedDepth = reversedDepthBuffer; 9253 9254 if ( shadow.map === null || typeChanged === true ) { 9255 9256 if ( shadow.map !== null ) { 9257 9258 if ( shadow.map.depthTexture !== null ) { 9259 9260 shadow.map.depthTexture.dispose(); 9261 shadow.map.depthTexture = null; 9262 9263 } 9264 9265 shadow.map.dispose(); 9266 9267 } 9268 9269 if ( this.type === VSMShadowMap ) { 9270 9271 if ( light.isPointLight ) { 9272 9273 warn( 'WebGLShadowMap: VSM shadow maps are not supported for PointLights. Use PCF or BasicShadowMap instead.' ); 9274 continue; 9275 9276 } 9277 9278 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, { 9279 format: RGFormat, 9280 type: HalfFloatType, 9281 minFilter: LinearFilter, 9282 magFilter: LinearFilter, 9283 generateMipmaps: false 9284 } ); 9285 shadow.map.texture.name = light.name + '.shadowMap'; 9286 9287 // Native depth texture for VSM - depth is captured here, then blurred into the color texture 9288 shadow.map.depthTexture = new DepthTexture( _shadowMapSize.x, _shadowMapSize.y, FloatType ); 9289 shadow.map.depthTexture.name = light.name + '.shadowMapDepth'; 9290 shadow.map.depthTexture.format = DepthFormat; 9291 shadow.map.depthTexture.compareFunction = null; // For regular sampling (not shadow comparison) 9292 shadow.map.depthTexture.minFilter = NearestFilter; 9293 shadow.map.depthTexture.magFilter = NearestFilter; 9294 9295 } else { 9296 9297 if ( light.isPointLight ) { 9298 9299 shadow.map = new WebGLCubeRenderTarget( _shadowMapSize.x ); 9300 shadow.map.depthTexture = new CubeDepthTexture( _shadowMapSize.x, UnsignedIntType ); 9301 9302 } else { 9303 9304 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y ); 9305 shadow.map.depthTexture = new DepthTexture( _shadowMapSize.x, _shadowMapSize.y, UnsignedIntType ); 9306 9307 } 9308 9309 shadow.map.depthTexture.name = light.name + '.shadowMap'; 9310 shadow.map.depthTexture.format = DepthFormat; 9311 9312 if ( this.type === PCFShadowMap ) { 9313 9314 shadow.map.depthTexture.compareFunction = reversedDepthBuffer ? GreaterEqualCompare : LessEqualCompare; 9315 shadow.map.depthTexture.minFilter = LinearFilter; 9316 shadow.map.depthTexture.magFilter = LinearFilter; 9317 9318 } else { 9319 9320 shadow.map.depthTexture.compareFunction = null; 9321 shadow.map.depthTexture.minFilter = NearestFilter; 9322 shadow.map.depthTexture.magFilter = NearestFilter; 9323 9324 } 9325 9326 } 9327 9328 shadow.camera.updateProjectionMatrix(); 9329 9330 } 9331 9332 if ( shadow.map.isWebGLCubeRenderTarget !== true && ( shadow.map.width !== _shadowMapSize.x || shadow.map.height !== _shadowMapSize.y ) ) { 9333 9334 shadow.map.setSize( _shadowMapSize.x, _shadowMapSize.y ); 9335 9336 } 9337 9338 // For cube render targets (PointLights), render all 6 faces. Sun lights 9339 // render one atlas viewport per cascade. 9340 const faceCount = shadow.map.isWebGLCubeRenderTarget ? 6 : shadow.getViewportCount(); 9341 9342 if ( light.isPointLight !== true ) shadow.updateMatrices( light, camera ); 9343 9344 for ( let face = 0; face < faceCount; face ++ ) { 9345 9346 const shadowCamera = shadow.getCamera( face ); 9347 9348 if ( light.isPointLight ) { 9349 9350 const camera = shadow.camera; 9351 const shadowMatrix = shadow.matrix; 9352 9353 const far = light.distance || camera.far; 9354 9355 if ( far !== camera.far ) { 9356 9357 camera.far = far; 9358 camera.updateProjectionMatrix(); 9359 9360 } 9361 9362 _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); 9363 camera.position.copy( _lightPositionWorld ); 9364 9365 _lookTarget.copy( camera.position ); 9366 _lookTarget.add( _cubeDirections[ face ] ); 9367 camera.up.copy( _cubeUps[ face ] ); 9368 camera.lookAt( _lookTarget ); 9369 camera.updateMatrixWorld(); 9370 9371 shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); 9372 9373 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); 9374 shadow._frustum.setFromProjectionMatrix( _projScreenMatrix, camera.coordinateSystem, camera.reversedDepth ); 9375 9376 } 9377 9378 // For cube render targets, render to each face separately 9379 if ( shadow.map.isWebGLCubeRenderTarget ) { 9380 9381 renderer.setRenderTarget( shadow.map, face ); 9382 renderer.clear(); 9383 9384 } else { 9385 9386 // For 2D render targets, use viewports 9387 if ( face === 0 ) { 9388 9389 renderer.setRenderTarget( shadow.map ); 9390 renderer.clear(); 9391 9392 } 9393 9394 const viewport = shadow.getViewport( face ); 9395 9396 _viewport.set( 9397 _viewportSize.x * viewport.x, 9398 _viewportSize.y * viewport.y, 9399 _viewportSize.x * viewport.z, 9400 _viewportSize.y * viewport.w 9401 ); 9402 9403 _state.viewport( _viewport ); 9404 9405 } 9406 9407 _frustum = shadow.getFrustum( face ); 9408 9409 renderObject( scene, camera, shadowCamera, light, this.type ); 9410 9411 } 9412 9413 // do blur pass for VSM 9414 9415 if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) { 9416 9417 VSMPass( shadow, camera ); 9418 9419 } 9420 9421 shadow.needsUpdate = false; 9422 9423 } 9424 9425 _previousType = this.type; 9426 9427 scope.needsUpdate = false; 9428 9429 renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); 9430 9431 }; 9432 9433 function VSMPass( shadow, camera ) { 9434 9435 const geometry = objects.update( fullScreenMesh ); 9436 9437 if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) { 9438 9439 shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples; 9440 shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples; 9441 9442 shadowMaterialVertical.needsUpdate = true; 9443 shadowMaterialHorizontal.needsUpdate = true; 9444 9445 } 9446 9447 if ( shadow.mapPass === null ) { 9448 9449 shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, { 9450 format: RGFormat, 9451 type: HalfFloatType 9452 } ); 9453 9454 } else if ( shadow.mapPass.width !== shadow.map.width || shadow.mapPass.height !== shadow.map.height ) { 9455 9456 shadow.mapPass.setSize( shadow.map.width, shadow.map.height ); 9457 9458 } 9459 9460 // vertical pass - read from native depth texture 9461 9462 shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.depthTexture; 9463 shadowMaterialVertical.uniforms.resolution.value.set( shadow.map.width, shadow.map.height ); 9464 shadowMaterialVertical.uniforms.radius.value = shadow.radius; 9465 renderer.setRenderTarget( shadow.mapPass ); 9466 renderer.clear(); 9467 renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null ); 9468 9469 // horizontal pass 9470 9471 shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture; 9472 shadowMaterialHorizontal.uniforms.resolution.value.set( shadow.map.width, shadow.map.height ); 9473 shadowMaterialHorizontal.uniforms.radius.value = shadow.radius; 9474 renderer.setRenderTarget( shadow.map ); 9475 renderer.clear(); 9476 renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null ); 9477 9478 } 9479 9480 function getDepthMaterial( object, material, light, type ) { 9481 9482 let result = null; 9483 9484 const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial; 9485 9486 if ( customMaterial !== undefined ) { 9487 9488 result = customMaterial; 9489 9490 } else { 9491 9492 result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; 9493 9494 if ( ( renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || 9495 ( material.displacementMap && material.displacementScale !== 0 ) || 9496 ( material.alphaMap && material.alphaTest > 0 ) || 9497 ( material.map && material.alphaTest > 0 ) || 9498 ( material.alphaToCoverage === true ) ) { 9499 9500 // in this case we need a unique material instance reflecting the 9501 // appropriate state 9502 9503 const keyA = result.uuid, keyB = material.uuid; 9504 9505 let materialsForVariant = _materialCache[ keyA ]; 9506 9507 if ( materialsForVariant === undefined ) { 9508 9509 materialsForVariant = {}; 9510 _materialCache[ keyA ] = materialsForVariant; 9511 9512 } 9513 9514 let cachedMaterial = materialsForVariant[ keyB ]; 9515 9516 if ( cachedMaterial === undefined ) { 9517 9518 cachedMaterial = result.clone(); 9519 materialsForVariant[ keyB ] = cachedMaterial; 9520 material.addEventListener( 'dispose', onMaterialDispose ); 9521 9522 } 9523 9524 result = cachedMaterial; 9525 9526 } 9527 9528 } 9529 9530 result.visible = material.visible; 9531 result.wireframe = material.wireframe; 9532 9533 if ( type === VSMShadowMap ) { 9534 9535 result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side; 9536 9537 } else { 9538 9539 result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ]; 9540 9541 } 9542 9543 result.alphaMap = material.alphaMap; 9544 result.alphaTest = ( material.alphaToCoverage === true ) ? 0.5 : material.alphaTest; // approximate alphaToCoverage by using a fixed alphaTest value 9545 result.map = material.map; 9546 9547 result.clipShadows = material.clipShadows; 9548 result.clippingPlanes = material.clippingPlanes; 9549 result.clipIntersection = material.clipIntersection; 9550 9551 result.displacementMap = material.displacementMap; 9552 result.displacementScale = material.displacementScale; 9553 result.displacementBias = material.displacementBias; 9554 9555 result.wireframeLinewidth = material.wireframeLinewidth; 9556 result.linewidth = material.linewidth; 9557 9558 if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { 9559 9560 const materialProperties = renderer.properties.get( result ); 9561 materialProperties.light = light; 9562 9563 } 9564 9565 return result; 9566 9567 } 9568 9569 function renderObject( object, camera, shadowCamera, light, type ) { 9570 9571 if ( object.visible === false ) return; 9572 9573 const visible = object.layers.test( camera.layers ); 9574 9575 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { 9576 9577 if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || object.intersectsFrustum( _frustum ) ) ) { 9578 9579 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); 9580 9581 const geometry = objects.update( object ); 9582 const material = object.material; 9583 9584 if ( Array.isArray( material ) ) { 9585 9586 const groups = geometry.groups; 9587 9588 for ( let k = 0, kl = groups.length; k < kl; k ++ ) { 9589 9590 const group = groups[ k ]; 9591 const groupMaterial = material[ group.materialIndex ]; 9592 9593 if ( groupMaterial && groupMaterial.visible ) { 9594 9595 const depthMaterial = getDepthMaterial( object, groupMaterial, light, type ); 9596 9597 object.onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); 9598 9599 renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); 9600 9601 object.onAfterShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); 9602 9603 } 9604 9605 } 9606 9607 } else if ( material.visible ) { 9608 9609 const depthMaterial = getDepthMaterial( object, material, light, type ); 9610 9611 object.onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); 9612 9613 renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); 9614 9615 object.onAfterShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); 9616 9617 } 9618 9619 } 9620 9621 } 9622 9623 const children = object.children; 9624 9625 for ( let i = 0, l = children.length; i < l; i ++ ) { 9626 9627 renderObject( children[ i ], camera, shadowCamera, light, type ); 9628 9629 } 9630 9631 } 9632 9633 function onMaterialDispose( event ) { 9634 9635 const material = event.target; 9636 9637 material.removeEventListener( 'dispose', onMaterialDispose ); 9638 9639 // make sure to remove the unique distance/depth materials used for shadow map rendering 9640 9641 for ( const id in _materialCache ) { 9642 9643 const cache = _materialCache[ id ]; 9644 9645 const uuid = event.target.uuid; 9646 9647 if ( uuid in cache ) { 9648 9649 const shadowMaterial = cache[ uuid ]; 9650 shadowMaterial.dispose(); 9651 delete cache[ uuid ]; 9652 9653 } 9654 9655 } 9656 9657 } 9658 9659} 9660 9661function WebGLState( gl, extensions ) { 9662 9663 function ColorBuffer() { 9664 9665 let locked = false; 9666 9667 const color = new Vector4(); 9668 let currentColorMask = null; 9669 const currentColorClear = new Vector4( 0, 0, 0, 0 ); 9670 9671 return { 9672 9673 setMask: function ( colorMask ) { 9674 9675 if ( currentColorMask !== colorMask && ! locked ) { 9676 9677 gl.colorMask( colorMask, colorMask, colorMask, colorMask ); 9678 currentColorMask = colorMask; 9679 9680 } 9681 9682 }, 9683 9684 setLocked: function ( lock ) { 9685 9686 locked = lock; 9687 9688 }, 9689 9690 setClear: function ( r, g, b, a, premultipliedAlpha ) { 9691 9692 if ( premultipliedAlpha === true ) { 9693 9694 r *= a; g *= a; b *= a; 9695 9696 } 9697 9698 color.set( r, g, b, a ); 9699 9700 if ( currentColorClear.equals( color ) === false ) { 9701 9702 gl.clearColor( r, g, b, a ); 9703 currentColorClear.copy( color ); 9704 9705 } 9706 9707 }, 9708 9709 reset: function () { 9710 9711 locked = false; 9712 9713 currentColorMask = null; 9714 currentColorClear.set( -1, 0, 0, 0 ); // set to invalid state 9715 9716 } 9717 9718 }; 9719 9720 } 9721 9722 function DepthBuffer() { 9723 9724 let locked = false; 9725 9726 let currentReversed = false; 9727 let currentDepthMask = null; 9728 let currentDepthFunc = null; 9729 let currentDepthClear = null; 9730 9731 return { 9732 9733 setReversed: function ( reversed ) { 9734 9735 if ( currentReversed !== reversed ) { 9736 9737 const ext = extensions.get( 'EXT_clip_control' ); 9738 9739 if ( reversed ) { 9740 9741 ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT ); 9742 9743 } else { 9744 9745 ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT ); 9746 9747 } 9748 9749 currentReversed = reversed; 9750 9751 const oldDepth = currentDepthClear; 9752 currentDepthClear = null; 9753 this.setClear( oldDepth ); 9754 9755 } 9756 9757 }, 9758 9759 getReversed: function () { 9760 9761 return currentReversed; 9762 9763 }, 9764 9765 setTest: function ( depthTest ) { 9766 9767 if ( depthTest ) { 9768 9769 enable( gl.DEPTH_TEST ); 9770 9771 } else { 9772 9773 disable( gl.DEPTH_TEST ); 9774 9775 } 9776 9777 }, 9778 9779 setMask: function ( depthMask ) { 9780 9781 if ( currentDepthMask !== depthMask && ! locked ) { 9782 9783 gl.depthMask( depthMask ); 9784 currentDepthMask = depthMask; 9785 9786 } 9787 9788 }, 9789 9790 setFunc: function ( depthFunc ) { 9791 9792 if ( currentReversed ) depthFunc = ReversedDepthFuncs[ depthFunc ]; 9793 9794 if ( currentDepthFunc !== depthFunc ) { 9795 9796 switch ( depthFunc ) { 9797 9798 case NeverDepth: 9799 9800 gl.depthFunc( gl.NEVER ); 9801 break; 9802 9803 case AlwaysDepth: 9804 9805 gl.depthFunc( gl.ALWAYS ); 9806 break; 9807 9808 case LessDepth: 9809 9810 gl.depthFunc( gl.LESS ); 9811 break; 9812 9813 case LessEqualDepth: 9814 9815 gl.depthFunc( gl.LEQUAL ); 9816 break; 9817 9818 case EqualDepth: 9819 9820 gl.depthFunc( gl.EQUAL ); 9821 break; 9822 9823 case GreaterEqualDepth: 9824 9825 gl.depthFunc( gl.GEQUAL ); 9826 break; 9827 9828 case GreaterDepth: 9829 9830 gl.depthFunc( gl.GREATER ); 9831 break; 9832 9833 case NotEqualDepth: 9834 9835 gl.depthFunc( gl.NOTEQUAL ); 9836 break; 9837 9838 default: 9839 9840 gl.depthFunc( gl.LEQUAL ); 9841 9842 } 9843 9844 currentDepthFunc = depthFunc; 9845 9846 } 9847 9848 }, 9849 9850 setLocked: function ( lock ) { 9851 9852 locked = lock; 9853 9854 }, 9855 9856 setClear: function ( depth ) { 9857 9858 if ( currentDepthClear !== depth ) { 9859 9860 currentDepthClear = depth; 9861 9862 if ( currentReversed ) { 9863 9864 depth = 1 - depth; 9865 9866 } 9867 9868 gl.clearDepth( depth ); 9869 9870 } 9871 9872 }, 9873 9874 reset: function () { 9875 9876 locked = false; 9877 9878 currentDepthMask = null; 9879 currentDepthFunc = null; 9880 currentDepthClear = null; 9881 currentReversed = false; 9882 9883 } 9884 9885 }; 9886 9887 } 9888 9889 function StencilBuffer() { 9890 9891 let locked = false; 9892 9893 let currentStencilMask = null; 9894 let currentStencilFunc = null; 9895 let currentStencilRef = null; 9896 let currentStencilFuncMask = null; 9897 let currentStencilFail = null; 9898 let currentStencilZFail = null; 9899 let currentStencilZPass = null; 9900 let currentStencilClear = null; 9901 9902 return { 9903 9904 setTest: function ( stencilTest ) { 9905 9906 if ( ! locked ) { 9907 9908 if ( stencilTest ) { 9909 9910 enable( gl.STENCIL_TEST ); 9911 9912 } else { 9913 9914 disable( gl.STENCIL_TEST ); 9915 9916 } 9917 9918 } 9919 9920 }, 9921 9922 setMask: function ( stencilMask ) { 9923 9924 if ( currentStencilMask !== stencilMask && ! locked ) { 9925 9926 gl.stencilMask( stencilMask ); 9927 currentStencilMask = stencilMask; 9928 9929 } 9930 9931 }, 9932 9933 setFunc: function ( stencilFunc, stencilRef, stencilMask ) { 9934 9935 if ( currentStencilFunc !== stencilFunc || 9936 currentStencilRef !== stencilRef || 9937 currentStencilFuncMask !== stencilMask ) { 9938 9939 gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); 9940 9941 currentStencilFunc = stencilFunc; 9942 currentStencilRef = stencilRef; 9943 currentStencilFuncMask = stencilMask; 9944 9945 } 9946 9947 }, 9948 9949 setOp: function ( stencilFail, stencilZFail, stencilZPass ) { 9950 9951 if ( currentStencilFail !== stencilFail || 9952 currentStencilZFail !== stencilZFail || 9953 currentStencilZPass !== stencilZPass ) { 9954 9955 gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); 9956 9957 currentStencilFail = stencilFail; 9958 currentStencilZFail = stencilZFail; 9959 currentStencilZPass = stencilZPass; 9960 9961 } 9962 9963 }, 9964 9965 setLocked: function ( lock ) { 9966 9967 locked = lock; 9968 9969 }, 9970 9971 setClear: function ( stencil ) { 9972 9973 if ( currentStencilClear !== stencil ) { 9974 9975 gl.clearStencil( stencil ); 9976 currentStencilClear = stencil; 9977 9978 } 9979 9980 }, 9981 9982 reset: function () { 9983 9984 locked = false; 9985 9986 currentStencilMask = null; 9987 currentStencilFunc = null; 9988 currentStencilRef = null; 9989 currentStencilFuncMask = null; 9990 currentStencilFail = null; 9991 currentStencilZFail = null; 9992 currentStencilZPass = null; 9993 currentStencilClear = null; 9994 9995 } 9996 9997 }; 9998 9999 } 10000 10001 // 10002 10003 const colorBuffer = new ColorBuffer(); 10004 const depthBuffer = new DepthBuffer(); 10005 const stencilBuffer = new StencilBuffer(); 10006 10007 const uboBindings = new WeakMap(); 10008 const uboProgramMap = new WeakMap(); 10009 10010 let enabledCapabilities = {}; 10011 let parameters = {}; 10012 10013 let currentBoundFramebuffers = {}; 10014 let currentDrawbuffers = new WeakMap(); 10015 let defaultDrawbuffers = []; 10016 10017 let currentProgram = null; 10018 10019 let currentBlendingEnabled = false; 10020 let currentBlending = null; 10021 let currentBlendEquation = null; 10022 let currentBlendSrc = null; 10023 let currentBlendDst = null; 10024 let currentBlendEquationAlpha = null; 10025 let currentBlendSrcAlpha = null; 10026 let currentBlendDstAlpha = null; 10027 let currentBlendColor = new Color( 0, 0, 0 ); 10028 let currentBlendAlpha = 0; 10029 let currentPremultipledAlpha = false; 10030 10031 let currentFlipSided = null; 10032 let currentCullFace = null; 10033 10034 let currentLineWidth = null; 10035 10036 let currentPolygonOffsetFactor = null; 10037 let currentPolygonOffsetUnits = null; 10038 10039 const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); 10040 10041 let lineWidthAvailable = false; 10042 let version = 0; 10043 const glVersion = gl.getParameter( gl.VERSION ); 10044 10045 if ( glVersion.indexOf( 'WebGL' ) !== -1 ) { 10046 10047 version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] ); 10048 lineWidthAvailable = ( version >= 1.0 ); 10049 10050 } else if ( glVersion.indexOf( 'OpenGL ES' ) !== -1 ) { 10051 10052 version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] ); 10053 lineWidthAvailable = ( version >= 2.0 ); 10054 10055 } 10056 10057 let currentTextureSlot = null; 10058 let currentBoundTextures = {}; 10059 10060 const scissorParam = gl.getParameter( gl.SCISSOR_BOX ); 10061 const viewportParam = gl.getParameter( gl.VIEWPORT ); 10062 10063 const currentScissor = new Vector4().fromArray( scissorParam ); 10064 const currentViewport = new Vector4().fromArray( viewportParam ); 10065 10066 function createTexture( type, target, count, dimensions ) { 10067 10068 const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. 10069 const texture = gl.createTexture(); 10070 10071 gl.bindTexture( type, texture ); 10072 gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); 10073 gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); 10074 10075 for ( let i = 0; i < count; i ++ ) { 10076 10077 if ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) { 10078 10079 gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); 10080 10081 } else { 10082 10083 gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); 10084 10085 } 10086 10087 } 10088 10089 return texture; 10090 10091 } 10092 10093 const emptyTextures = {}; 10094 emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); 10095 emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); 10096 emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 ); 10097 emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 ); 10098 10099 // init 10100 10101 colorBuffer.setClear( 0, 0, 0, 1 ); 10102 depthBuffer.setClear( 1 ); 10103 stencilBuffer.setClear( 0 ); 10104 10105 enable( gl.DEPTH_TEST ); 10106 depthBuffer.setFunc( LessEqualDepth ); 10107 10108 setFlipSided( false ); 10109 setCullFace( CullFaceBack ); 10110 enable( gl.CULL_FACE ); 10111 10112 setBlending( NoBlending ); 10113 10114 // 10115 10116 function enable( id ) { 10117 10118 if ( enabledCapabilities[ id ] !== true ) { 10119 10120 gl.enable( id ); 10121 enabledCapabilities[ id ] = true; 10122 10123 } 10124 10125 } 10126 10127 function disable( id ) { 10128 10129 if ( enabledCapabilities[ id ] !== false ) { 10130 10131 gl.disable( id ); 10132 enabledCapabilities[ id ] = false; 10133 10134 } 10135 10136 } 10137 10138 function bindFramebuffer( target, framebuffer ) { 10139 10140 if ( currentBoundFramebuffers[ target ] !== framebuffer ) { 10141 10142 gl.bindFramebuffer( target, framebuffer ); 10143 10144 currentBoundFramebuffers[ target ] = framebuffer; 10145 10146 // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER 10147 10148 if ( target === gl.DRAW_FRAMEBUFFER ) { 10149 10150 currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer; 10151 10152 } 10153 10154 if ( target === gl.FRAMEBUFFER ) { 10155 10156 currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer; 10157 10158 } 10159 10160 return true; 10161 10162 } 10163 10164 return false; 10165 10166 } 10167 10168 function drawBuffers( renderTarget, framebuffer ) { 10169 10170 let drawBuffers = defaultDrawbuffers; 10171 10172 let needsUpdate = false; 10173 10174 if ( renderTarget ) { 10175 10176 drawBuffers = currentDrawbuffers.get( framebuffer ); 10177 10178 if ( drawBuffers === undefined ) { 10179 10180 drawBuffers = []; 10181 currentDrawbuffers.set( framebuffer, drawBuffers ); 10182 10183 } 10184 10185 const textures = renderTarget.textures; 10186 10187 if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { 10188 10189 for ( let i = 0, il = textures.length; i < il; i ++ ) { 10190 10191 drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i; 10192 10193 } 10194 10195 drawBuffers.length = textures.length; 10196 10197 needsUpdate = true; 10198 10199 } 10200 10201 } else { 10202 10203 if ( drawBuffers[ 0 ] !== gl.BACK ) { 10204 10205 drawBuffers[ 0 ] = gl.BACK; 10206 10207 needsUpdate = true; 10208 10209 } 10210 10211 } 10212 10213 if ( needsUpdate ) { 10214 10215 gl.drawBuffers( drawBuffers ); 10216 10217 } 10218 10219 } 10220 10221 function useProgram( program ) { 10222 10223 if ( currentProgram !== program ) { 10224 10225 gl.useProgram( program ); 10226 10227 currentProgram = program; 10228 10229 return true; 10230 10231 } 10232 10233 return false; 10234 10235 } 10236 10237 const equationToGL = { 10238 [ AddEquation ]: gl.FUNC_ADD, 10239 [ SubtractEquation ]: gl.FUNC_SUBTRACT, 10240 [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT 10241 }; 10242 10243 equationToGL[ MinEquation ] = gl.MIN; 10244 equationToGL[ MaxEquation ] = gl.MAX; 10245 10246 const factorToGL = { 10247 [ ZeroFactor ]: gl.ZERO, 10248 [ OneFactor ]: gl.ONE, 10249 [ SrcColorFactor ]: gl.SRC_COLOR, 10250 [ SrcAlphaFactor ]: gl.SRC_ALPHA, 10251 [ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE, 10252 [ DstColorFactor ]: gl.DST_COLOR, 10253 [ DstAlphaFactor ]: gl.DST_ALPHA, 10254 [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR, 10255 [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA, 10256 [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR, 10257 [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA, 10258 [ ConstantColorFactor ]: gl.CONSTANT_COLOR, 10259 [ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR, 10260 [ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA, 10261 [ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA 10262 }; 10263 10264 function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) { 10265 10266 if ( blending === NoBlending ) { 10267 10268 if ( currentBlendingEnabled === true ) { 10269 10270 disable( gl.BLEND ); 10271 currentBlendingEnabled = false; 10272 10273 } 10274 10275 return; 10276 10277 } 10278 10279 if ( currentBlendingEnabled === false ) { 10280 10281 enable( gl.BLEND ); 10282 currentBlendingEnabled = true; 10283 10284 } 10285 10286 if ( blending !== CustomBlending ) { 10287 10288 if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { 10289 10290 if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { 10291 10292 gl.blendEquation( gl.FUNC_ADD ); 10293 10294 currentBlendEquation = AddEquation; 10295 currentBlendEquationAlpha = AddEquation; 10296 10297 } 10298 10299 if ( premultipliedAlpha ) { 10300 10301 switch ( blending ) { 10302 10303 case NormalBlending: 10304 gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); 10305 break; 10306 10307 case AdditiveBlending: 10308 gl.blendFunc( gl.ONE, gl.ONE ); 10309 break; 10310 10311 case SubtractiveBlending: 10312 gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); 10313 break; 10314 10315 case MultiplyBlending: 10316 gl.blendFuncSeparate( gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE ); 10317 break; 10318 10319 default: 10320 error( 'WebGLState: Invalid blending: ', blending ); 10321 break; 10322 10323 } 10324 10325 } else { 10326 10327 switch ( blending ) { 10328 10329 case NormalBlending: 10330 gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); 10331 break; 10332 10333 case AdditiveBlending: 10334 gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE, gl.ONE, gl.ONE ); 10335 break; 10336 10337 case SubtractiveBlending: 10338 error( 'WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true' ); 10339 break; 10340 10341 case MultiplyBlending: 10342 error( 'WebGLState: MultiplyBlending requires material.premultipliedAlpha = true' ); 10343 break; 10344 10345 default: 10346 error( 'WebGLState: Invalid blending: ', blending ); 10347 break; 10348 10349 } 10350 10351 } 10352 10353 currentBlendSrc = null; 10354 currentBlendDst = null; 10355 currentBlendSrcAlpha = null; 10356 currentBlendDstAlpha = null; 10357 currentBlendColor.set( 0, 0, 0 ); 10358 currentBlendAlpha = 0; 10359 10360 currentBlending = blending; 10361 currentPremultipledAlpha = premultipliedAlpha; 10362 10363 } 10364 10365 return; 10366 10367 } 10368 10369 // custom blending 10370 10371 blendEquationAlpha = blendEquationAlpha || blendEquation; 10372 blendSrcAlpha = blendSrcAlpha || blendSrc; 10373 blendDstAlpha = blendDstAlpha || blendDst; 10374 10375 if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { 10376 10377 gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] ); 10378 10379 currentBlendEquation = blendEquation; 10380 currentBlendEquationAlpha = blendEquationAlpha; 10381 10382 } 10383 10384 if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { 10385 10386 gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] ); 10387 10388 currentBlendSrc = blendSrc; 10389 currentBlendDst = blendDst; 10390 currentBlendSrcAlpha = blendSrcAlpha; 10391 currentBlendDstAlpha = blendDstAlpha; 10392 10393 } 10394 10395 if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) { 10396 10397 gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha ); 10398 10399 currentBlendColor.copy( blendColor ); 10400 currentBlendAlpha = blendAlpha; 10401 10402 } 10403 10404 currentBlending = blending; 10405 currentPremultipledAlpha = false; 10406 10407 } 10408 10409 function setMaterial( material, frontFaceCW ) { 10410 10411 material.side === DoubleSide 10412 ? disable( gl.CULL_FACE ) 10413 : enable( gl.CULL_FACE ); 10414 10415 let flipSided = ( material.side === BackSide ); 10416 if ( frontFaceCW ) flipSided = ! flipSided; 10417 10418 setFlipSided( flipSided ); 10419 10420 ( material.blending === NormalBlending && material.transparent === false ) 10421 ? setBlending( NoBlending ) 10422 : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha ); 10423 10424 depthBuffer.setFunc( material.depthFunc ); 10425 depthBuffer.setTest( material.depthTest ); 10426 depthBuffer.setMask( material.depthWrite ); 10427 colorBuffer.setMask( material.colorWrite ); 10428 10429 const stencilWrite = material.stencilWrite; 10430 stencilBuffer.setTest( stencilWrite ); 10431 if ( stencilWrite ) { 10432 10433 stencilBuffer.setMask( material.stencilWriteMask ); 10434 stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); 10435 stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); 10436 10437 } 10438 10439 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); 10440 10441 material.alphaToCoverage === true 10442 ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) 10443 : disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); 10444 10445 } 10446 10447 // 10448 10449 function setFlipSided( flipSided ) { 10450 10451 if ( currentFlipSided !== flipSided ) { 10452 10453 if ( flipSided ) { 10454 10455 gl.frontFace( gl.CW ); 10456 10457 } else { 10458 10459 gl.frontFace( gl.CCW ); 10460 10461 } 10462 10463 currentFlipSided = flipSided; 10464 10465 } 10466 10467 } 10468 10469 function setCullFace( cullFace ) { 10470 10471 if ( cullFace !== CullFaceNone ) { 10472 10473 enable( gl.CULL_FACE ); 10474 10475 if ( cullFace !== currentCullFace ) { 10476 10477 if ( cullFace === CullFaceBack ) { 10478 10479 gl.cullFace( gl.BACK ); 10480 10481 } else if ( cullFace === CullFaceFront ) { 10482 10483 gl.cullFace( gl.FRONT ); 10484 10485 } else { 10486 10487 gl.cullFace( gl.FRONT_AND_BACK ); 10488 10489 } 10490 10491 } 10492 10493 } else { 10494 10495 disable( gl.CULL_FACE ); 10496 10497 } 10498 10499 currentCullFace = cullFace; 10500 10501 } 10502 10503 function setLineWidth( width ) { 10504 10505 if ( width !== currentLineWidth ) { 10506 10507 if ( lineWidthAvailable ) gl.lineWidth( width ); 10508 10509 currentLineWidth = width; 10510 10511 } 10512 10513 } 10514 10515 function setPolygonOffset( polygonOffset, factor, units ) { 10516 10517 if ( polygonOffset ) { 10518 10519 enable( gl.POLYGON_OFFSET_FILL ); 10520 10521 if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { 10522 10523 currentPolygonOffsetFactor = factor; 10524 currentPolygonOffsetUnits = units; 10525 10526 if ( depthBuffer.getReversed() ) { 10527 10528 factor = - factor; 10529 10530 } 10531 10532 gl.polygonOffset( factor, units ); 10533 10534 } 10535 10536 } else { 10537 10538 disable( gl.POLYGON_OFFSET_FILL ); 10539 10540 } 10541 10542 } 10543 10544 function setScissorTest( scissorTest ) { 10545 10546 if ( scissorTest ) { 10547 10548 enable( gl.SCISSOR_TEST ); 10549 10550 } else { 10551 10552 disable( gl.SCISSOR_TEST ); 10553 10554 } 10555 10556 } 10557 10558 // texture 10559 10560 function activeTexture( webglSlot ) { 10561 10562 if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; 10563 10564 if ( currentTextureSlot !== webglSlot ) { 10565 10566 gl.activeTexture( webglSlot ); 10567 currentTextureSlot = webglSlot; 10568 10569 } 10570 10571 } 10572 10573 function bindTexture( webglType, webglTexture, webglSlot ) { 10574 10575 if ( webglSlot === undefined ) { 10576 10577 if ( currentTextureSlot === null ) { 10578 10579 webglSlot = gl.TEXTURE0 + maxTextures - 1; 10580 10581 } else { 10582 10583 webglSlot = currentTextureSlot; 10584 10585 } 10586 10587 } 10588 10589 let boundTexture = currentBoundTextures[ webglSlot ]; 10590 10591 if ( boundTexture === undefined ) { 10592 10593 boundTexture = { type: undefined, texture: undefined }; 10594 currentBoundTextures[ webglSlot ] = boundTexture; 10595 10596 } 10597 10598 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { 10599 10600 if ( currentTextureSlot !== webglSlot ) { 10601 10602 gl.activeTexture( webglSlot ); 10603 currentTextureSlot = webglSlot; 10604 10605 } 10606 10607 gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); 10608 10609 boundTexture.type = webglType; 10610 boundTexture.texture = webglTexture; 10611 10612 } 10613 10614 } 10615 10616 function unbindTexture() { 10617 10618 const boundTexture = currentBoundTextures[ currentTextureSlot ]; 10619 10620 if ( boundTexture !== undefined && boundTexture.type !== undefined ) { 10621 10622 gl.bindTexture( boundTexture.type, null ); 10623 10624 boundTexture.type = undefined; 10625 boundTexture.texture = undefined; 10626 10627 } 10628 10629 } 10630 10631 function compressedTexImage2D() { 10632 10633 try { 10634 10635 gl.compressedTexImage2D( ...arguments ); 10636 10637 } catch ( e ) { 10638 10639 error( 'WebGLState:', e ); 10640 10641 } 10642 10643 } 10644 10645 function compressedTexImage3D() { 10646 10647 try { 10648 10649 gl.compressedTexImage3D( ...arguments ); 10650 10651 } catch ( e ) { 10652 10653 error( 'WebGLState:', e ); 10654 10655 } 10656 10657 } 10658 10659 function texSubImage2D() { 10660 10661 try { 10662 10663 gl.texSubImage2D( ...arguments ); 10664 10665 } catch ( e ) { 10666 10667 error( 'WebGLState:', e ); 10668 10669 } 10670 10671 } 10672 10673 function texSubImage3D() { 10674 10675 try { 10676 10677 gl.texSubImage3D( ...arguments ); 10678 10679 } catch ( e ) { 10680 10681 error( 'WebGLState:', e ); 10682 10683 } 10684 10685 } 10686 10687 function compressedTexSubImage2D() { 10688 10689 try { 10690 10691 gl.compressedTexSubImage2D( ...arguments ); 10692 10693 } catch ( e ) { 10694 10695 error( 'WebGLState:', e ); 10696 10697 } 10698 10699 } 10700 10701 function compressedTexSubImage3D() { 10702 10703 try { 10704 10705 gl.compressedTexSubImage3D( ...arguments ); 10706 10707 } catch ( e ) { 10708 10709 error( 'WebGLState:', e ); 10710 10711 } 10712 10713 } 10714 10715 function texStorage2D() { 10716 10717 try { 10718 10719 gl.texStorage2D( ...arguments ); 10720 10721 } catch ( e ) { 10722 10723 error( 'WebGLState:', e ); 10724 10725 } 10726 10727 } 10728 10729 function texStorage3D() { 10730 10731 try { 10732 10733 gl.texStorage3D( ...arguments ); 10734 10735 } catch ( e ) { 10736 10737 error( 'WebGLState:', e ); 10738 10739 } 10740 10741 } 10742 10743 function texImage2D() { 10744 10745 try { 10746 10747 gl.texImage2D( ...arguments ); 10748 10749 } catch ( e ) { 10750 10751 error( 'WebGLState:', e ); 10752 10753 } 10754 10755 } 10756 10757 function texImage3D() { 10758 10759 try { 10760 10761 gl.texImage3D( ...arguments ); 10762 10763 } catch ( e ) { 10764 10765 error( 'WebGLState:', e ); 10766 10767 } 10768 10769 } 10770 10771 function getParameter( name ) { 10772 10773 if ( parameters[ name ] !== undefined ) { 10774 10775 return parameters[ name ]; 10776 10777 } else { 10778 10779 return gl.getParameter( name ); 10780 10781 } 10782 10783 } 10784 10785 function pixelStorei( name, value ) { 10786 10787 if ( parameters[ name ] !== value ) { 10788 10789 gl.pixelStorei( name, value ); 10790 parameters[ name ] = value; 10791 10792 } 10793 10794 } 10795 10796 // 10797 10798 function scissor( scissor ) { 10799 10800 if ( currentScissor.equals( scissor ) === false ) { 10801 10802 gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); 10803 currentScissor.copy( scissor ); 10804 10805 } 10806 10807 } 10808 10809 function viewport( viewport ) { 10810 10811 if ( currentViewport.equals( viewport ) === false ) { 10812 10813 gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); 10814 currentViewport.copy( viewport ); 10815 10816 } 10817 10818 } 10819 10820 function updateUBOMapping( uniformsGroup, program ) { 10821 10822 let mapping = uboProgramMap.get( program ); 10823 10824 if ( mapping === undefined ) { 10825 10826 mapping = new WeakMap(); 10827 10828 uboProgramMap.set( program, mapping ); 10829 10830 } 10831 10832 let blockIndex = mapping.get( uniformsGroup ); 10833 10834 if ( blockIndex === undefined ) { 10835 10836 blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name ); 10837 10838 mapping.set( uniformsGroup, blockIndex ); 10839 10840 } 10841 10842 } 10843 10844 function uniformBlockBinding( uniformsGroup, program ) { 10845 10846 const mapping = uboProgramMap.get( program ); 10847 const blockIndex = mapping.get( uniformsGroup ); 10848 10849 if ( uboBindings.get( program ) !== blockIndex ) { 10850 10851 // bind shader specific block index to global block point 10852 gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex ); 10853 10854 uboBindings.set( program, blockIndex ); 10855 10856 } 10857 10858 } 10859 10860 // 10861 10862 function reset() { 10863 10864 // reset state 10865 10866 gl.disable( gl.BLEND ); 10867 gl.disable( gl.CULL_FACE ); 10868 gl.disable( gl.DEPTH_TEST ); 10869 gl.disable( gl.POLYGON_OFFSET_FILL ); 10870 gl.disable( gl.SCISSOR_TEST ); 10871 gl.disable( gl.STENCIL_TEST ); 10872 gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); 10873 10874 gl.blendEquation( gl.FUNC_ADD ); 10875 gl.blendFunc( gl.ONE, gl.ZERO ); 10876 gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO ); 10877 gl.blendColor( 0, 0, 0, 0 ); 10878 10879 gl.colorMask( true, true, true, true ); 10880 gl.clearColor( 0, 0, 0, 0 ); 10881 10882 gl.depthMask( true ); 10883 gl.depthFunc( gl.LESS ); 10884 10885 depthBuffer.setReversed( false ); 10886 10887 gl.clearDepth( 1 ); 10888 10889 gl.stencilMask( 0xffffffff ); 10890 gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff ); 10891 gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP ); 10892 gl.clearStencil( 0 ); 10893 10894 gl.cullFace( gl.BACK ); 10895 gl.frontFace( gl.CCW ); 10896 10897 gl.polygonOffset( 0, 0 ); 10898 10899 gl.activeTexture( gl.TEXTURE0 ); 10900 10901 gl.bindFramebuffer( gl.FRAMEBUFFER, null ); 10902 gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); 10903 gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); 10904 10905 gl.useProgram( null ); 10906 10907 gl.lineWidth( 1 ); 10908 10909 gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height ); 10910 gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height ); 10911 10912 gl.pixelStorei( gl.PACK_ALIGNMENT, 4 ); 10913 gl.pixelStorei( gl.UNPACK_ALIGNMENT, 4 ); 10914 gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, false ); 10915 gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false ); 10916 gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL ); 10917 gl.pixelStorei( gl.PACK_ROW_LENGTH, 0 ); 10918 gl.pixelStorei( gl.PACK_SKIP_PIXELS, 0 ); 10919 gl.pixelStorei( gl.PACK_SKIP_ROWS, 0 ); 10920 gl.pixelStorei( gl.UNPACK_ROW_LENGTH, 0 ); 10921 gl.pixelStorei( gl.UNPACK_IMAGE_HEIGHT, 0 ); 10922 gl.pixelStorei( gl.UNPACK_SKIP_PIXELS, 0 ); 10923 gl.pixelStorei( gl.UNPACK_SKIP_ROWS, 0 ); 10924 gl.pixelStorei( gl.UNPACK_SKIP_IMAGES, 0 ); 10925 10926 // reset internals 10927 10928 enabledCapabilities = {}; 10929 parameters = {}; 10930 10931 currentTextureSlot = null; 10932 currentBoundTextures = {}; 10933 10934 currentBoundFramebuffers = {}; 10935 currentDrawbuffers = new WeakMap(); 10936 defaultDrawbuffers = []; 10937 10938 currentProgram = null; 10939 10940 currentBlendingEnabled = false; 10941 currentBlending = null; 10942 currentBlendEquation = null; 10943 currentBlendSrc = null; 10944 currentBlendDst = null; 10945 currentBlendEquationAlpha = null; 10946 currentBlendSrcAlpha = null; 10947 currentBlendDstAlpha = null; 10948 currentBlendColor = new Color( 0, 0, 0 ); 10949 currentBlendAlpha = 0; 10950 currentPremultipledAlpha = false; 10951 10952 currentFlipSided = null; 10953 currentCullFace = null; 10954 10955 currentLineWidth = null; 10956 10957 currentPolygonOffsetFactor = null; 10958 currentPolygonOffsetUnits = null; 10959 10960 currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height ); 10961 currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height ); 10962 10963 colorBuffer.reset(); 10964 depthBuffer.reset(); 10965 stencilBuffer.reset(); 10966 10967 } 10968 10969 return { 10970 10971 buffers: { 10972 color: colorBuffer, 10973 depth: depthBuffer, 10974 stencil: stencilBuffer 10975 }, 10976 10977 enable: enable, 10978 disable: disable, 10979 10980 bindFramebuffer: bindFramebuffer, 10981 drawBuffers: drawBuffers, 10982 10983 useProgram: useProgram, 10984 10985 setBlending: setBlending, 10986 setMaterial: setMaterial, 10987 10988 setFlipSided: setFlipSided, 10989 setCullFace: setCullFace, 10990 10991 setLineWidth: setLineWidth, 10992 setPolygonOffset: setPolygonOffset, 10993 10994 setScissorTest: setScissorTest, 10995 10996 activeTexture: activeTexture, 10997 bindTexture: bindTexture, 10998 unbindTexture: unbindTexture, 10999 compressedTexImage2D: compressedTexImage2D, 11000 compressedTexImage3D: compressedTexImage3D, 11001 texImage2D: texImage2D, 11002 texImage3D: texImage3D, 11003 pixelStorei: pixelStorei, 11004 getParameter: getParameter, 11005 11006 updateUBOMapping: updateUBOMapping, 11007 uniformBlockBinding: uniformBlockBinding, 11008 11009 texStorage2D: texStorage2D, 11010 texStorage3D: texStorage3D, 11011 texSubImage2D: texSubImage2D, 11012 texSubImage3D: texSubImage3D, 11013 compressedTexSubImage2D: compressedTexSubImage2D, 11014 compressedTexSubImage3D: compressedTexSubImage3D, 11015 11016 scissor: scissor, 11017 viewport: viewport, 11018 11019 reset: reset 11020 11021 }; 11022 11023} 11024 11025function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { 11026 11027 const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null; 11028 const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent ); 11029 11030 const _imageDimensions = new Vector2(); 11031 const _videoTextures = new WeakMap(); 11032 const _htmlTextures = new Set(); 11033 let _canvas; 11034 11035 const _sources = new WeakMap(); // maps WebglTexture objects to instances of TextureSource 11036 11037 // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, 11038 // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! 11039 // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). 11040 11041 let useOffscreenCanvas = false; 11042 11043 try { 11044 11045 useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' 11046 && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null; 11047 11048 11049 } catch ( err ) { 11050 11051 // Ignore any errors 11052 11053 } 11054 11055 function createCanvas( width, height ) { 11056 11057 // Use OffscreenCanvas when available. Specially needed in web workers 11058 11059 return useOffscreenCanvas ? 11060 new OffscreenCanvas( width, height ) : createElementNS( 'canvas' ); 11061 11062 } 11063 11064 function resizeImage( image, needsNewCanvas, maxSize ) { 11065 11066 let scale = 1; 11067 11068 const dimensions = getDimensions( image ); 11069 11070 // handle case if texture exceeds max size 11071 11072 if ( dimensions.width > maxSize || dimensions.height > maxSize ) { 11073 11074 scale = maxSize / Math.max( dimensions.width, dimensions.height ); 11075 11076 } 11077 11078 // only perform resize if necessary 11079 11080 if ( scale < 1 ) { 11081 11082 // only perform resize for certain image types 11083 11084 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || 11085 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || 11086 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) || 11087 ( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) ) { 11088 11089 const width = Math.floor( scale * dimensions.width ); 11090 const height = Math.floor( scale * dimensions.height ); 11091 11092 if ( _canvas === undefined ) _canvas = createCanvas( width, height ); 11093 11094 // cube textures can't reuse the same canvas 11095 11096 const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas; 11097 11098 canvas.width = width; 11099 canvas.height = height; 11100 11101 const context = canvas.getContext( '2d' ); 11102 context.drawImage( image, 0, 0, width, height ); 11103 11104 warn( 'WebGLRenderer: Texture has been resized from (' + dimensions.width + 'x' + dimensions.height + ') to (' + width + 'x' + height + ').' ); 11105 11106 return canvas; 11107 11108 } else { 11109 11110 if ( 'data' in image ) { 11111 11112 warn( 'WebGLRenderer: Image in DataTexture is too big (' + dimensions.width + 'x' + dimensions.height + ').' ); 11113 11114 } 11115 11116 return image; 11117 11118 } 11119 11120 } 11121 11122 return image; 11123 11124 } 11125 11126 function textureNeedsGenerateMipmaps( texture ) { 11127 11128 return texture.generateMipmaps; 11129 11130 } 11131 11132 function generateMipmap( target ) { 11133 11134 _gl.generateMipmap( target ); 11135 11136 } 11137 11138 function getTargetType( texture ) { 11139 11140 if ( texture.isWebGLCubeRenderTarget ) return _gl.TEXTURE_CUBE_MAP; 11141 if ( texture.isWebGL3DRenderTarget ) return _gl.TEXTURE_3D; 11142 if ( texture.isWebGLArrayRenderTarget || texture.isCompressedArrayTexture ) return _gl.TEXTURE_2D_ARRAY; 11143 return _gl.TEXTURE_2D; 11144 11145 } 11146 11147 function getInternalFormat( internalFormatName, glFormat, glType, normalized, colorSpace, forceLinearTransfer = false ) { 11148 11149 if ( internalFormatName !== null ) { 11150 11151 if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ]; 11152 11153 warn( 'WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); 11154 11155 } 11156 11157 let ext_texture_norm16; 11158 11159 if ( normalized ) { 11160 11161 ext_texture_norm16 = extensions.get( 'EXT_texture_norm16' ); 11162 11163 if ( ! ext_texture_norm16 ) { 11164 11165 warn( 'WebGLRenderer: Unable to use normalized textures without EXT_texture_norm16 extension' ); 11166 11167 } 11168 11169 } 11170 11171 let internalFormat = glFormat; 11172 11173 if ( glFormat === _gl.RED ) { 11174 11175 if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F; 11176 if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F; 11177 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8; 11178 if ( glType === _gl.UNSIGNED_SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.R16_EXT; 11179 if ( glType === _gl.SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.R16_SNORM_EXT; 11180 11181 } 11182 11183 if ( glFormat === _gl.RED_INTEGER ) { 11184 11185 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI; 11186 if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI; 11187 if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI; 11188 if ( glType === _gl.BYTE ) internalFormat = _gl.R8I; 11189 if ( glType === _gl.SHORT ) internalFormat = _gl.R16I; 11190 if ( glType === _gl.INT ) internalFormat = _gl.R32I; 11191 11192 } 11193 11194 if ( glFormat === _gl.RG ) { 11195 11196 if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F; 11197 if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F; 11198 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8; 11199 if ( glType === _gl.UNSIGNED_SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RG16_EXT; 11200 if ( glType === _gl.SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RG16_SNORM_EXT; 11201 11202 } 11203 11204 if ( glFormat === _gl.RG_INTEGER ) { 11205 11206 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8UI; 11207 if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RG16UI; 11208 if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RG32UI; 11209 if ( glType === _gl.BYTE ) internalFormat = _gl.RG8I; 11210 if ( glType === _gl.SHORT ) internalFormat = _gl.RG16I; 11211 if ( glType === _gl.INT ) internalFormat = _gl.RG32I; 11212 11213 } 11214 11215 if ( glFormat === _gl.RGB_INTEGER ) { 11216 11217 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGB8UI; 11218 if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGB16UI; 11219 if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGB32UI; 11220 if ( glType === _gl.BYTE ) internalFormat = _gl.RGB8I; 11221 if ( glType === _gl.SHORT ) internalFormat = _gl.RGB16I; 11222 if ( glType === _gl.INT ) internalFormat = _gl.RGB32I; 11223 11224 } 11225 11226 if ( glFormat === _gl.RGBA_INTEGER ) { 11227 11228 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGBA8UI; 11229 if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGBA16UI; 11230 if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGBA32UI; 11231 if ( glType === _gl.BYTE ) internalFormat = _gl.RGBA8I; 11232 if ( glType === _gl.SHORT ) internalFormat = _gl.RGBA16I; 11233 if ( glType === _gl.INT ) internalFormat = _gl.RGBA32I; 11234 11235 } 11236 11237 if ( glFormat === _gl.RGB ) { 11238 11239 if ( glType === _gl.UNSIGNED_SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RGB16_EXT; 11240 if ( glType === _gl.SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RGB16_SNORM_EXT; 11241 if ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5; 11242 if ( glType === _gl.UNSIGNED_INT_10F_11F_11F_REV ) internalFormat = _gl.R11F_G11F_B10F; 11243 11244 } 11245 11246 if ( glFormat === _gl.RGBA ) { 11247 11248 const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace ); 11249 11250 if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F; 11251 if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F; 11252 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8; 11253 if ( glType === _gl.UNSIGNED_SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RGBA16_EXT; 11254 if ( glType === _gl.SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RGBA16_SNORM_EXT; 11255 if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4; 11256 if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1; 11257 11258 } 11259 11260 if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F || 11261 internalFormat === _gl.RG16F || internalFormat === _gl.RG32F || 11262 internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) { 11263 11264 extensions.get( 'EXT_color_buffer_float' ); 11265 11266 } 11267 11268 return internalFormat; 11269 11270 } 11271 11272 function getInternalDepthFormat( useStencil, depthType ) { 11273 11274 let glInternalFormat; 11275 if ( useStencil ) { 11276 11277 if ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) { 11278 11279 glInternalFormat = _gl.DEPTH24_STENCIL8; 11280 11281 } else if ( depthType === FloatType ) { 11282 11283 glInternalFormat = _gl.DEPTH32F_STENCIL8; 11284 11285 } else if ( depthType === UnsignedShortType ) { 11286 11287 glInternalFormat = _gl.DEPTH24_STENCIL8; 11288 warn( 'DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.' ); 11289 11290 } 11291 11292 } else { 11293 11294 if ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) { 11295 11296 glInternalFormat = _gl.DEPTH_COMPONENT24; 11297 11298 } else if ( depthType === FloatType ) { 11299 11300 glInternalFormat = _gl.DEPTH_COMPONENT32F; 11301 11302 } else if ( depthType === UnsignedShortType ) { 11303 11304 glInternalFormat = _gl.DEPTH_COMPONENT16; 11305 11306 } 11307 11308 } 11309 11310 return glInternalFormat; 11311 11312 } 11313 11314 function getMipLevels( texture, image ) { 11315 11316 if ( textureNeedsGenerateMipmaps( texture ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) { 11317 11318 return Math.log2( Math.max( image.width, image.height ) ) + 1; 11319 11320 } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) { 11321 11322 // user-defined mipmaps 11323 11324 return texture.mipmaps.length; 11325 11326 } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) { 11327 11328 return image.mipmaps.length; 11329 11330 } else { 11331 11332 // texture without mipmaps (only base level) 11333 11334 return 1; 11335 11336 } 11337 11338 } 11339 11340 // 11341 11342 function onTextureDispose( event ) { 11343 11344 const texture = event.target; 11345 11346 texture.removeEventListener( 'dispose', onTextureDispose ); 11347 11348 deallocateTexture( texture ); 11349 11350 if ( texture.isVideoTexture ) { 11351 11352 _videoTextures.delete( texture ); 11353 11354 } 11355 11356 if ( texture.isHTMLTexture ) { 11357 11358 _htmlTextures.delete( texture ); 11359 11360 } 11361 11362 } 11363 11364 function onRenderTargetDispose( event ) { 11365 11366 const renderTarget = event.target; 11367 11368 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); 11369 11370 deallocateRenderTarget( renderTarget ); 11371 11372 } 11373 11374 // 11375 11376 function deallocateTexture( texture ) { 11377 11378 const textureProperties = properties.get( texture ); 11379 11380 if ( textureProperties.__webglInit === undefined ) return; 11381 11382 // check if it's necessary to remove the WebGLTexture object 11383 11384 const source = texture.source; 11385 const webglTextures = _sources.get( source ); 11386 11387 if ( webglTextures ) { 11388 11389 const webglTexture = webglTextures[ textureProperties.__cacheKey ]; 11390 webglTexture.usedTimes --; 11391 11392 // the WebGLTexture object is not used anymore, remove it 11393 11394 if ( webglTexture.usedTimes === 0 ) { 11395 11396 deleteTexture( texture ); 11397 11398 } 11399 11400 // remove the weak map entry if no WebGLTexture uses the source anymore 11401 11402 if ( Object.keys( webglTextures ).length === 0 ) { 11403 11404 _sources.delete( source ); 11405 11406 } 11407 11408 } 11409 11410 properties.remove( texture ); 11411 11412 } 11413 11414 function deleteTexture( texture ) { 11415 11416 const textureProperties = properties.get( texture ); 11417 _gl.deleteTexture( textureProperties.__webglTexture ); 11418 11419 const source = texture.source; 11420 const webglTextures = _sources.get( source ); 11421 delete webglTextures[ textureProperties.__cacheKey ]; 11422 11423 info.memory.textures --; 11424 11425 } 11426 11427 function deallocateRenderTarget( renderTarget ) { 11428 11429 const renderTargetProperties = properties.get( renderTarget ); 11430 11431 if ( renderTarget.depthTexture ) { 11432 11433 renderTarget.depthTexture.dispose(); 11434 11435 properties.remove( renderTarget.depthTexture ); 11436 11437 } 11438 11439 if ( renderTarget.isWebGLCubeRenderTarget ) { 11440 11441 for ( let i = 0; i < 6; i ++ ) { 11442 11443 if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) { 11444 11445 for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] ); 11446 11447 } else { 11448 11449 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); 11450 11451 } 11452 11453 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); 11454 11455 } 11456 11457 } else { 11458 11459 if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) { 11460 11461 for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] ); 11462 11463 } else { 11464 11465 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); 11466 11467 } 11468 11469 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); 11470 if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); 11471 11472 if ( renderTargetProperties.__webglColorRenderbuffer ) { 11473 11474 for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) { 11475 11476 if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] ); 11477 11478 } 11479 11480 } 11481 11482 if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer ); 11483 11484 } 11485 11486 const textures = renderTarget.textures; 11487 11488 for ( let i = 0, il = textures.length; i < il; i ++ ) { 11489 11490 const attachmentProperties = properties.get( textures[ i ] ); 11491 11492 if ( attachmentProperties.__webglTexture ) { 11493 11494 _gl.deleteTexture( attachmentProperties.__webglTexture ); 11495 11496 info.memory.textures --; 11497 11498 } 11499 11500 properties.remove( textures[ i ] ); 11501 11502 } 11503 11504 properties.remove( renderTarget ); 11505 11506 } 11507 11508 // 11509 11510 let textureUnits = 0; 11511 11512 function resetTextureUnits() { 11513 11514 textureUnits = 0; 11515 11516 } 11517 11518 function getTextureUnits() { 11519 11520 return textureUnits; 11521 11522 } 11523 11524 function setTextureUnits( value ) { 11525 11526 textureUnits = value; 11527 11528 } 11529 11530 function allocateTextureUnit() { 11531 11532 const textureUnit = textureUnits; 11533 11534 if ( textureUnit >= capabilities.maxTextures ) { 11535 11536 warn( 'WebGLTextures: Trying to use ' + ( textureUnit + 1 ) + ' texture units while this GPU supports only ' + capabilities.maxTextures ); 11537 11538 } 11539 11540 textureUnits += 1; 11541 11542 return textureUnit; 11543 11544 } 11545 11546 function getTextureCacheKey( texture ) { 11547 11548 const array = []; 11549 11550 array.push( texture.wrapS ); 11551 array.push( texture.wrapT ); 11552 array.push( texture.wrapR || 0 ); 11553 array.push( texture.magFilter ); 11554 array.push( texture.minFilter ); 11555 array.push( texture.anisotropy ); 11556 array.push( texture.internalFormat ); 11557 array.push( texture.format ); 11558 array.push( texture.type ); 11559 array.push( texture.generateMipmaps ); 11560 array.push( texture.premultiplyAlpha ); 11561 array.push( texture.flipY ); 11562 array.push( texture.unpackAlignment ); 11563 array.push( texture.colorSpace ); 11564 11565 return array.join(); 11566 11567 } 11568 11569 // 11570 11571 function setTexture2D( texture, slot ) { 11572 11573 const textureProperties = properties.get( texture ); 11574 11575 if ( texture.isVideoTexture ) updateVideoTexture( texture ); 11576 11577 if ( texture.isRenderTargetTexture === false && texture.isExternalTexture !== true && texture.version > 0 && textureProperties.__version !== texture.version ) { 11578 11579 const image = texture.image; 11580 11581 if ( image === null ) { 11582 11583 warn( 'WebGLRenderer: Texture marked for update but no image data found.' ); 11584 11585 } else if ( image.complete === false ) { 11586 11587 warn( 'WebGLRenderer: Texture marked for update but image is incomplete' ); 11588 11589 } else { 11590 11591 uploadTexture( textureProperties, texture, slot ); 11592 return; 11593 11594 } 11595 11596 } else if ( texture.isExternalTexture ) { 11597 11598 textureProperties.__webglTexture = texture.sourceTexture ? texture.sourceTexture : null; 11599 11600 } 11601 11602 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 11603 11604 } 11605 11606 function setTexture2DArray( texture, slot ) { 11607 11608 const textureProperties = properties.get( texture ); 11609 11610 if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) { 11611 11612 uploadTexture( textureProperties, texture, slot ); 11613 return; 11614 11615 } else if ( texture.isExternalTexture ) { 11616 11617 textureProperties.__webglTexture = texture.sourceTexture ? texture.sourceTexture : null; 11618 11619 } 11620 11621 state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 11622 11623 } 11624 11625 function setTexture3D( texture, slot ) { 11626 11627 const textureProperties = properties.get( texture ); 11628 11629 if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) { 11630 11631 uploadTexture( textureProperties, texture, slot ); 11632 return; 11633 11634 } 11635 11636 state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 11637 11638 } 11639 11640 function setTextureCube( texture, slot ) { 11641 11642 const textureProperties = properties.get( texture ); 11643 11644 if ( texture.isCubeDepthTexture !== true && texture.version > 0 && textureProperties.__version !== texture.version ) { 11645 11646 uploadCubeTexture( textureProperties, texture, slot ); 11647 return; 11648 11649 } 11650 11651 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 11652 11653 } 11654 11655 const wrappingToGL = { 11656 [ RepeatWrapping ]: _gl.REPEAT, 11657 [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE, 11658 [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT 11659 }; 11660 11661 const filterToGL = { 11662 [ NearestFilter ]: _gl.NEAREST, 11663 [ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST, 11664 [ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR, 11665 11666 [ LinearFilter ]: _gl.LINEAR, 11667 [ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST, 11668 [ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR 11669 }; 11670 11671 const compareToGL = { 11672 [ NeverCompare ]: _gl.NEVER, 11673 [ AlwaysCompare ]: _gl.ALWAYS, 11674 [ LessCompare ]: _gl.LESS, 11675 [ LessEqualCompare ]: _gl.LEQUAL, 11676 [ EqualCompare ]: _gl.EQUAL, 11677 [ GreaterEqualCompare ]: _gl.GEQUAL, 11678 [ GreaterCompare ]: _gl.GREATER, 11679 [ NotEqualCompare ]: _gl.NOTEQUAL 11680 }; 11681 11682 function setTextureParameters( textureType, texture ) { 11683 11684 if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false && 11685 ( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter || 11686 texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ) ) { 11687 11688 warn( 'WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device.' ); 11689 11690 } 11691 11692 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] ); 11693 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] ); 11694 11695 if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { 11696 11697 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] ); 11698 11699 } 11700 11701 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] ); 11702 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] ); 11703 11704 if ( texture.compareFunction ) { 11705 11706 _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE ); 11707 _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] ); 11708 11709 } 11710 11711 if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { 11712 11713 if ( texture.magFilter === NearestFilter ) return; 11714 if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return; 11715 if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension 11716 11717 if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { 11718 11719 const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); 11720 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); 11721 properties.get( texture ).__currentAnisotropy = texture.anisotropy; 11722 11723 } 11724 11725 } 11726 11727 } 11728 11729 function initTexture( textureProperties, texture ) { 11730 11731 let forceUpload = false; 11732 11733 if ( textureProperties.__webglInit === undefined ) { 11734 11735 textureProperties.__webglInit = true; 11736 11737 texture.addEventListener( 'dispose', onTextureDispose ); 11738 11739 } 11740 11741 // create TextureSource <-> WebGLTextures mapping if necessary 11742 11743 const source = texture.source; 11744 let webglTextures = _sources.get( source ); 11745 11746 if ( webglTextures === undefined ) { 11747 11748 webglTextures = {}; 11749 _sources.set( source, webglTextures ); 11750 11751 } 11752 11753 // check if there is already a WebGLTexture object for the given texture parameters 11754 11755 const textureCacheKey = getTextureCacheKey( texture ); 11756 11757 if ( textureCacheKey !== textureProperties.__cacheKey ) { 11758 11759 // if not, create a new instance of WebGLTexture 11760 11761 if ( webglTextures[ textureCacheKey ] === undefined ) { 11762 11763 // create new entry 11764 11765 webglTextures[ textureCacheKey ] = { 11766 texture: _gl.createTexture(), 11767 usedTimes: 0 11768 }; 11769 11770 info.memory.textures ++; 11771 11772 // when a new instance of WebGLTexture was created, a texture upload is required 11773 // even if the image contents are identical 11774 11775 forceUpload = true; 11776 11777 } 11778 11779 webglTextures[ textureCacheKey ].usedTimes ++; 11780 11781 // every time the texture cache key changes, it's necessary to check if an instance of 11782 // WebGLTexture can be deleted in order to avoid a memory leak. 11783 11784 const webglTexture = webglTextures[ textureProperties.__cacheKey ]; 11785 11786 if ( webglTexture !== undefined ) { 11787 11788 webglTextures[ textureProperties.__cacheKey ].usedTimes --; 11789 11790 if ( webglTexture.usedTimes === 0 ) { 11791 11792 deleteTexture( texture ); 11793 11794 } 11795 11796 } 11797 11798 // store references to cache key and WebGLTexture object 11799 11800 textureProperties.__cacheKey = textureCacheKey; 11801 textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture; 11802 11803 } 11804 11805 return forceUpload; 11806 11807 } 11808 11809 function getRow( index, rowLength, componentStride ) { 11810 11811 return Math.floor( Math.floor( index / componentStride ) / rowLength ); 11812 11813 } 11814 11815 function updateTexture( texture, image, glFormat, glType ) { 11816 11817 const componentStride = 4; // only RGBA supported 11818 11819 const updateRanges = texture.updateRanges; 11820 11821 if ( updateRanges.length === 0 ) { 11822 11823 state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); 11824 11825 } else { 11826 11827 // Before applying update ranges, we merge any adjacent / overlapping 11828 // ranges to reduce load on `gl.texSubImage2D`. Empirically, this has led 11829 // to performance improvements for applications which make heavy use of 11830 // update ranges. Likely due to GPU command overhead. 11831 // 11832 // Note that to reduce garbage collection between frames, we merge the 11833 // update ranges in-place. This is safe because this method will clear the 11834 // update ranges once updated. 11835 11836 updateRanges.sort( ( a, b ) => a.start - b.start ); 11837 11838 // To merge the update ranges in-place, we work from left to right in the 11839 // existing updateRanges array, merging ranges. This may result in a final 11840 // array which is smaller than the original. This index tracks the last 11841 // index representing a merged range, any data after this index can be 11842 // trimmed once the merge algorithm is completed. 11843 let mergeIndex = 0; 11844 11845 for ( let i = 1; i < updateRanges.length; i ++ ) { 11846 11847 const previousRange = updateRanges[ mergeIndex ]; 11848 const range = updateRanges[ i ]; 11849 11850 // Only merge if in the same row and overlapping/adjacent 11851 const previousEnd = previousRange.start + previousRange.count; 11852 const currentRow = getRow( range.start, image.width, componentStride ); 11853 const previousRow = getRow( previousRange.start, image.width, componentStride ); 11854 11855 // We add one here to merge adjacent ranges. This is safe because ranges 11856 // operate over positive integers. 11857 if ( 11858 range.start <= previousEnd + 1 && 11859 currentRow === previousRow && 11860 getRow( range.start + range.count - 1, image.width, componentStride ) === currentRow // ensure range doesn't spill 11861 ) { 11862 11863 previousRange.count = Math.max( 11864 previousRange.count, 11865 range.start + range.count - previousRange.start 11866 ); 11867 11868 } else { 11869 11870 ++ mergeIndex; 11871 updateRanges[ mergeIndex ] = range; 11872 11873 } 11874 11875 11876 } 11877 11878 // Trim the array to only contain the merged ranges. 11879 updateRanges.length = mergeIndex + 1; 11880 11881 const currentUnpackRowLen = state.getParameter( _gl.UNPACK_ROW_LENGTH ); 11882 const currentUnpackSkipPixels = state.getParameter( _gl.UNPACK_SKIP_PIXELS ); 11883 const currentUnpackSkipRows = state.getParameter( _gl.UNPACK_SKIP_ROWS ); 11884 11885 state.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width ); 11886 11887 for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { 11888 11889 const range = updateRanges[ i ]; 11890 11891 const pixelStart = Math.floor( range.start / componentStride ); 11892 const pixelCount = Math.ceil( range.count / componentStride ); 11893 11894 const x = pixelStart % image.width; 11895 const y = Math.floor( pixelStart / image.width ); 11896 11897 // Assumes update ranges refer to contiguous memory 11898 const width = pixelCount; 11899 const height = 1; 11900 11901 state.pixelStorei( _gl.UNPACK_SKIP_PIXELS, x ); 11902 state.pixelStorei( _gl.UNPACK_SKIP_ROWS, y ); 11903 11904 state.texSubImage2D( _gl.TEXTURE_2D, 0, x, y, width, height, glFormat, glType, image.data ); 11905 11906 } 11907 11908 texture.clearUpdateRanges(); 11909 11910 state.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen ); 11911 state.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels ); 11912 state.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows ); 11913 11914 } 11915 11916 } 11917 11918 function uploadTexture( textureProperties, texture, slot ) { 11919 11920 let textureType = _gl.TEXTURE_2D; 11921 11922 if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY; 11923 if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D; 11924 11925 const forceUpload = initTexture( textureProperties, texture ); 11926 const source = texture.source; 11927 11928 state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 11929 11930 const sourceProperties = properties.get( source ); 11931 11932 if ( source.version !== sourceProperties.__version || forceUpload === true ) { 11933 11934 state.activeTexture( _gl.TEXTURE0 + slot ); 11935 11936 const isImageBitmap = ( typeof ImageBitmap !== 'undefined' && texture.image instanceof ImageBitmap ); 11937 11938 if ( isImageBitmap === false ) { 11939 11940 const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); 11941 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace ); 11942 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; 11943 11944 state.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); 11945 state.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); 11946 state.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); 11947 11948 } 11949 11950 state.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); 11951 11952 let image = resizeImage( texture.image, false, capabilities.maxTextureSize ); 11953 image = verifyColorSpace( texture, image ); 11954 11955 const glFormat = utils.convert( texture.format, texture.colorSpace ); 11956 11957 const glType = utils.convert( texture.type ); 11958 let glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace, texture.isVideoTexture ); 11959 11960 setTextureParameters( textureType, texture ); 11961 11962 let mipmap; 11963 const mipmaps = texture.mipmaps; 11964 11965 const useTexStorage = ( texture.isVideoTexture !== true ); 11966 const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); 11967 const dataReady = source.dataReady; 11968 const levels = getMipLevels( texture, image ); 11969 11970 if ( texture.isDepthTexture ) { 11971 11972 glInternalFormat = getInternalDepthFormat( texture.format === DepthStencilFormat, texture.type ); 11973 11974 // 11975 11976 if ( allocateMemory ) { 11977 11978 if ( useTexStorage ) { 11979 11980 state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height ); 11981 11982 } else { 11983 11984 state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); 11985 11986 } 11987 11988 } 11989 11990 } else if ( texture.isDataTexture ) { 11991 11992 // use manually created mipmaps if available 11993 // if there are no manual mipmaps 11994 // set 0 level mipmap and then use GL to generate other mipmap levels 11995 11996 if ( mipmaps.length > 0 ) { 11997 11998 if ( useTexStorage && allocateMemory ) { 11999 12000 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); 12001 12002 } 12003 12004 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { 12005 12006 mipmap = mipmaps[ i ]; 12007 12008 if ( useTexStorage ) { 12009 12010 if ( dataReady ) { 12011 12012 state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); 12013 12014 } 12015 12016 } else { 12017 12018 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); 12019 12020 } 12021 12022 } 12023 12024 texture.generateMipmaps = false; 12025 12026 } else { 12027 12028 if ( useTexStorage ) { 12029 12030 if ( allocateMemory ) { 12031 12032 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); 12033 12034 } 12035 12036 if ( dataReady ) { 12037 12038 updateTexture( texture, image, glFormat, glType ); 12039 12040 } 12041 12042 } else { 12043 12044 state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); 12045 12046 } 12047 12048 } 12049 12050 } else if ( texture.isCompressedTexture ) { 12051 12052 if ( texture.isCompressedArrayTexture ) { 12053 12054 if ( useTexStorage && allocateMemory ) { 12055 12056 state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); 12057 12058 } 12059 12060 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { 12061 12062 mipmap = mipmaps[ i ]; 12063 12064 if ( texture.format !== RGBAFormat ) { 12065 12066 if ( glFormat !== null ) { 12067 12068 if ( useTexStorage ) { 12069 12070 if ( dataReady ) { 12071 12072 if ( texture.layerUpdates.size > 0 ) { 12073 12074 const layerByteLength = getByteLength( mipmap.width, mipmap.height, texture.format, texture.type ); 12075 12076 for ( const layerIndex of texture.layerUpdates ) { 12077 12078 const layerData = mipmap.data.subarray( 12079 layerIndex * layerByteLength / mipmap.data.BYTES_PER_ELEMENT, 12080 ( layerIndex + 1 ) * layerByteLength / mipmap.data.BYTES_PER_ELEMENT 12081 ); 12082 state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, layerIndex, mipmap.width, mipmap.height, 1, glFormat, layerData ); 12083 12084 } 12085 12086 } else { 12087 12088 state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data ); 12089 12090 } 12091 12092 } 12093 12094 } else { 12095 12096 state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); 12097 12098 } 12099 12100 } else { 12101 12102 warn( 'WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); 12103 12104 } 12105 12106 } else { 12107 12108 if ( useTexStorage ) { 12109 12110 if ( dataReady ) { 12111 12112 state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); 12113 12114 } 12115 12116 } else { 12117 12118 state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); 12119 12120 } 12121 12122 } 12123 12124 } 12125 12126 if ( texture.layerUpdates.size > 0 ) texture.clearLayerUpdates(); 12127 12128 } else { 12129 12130 if ( useTexStorage && allocateMemory ) { 12131 12132 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); 12133 12134 } 12135 12136 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { 12137 12138 mipmap = mipmaps[ i ]; 12139 12140 if ( texture.format !== RGBAFormat ) { 12141 12142 if ( glFormat !== null ) { 12143 12144 if ( useTexStorage ) { 12145 12146 if ( dataReady ) { 12147 12148 state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); 12149 12150 } 12151 12152 } else { 12153 12154 state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); 12155 12156 } 12157 12158 } else { 12159 12160 warn( 'WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); 12161 12162 } 12163 12164 } else { 12165 12166 if ( useTexStorage ) { 12167 12168 if ( dataReady ) { 12169 12170 state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); 12171 12172 } 12173 12174 } else { 12175 12176 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); 12177 12178 } 12179 12180 } 12181 12182 } 12183 12184 } 12185 12186 } else if ( texture.isDataArrayTexture ) { 12187 12188 if ( useTexStorage ) { 12189 12190 if ( allocateMemory ) { 12191 12192 state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth ); 12193 12194 } 12195 12196 if ( dataReady ) { 12197 12198 if ( texture.layerUpdates.size > 0 ) { 12199 12200 const layerByteLength = getByteLength( image.width, image.height, texture.format, texture.type ); 12201 12202 for ( const layerIndex of texture.layerUpdates ) { 12203 12204 const layerData = image.data.subarray( 12205 layerIndex * layerByteLength / image.data.BYTES_PER_ELEMENT, 12206 ( layerIndex + 1 ) * layerByteLength / image.data.BYTES_PER_ELEMENT 12207 ); 12208 state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, layerIndex, image.width, image.height, 1, glFormat, glType, layerData ); 12209 12210 } 12211 12212 texture.clearLayerUpdates(); 12213 12214 } else { 12215 12216 state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); 12217 12218 } 12219 12220 } 12221 12222 } else { 12223 12224 state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); 12225 12226 } 12227 12228 } else if ( texture.isData3DTexture ) { 12229 12230 if ( useTexStorage ) { 12231 12232 if ( allocateMemory ) { 12233 12234 state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth ); 12235 12236 } 12237 12238 if ( dataReady ) { 12239 12240 state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); 12241 12242 } 12243 12244 } else { 12245 12246 state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); 12247 12248 } 12249 12250 } else if ( texture.isFramebufferTexture ) { 12251 12252 if ( allocateMemory ) { 12253 12254 if ( useTexStorage ) { 12255 12256 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); 12257 12258 } else { 12259 12260 let width = image.width, height = image.height; 12261 12262 for ( let i = 0; i < levels; i ++ ) { 12263 12264 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null ); 12265 12266 width >>= 1; 12267 height >>= 1; 12268 12269 } 12270 12271 } 12272 12273 } 12274 12275 } else if ( texture.isHTMLTexture ) { 12276 12277 if ( 'texElementImage2D' in _gl ) { 12278 12279 const canvas = _gl.canvas; 12280 12281 // Ensure the canvas supports HTML-in-Canvas and the element is a child. 12282 if ( ! canvas.hasAttribute( 'layoutsubtree' ) ) { 12283 12284 canvas.setAttribute( 'layoutsubtree', 'true' ); 12285 12286 } 12287 12288 if ( image.parentNode !== canvas ) { 12289 12290 canvas.appendChild( image ); 12291 12292 // Register and set up a shared paint callback for all HTMLTextures. 12293 _htmlTextures.add( texture ); 12294 12295 canvas.onpaint = ( event ) => { 12296 12297 const changed = event.changedElements; 12298 12299 for ( const t of _htmlTextures ) { 12300 12301 if ( changed.includes( t.image ) ) { 12302 12303 t.needsUpdate = true; 12304 12305 } 12306 12307 } 12308 12309 }; 12310 12311 canvas.requestPaint(); 12312 return; 12313 12314 } 12315 12316 if ( _gl.texElementImage2D.length === 3 ) { 12317 12318 // Chrome 150+ 12319 12320 _gl.texElementImage2D( _gl.TEXTURE_2D, _gl.RGBA8, image ); 12321 12322 } else { 12323 12324 // Chrome 138 - 149 12325 12326 const level = 0; 12327 const internalFormat = _gl.RGBA; 12328 const srcFormat = _gl.RGBA; 12329 const srcType = _gl.UNSIGNED_BYTE; 12330 12331 _gl.texElementImage2D( _gl.TEXTURE_2D, level, internalFormat, srcFormat, srcType, image ); 12332 12333 } 12334 12335 _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR ); 12336 _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); 12337 _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); 12338 12339 } 12340 12341 } else { 12342 12343 // regular Texture (image, video, canvas) 12344 12345 // use manually created mipmaps if available 12346 // if there are no manual mipmaps 12347 // set 0 level mipmap and then use GL to generate other mipmap levels 12348 12349 if ( mipmaps.length > 0 ) { 12350 12351 if ( useTexStorage && allocateMemory ) { 12352 12353 const dimensions = getDimensions( mipmaps[ 0 ] ); 12354 12355 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height ); 12356 12357 } 12358 12359 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { 12360 12361 mipmap = mipmaps[ i ]; 12362 12363 if ( useTexStorage ) { 12364 12365 if ( dataReady ) { 12366 12367 state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap ); 12368 12369 } 12370 12371 } else { 12372 12373 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap ); 12374 12375 } 12376 12377 } 12378 12379 texture.generateMipmaps = false; 12380 12381 } else { 12382 12383 if ( useTexStorage ) { 12384 12385 if ( allocateMemory ) { 12386 12387 const dimensions = getDimensions( image ); 12388 12389 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height ); 12390 12391 } 12392 12393 if ( dataReady ) { 12394 12395 state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image ); 12396 12397 } 12398 12399 } else { 12400 12401 state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image ); 12402 12403 } 12404 12405 } 12406 12407 } 12408 12409 if ( textureNeedsGenerateMipmaps( texture ) ) { 12410 12411 generateMipmap( textureType ); 12412 12413 } 12414 12415 sourceProperties.__version = source.version; 12416 12417 if ( texture.onUpdate ) texture.onUpdate( texture ); 12418 12419 } 12420 12421 textureProperties.__version = texture.version; 12422 12423 } 12424 12425 function uploadCubeTexture( textureProperties, texture, slot ) { 12426 12427 if ( texture.image.length !== 6 ) return; 12428 12429 const forceUpload = initTexture( textureProperties, texture ); 12430 const source = texture.source; 12431 12432 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 12433 12434 const sourceProperties = properties.get( source ); 12435 12436 if ( source.version !== sourceProperties.__version || forceUpload === true ) { 12437 12438 state.activeTexture( _gl.TEXTURE0 + slot ); 12439 12440 const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); 12441 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace ); 12442 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; 12443 12444 state.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); 12445 state.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); 12446 state.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); 12447 state.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); 12448 12449 const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ); 12450 const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); 12451 12452 const cubeImage = []; 12453 12454 for ( let i = 0; i < 6; i ++ ) { 12455 12456 if ( ! isCompressed && ! isDataTexture ) { 12457 12458 cubeImage[ i ] = resizeImage( texture.image[ i ], true, capabilities.maxCubemapSize ); 12459 12460 } else { 12461 12462 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; 12463 12464 } 12465 12466 cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] ); 12467 12468 } 12469 12470 const image = cubeImage[ 0 ], 12471 glFormat = utils.convert( texture.format, texture.colorSpace ), 12472 glType = utils.convert( texture.type ), 12473 glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace ); 12474 12475 const useTexStorage = ( texture.isVideoTexture !== true ); 12476 const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); 12477 const dataReady = source.dataReady; 12478 let levels = getMipLevels( texture, image ); 12479 12480 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture ); 12481 12482 let mipmaps; 12483 12484 if ( isCompressed ) { 12485 12486 if ( useTexStorage && allocateMemory ) { 12487 12488 state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height ); 12489 12490 } 12491 12492 for ( let i = 0; i < 6; i ++ ) { 12493 12494 mipmaps = cubeImage[ i ].mipmaps; 12495 12496 for ( let j = 0; j < mipmaps.length; j ++ ) { 12497 12498 const mipmap = mipmaps[ j ]; 12499 12500 if ( texture.format !== RGBAFormat ) { 12501 12502 if ( glFormat !== null ) { 12503 12504 if ( useTexStorage ) { 12505 12506 if ( dataReady ) { 12507 12508 state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); 12509 12510 } 12511 12512 } else { 12513 12514 state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); 12515 12516 } 12517 12518 } else { 12519 12520 warn( 'WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); 12521 12522 } 12523 12524 } else { 12525 12526 if ( useTexStorage ) { 12527 12528 if ( dataReady ) { 12529 12530 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); 12531 12532 } 12533 12534 } else { 12535 12536 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); 12537 12538 } 12539 12540 } 12541 12542 } 12543 12544 } 12545 12546 } else { 12547 12548 mipmaps = texture.mipmaps; 12549 12550 if ( useTexStorage && allocateMemory ) { 12551 12552 // TODO: Uniformly handle mipmap definitions 12553 // Normal textures and compressed cube textures define base level + mips with their mipmap array 12554 // Uncompressed cube textures use their mipmap array only for mips (no base level) 12555 12556 if ( mipmaps.length > 0 ) levels ++; 12557 12558 const dimensions = getDimensions( cubeImage[ 0 ] ); 12559 12560 state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, dimensions.width, dimensions.height ); 12561 12562 } 12563 12564 for ( let i = 0; i < 6; i ++ ) { 12565 12566 if ( isDataTexture ) { 12567 12568 if ( useTexStorage ) { 12569 12570 if ( dataReady ) { 12571 12572 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); 12573 12574 } 12575 12576 } else { 12577 12578 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); 12579 12580 } 12581 12582 for ( let j = 0; j < mipmaps.length; j ++ ) { 12583 12584 const mipmap = mipmaps[ j ]; 12585 const mipmapImage = mipmap.image[ i ].image; 12586 12587 if ( useTexStorage ) { 12588 12589 if ( dataReady ) { 12590 12591 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); 12592 12593 } 12594 12595 } else { 12596 12597 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); 12598 12599 } 12600 12601 } 12602 12603 } else { 12604 12605 if ( useTexStorage ) { 12606 12607 if ( dataReady ) { 12608 12609 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); 12610 12611 } 12612 12613 } else { 12614 12615 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); 12616 12617 } 12618 12619 for ( let j = 0; j < mipmaps.length; j ++ ) { 12620 12621 const mipmap = mipmaps[ j ]; 12622 12623 if ( useTexStorage ) { 12624 12625 if ( dataReady ) { 12626 12627 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); 12628 12629 } 12630 12631 } else { 12632 12633 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); 12634 12635 } 12636 12637 } 12638 12639 } 12640 12641 } 12642 12643 } 12644 12645 if ( textureNeedsGenerateMipmaps( texture ) ) { 12646 12647 // We assume images for cube map have the same size. 12648 generateMipmap( _gl.TEXTURE_CUBE_MAP ); 12649 12650 } 12651 12652 sourceProperties.__version = source.version; 12653 12654 if ( texture.onUpdate ) texture.onUpdate( texture ); 12655 12656 } 12657 12658 textureProperties.__version = texture.version; 12659 12660 } 12661 12662 // Render targets 12663 12664 // Setup storage for target texture and bind it to correct framebuffer 12665 function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) { 12666 12667 const glFormat = utils.convert( texture.format, texture.colorSpace ); 12668 const glType = utils.convert( texture.type ); 12669 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace ); 12670 const renderTargetProperties = properties.get( renderTarget ); 12671 const textureProperties = properties.get( texture ); 12672 12673 textureProperties.__renderTarget = renderTarget; 12674 12675 if ( ! renderTargetProperties.__hasExternalTextures ) { 12676 12677 const width = Math.max( 1, renderTarget.width >> level ); 12678 const height = Math.max( 1, renderTarget.height >> level ); 12679 12680 if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) { 12681 12682 state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null ); 12683 12684 } else { 12685 12686 state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null ); 12687 12688 } 12689 12690 } 12691 12692 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 12693 12694 if ( useMultisampledRTT( renderTarget ) ) { 12695 12696 multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); 12697 12698 } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753 12699 12700 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, level ); 12701 12702 } 12703 12704 state.bindFramebuffer( _gl.FRAMEBUFFER, null ); 12705 12706 } 12707 12708 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer 12709 function setupRenderBufferStorage( renderbuffer, renderTarget, useMultisample ) { 12710 12711 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); 12712 12713 if ( renderTarget.depthBuffer ) { 12714 12715 // retrieve the depth attachment types 12716 const depthTexture = renderTarget.depthTexture; 12717 const depthType = depthTexture && depthTexture.isDepthTexture ? depthTexture.type : null; 12718 const glInternalFormat = getInternalDepthFormat( renderTarget.stencilBuffer, depthType ); 12719 const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 12720 12721 // set up the attachment 12722 if ( useMultisampledRTT( renderTarget ) ) { 12723 12724 multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, getRenderTargetSamples( renderTarget ), glInternalFormat, renderTarget.width, renderTarget.height ); 12725 12726 } else if ( useMultisample ) { 12727 12728 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, getRenderTargetSamples( renderTarget ), glInternalFormat, renderTarget.width, renderTarget.height ); 12729 12730 } else { 12731 12732 _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); 12733 12734 } 12735 12736 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer ); 12737 12738 } else { 12739 12740 const textures = renderTarget.textures; 12741 12742 for ( let i = 0; i < textures.length; i ++ ) { 12743 12744 const texture = textures[ i ]; 12745 12746 const glFormat = utils.convert( texture.format, texture.colorSpace ); 12747 const glType = utils.convert( texture.type ); 12748 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace ); 12749 12750 if ( useMultisampledRTT( renderTarget ) ) { 12751 12752 multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, getRenderTargetSamples( renderTarget ), glInternalFormat, renderTarget.width, renderTarget.height ); 12753 12754 } else if ( useMultisample ) { 12755 12756 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, getRenderTargetSamples( renderTarget ), glInternalFormat, renderTarget.width, renderTarget.height ); 12757 12758 } else { 12759 12760 _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); 12761 12762 } 12763 12764 } 12765 12766 } 12767 12768 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); 12769 12770 } 12771 12772 // Setup resources for a Depth Texture for a FBO (needs an extension) 12773 function setupDepthTexture( framebuffer, renderTarget, cubeFace ) { 12774 12775 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); 12776 12777 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 12778 12779 if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { 12780 12781 throw new Error( 'THREE.WebGLTextures: renderTarget.depthTexture must be an instance of THREE.DepthTexture.' ); 12782 12783 } 12784 12785 const textureProperties = properties.get( renderTarget.depthTexture ); 12786 textureProperties.__renderTarget = renderTarget; 12787 12788 // upload an empty depth texture with framebuffer size 12789 if ( ! textureProperties.__webglTexture || 12790 renderTarget.depthTexture.image.width !== renderTarget.width || 12791 renderTarget.depthTexture.image.height !== renderTarget.height ) { 12792 12793 renderTarget.depthTexture.image.width = renderTarget.width; 12794 renderTarget.depthTexture.image.height = renderTarget.height; 12795 renderTarget.depthTexture.needsUpdate = true; 12796 12797 } 12798 12799 if ( isCube ) { 12800 12801 // For cube depth textures, initialize and bind without uploading image data 12802 if ( textureProperties.__webglInit === undefined ) { 12803 12804 textureProperties.__webglInit = true; 12805 renderTarget.depthTexture.addEventListener( 'dispose', onTextureDispose ); 12806 12807 } 12808 12809 // Only create and allocate storage once 12810 if ( textureProperties.__webglTexture === undefined ) { 12811 12812 textureProperties.__webglTexture = _gl.createTexture(); 12813 12814 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); 12815 setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget.depthTexture ); 12816 12817 // Allocate storage for all 6 faces with correct depth texture format 12818 const glFormat = utils.convert( renderTarget.depthTexture.format ); 12819 const glType = utils.convert( renderTarget.depthTexture.type ); 12820 12821 // Use proper internal format for depth textures 12822 let glInternalFormat; 12823 if ( renderTarget.depthTexture.format === DepthFormat ) { 12824 12825 glInternalFormat = _gl.DEPTH_COMPONENT24; 12826 12827 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { 12828 12829 glInternalFormat = _gl.DEPTH24_STENCIL8; 12830 12831 } 12832 12833 for ( let i = 0; i < 6; i ++ ) { 12834 12835 _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); 12836 12837 } 12838 12839 } 12840 12841 } else { 12842 12843 setTexture2D( renderTarget.depthTexture, 0 ); 12844 12845 } 12846 12847 const webglDepthTexture = textureProperties.__webglTexture; 12848 const samples = getRenderTargetSamples( renderTarget ); 12849 12850 const glTextureType = isCube ? _gl.TEXTURE_CUBE_MAP_POSITIVE_X + cubeFace : _gl.TEXTURE_2D; 12851 const glAttachmentType = renderTarget.depthTexture.format === DepthStencilFormat ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 12852 12853 if ( renderTarget.depthTexture.format === DepthFormat ) { 12854 12855 if ( useMultisampledRTT( renderTarget ) ) { 12856 12857 multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, glAttachmentType, glTextureType, webglDepthTexture, 0, samples ); 12858 12859 } else { 12860 12861 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, glAttachmentType, glTextureType, webglDepthTexture, 0 ); 12862 12863 } 12864 12865 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { 12866 12867 if ( useMultisampledRTT( renderTarget ) ) { 12868 12869 multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, glAttachmentType, glTextureType, webglDepthTexture, 0, samples ); 12870 12871 } else { 12872 12873 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, glAttachmentType, glTextureType, webglDepthTexture, 0 ); 12874 12875 } 12876 12877 } else { 12878 12879 throw new Error( 'THREE.WebGLTextures: Unknown depthTexture format.' ); 12880 12881 } 12882 12883 } 12884 12885 // Setup GL resources for a non-texture depth buffer 12886 function setupDepthRenderbuffer( renderTarget ) { 12887 12888 const renderTargetProperties = properties.get( renderTarget ); 12889 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); 12890 12891 // if the bound depth texture has changed 12892 if ( renderTargetProperties.__boundDepthTexture !== renderTarget.depthTexture ) { 12893 12894 // fire the dispose event to get rid of stored state associated with the previously bound depth buffer 12895 const depthTexture = renderTarget.depthTexture; 12896 if ( renderTargetProperties.__depthDisposeCallback ) { 12897 12898 renderTargetProperties.__depthDisposeCallback(); 12899 12900 } 12901 12902 // set up dispose listeners to track when the currently attached buffer is implicitly unbound 12903 if ( depthTexture ) { 12904 12905 const disposeEvent = () => { 12906 12907 delete renderTargetProperties.__boundDepthTexture; 12908 delete renderTargetProperties.__depthDisposeCallback; 12909 depthTexture.removeEventListener( 'dispose', disposeEvent ); 12910 12911 }; 12912 12913 depthTexture.addEventListener( 'dispose', disposeEvent ); 12914 renderTargetProperties.__depthDisposeCallback = disposeEvent; 12915 12916 } 12917 12918 renderTargetProperties.__boundDepthTexture = depthTexture; 12919 12920 } 12921 12922 if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) { 12923 12924 if ( isCube ) { 12925 12926 // For cube render targets with depth texture, setup each face 12927 for ( let i = 0; i < 6; i ++ ) { 12928 12929 setupDepthTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, i ); 12930 12931 } 12932 12933 } else { 12934 12935 const mipmaps = renderTarget.texture.mipmaps; 12936 12937 if ( mipmaps && mipmaps.length > 0 ) { 12938 12939 setupDepthTexture( renderTargetProperties.__webglFramebuffer[ 0 ], renderTarget, 0 ); 12940 12941 } else { 12942 12943 setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget, 0 ); 12944 12945 } 12946 12947 } 12948 12949 } else { 12950 12951 if ( isCube ) { 12952 12953 renderTargetProperties.__webglDepthbuffer = []; 12954 12955 for ( let i = 0; i < 6; i ++ ) { 12956 12957 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); 12958 12959 if ( renderTargetProperties.__webglDepthbuffer[ i ] === undefined ) { 12960 12961 renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); 12962 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); 12963 12964 } else { 12965 12966 // attach buffer if it's been created already 12967 const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 12968 const renderbuffer = renderTargetProperties.__webglDepthbuffer[ i ]; 12969 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); 12970 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer ); 12971 12972 } 12973 12974 } 12975 12976 } else { 12977 12978 const mipmaps = renderTarget.texture.mipmaps; 12979 12980 if ( mipmaps && mipmaps.length > 0 ) { 12981 12982 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ 0 ] ); 12983 12984 } else { 12985 12986 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 12987 12988 } 12989 12990 if ( renderTargetProperties.__webglDepthbuffer === undefined ) { 12991 12992 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); 12993 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); 12994 12995 } else { 12996 12997 // attach buffer if it's been created already 12998 const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 12999 const renderbuffer = renderTargetProperties.__webglDepthbuffer; 13000 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); 13001 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer ); 13002 13003 } 13004 13005 } 13006 13007 } 13008 13009 state.bindFramebuffer( _gl.FRAMEBUFFER, null ); 13010 13011 } 13012 13013 // rebind framebuffer with external textures 13014 function rebindTextures( renderTarget, colorTexture, depthTexture ) { 13015 13016 const renderTargetProperties = properties.get( renderTarget ); 13017 13018 if ( colorTexture !== undefined ) { 13019 13020 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 ); 13021 13022 } 13023 13024 if ( depthTexture !== undefined ) { 13025 13026 setupDepthRenderbuffer( renderTarget ); 13027 13028 } 13029 13030 } 13031 13032 // Set up GL resources for the render target 13033 function setupRenderTarget( renderTarget ) { 13034 13035 const texture = renderTarget.texture; 13036 13037 const renderTargetProperties = properties.get( renderTarget ); 13038 const textureProperties = properties.get( texture ); 13039 13040 renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); 13041 13042 const textures = renderTarget.textures; 13043 13044 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); 13045 const isMultipleRenderTargets = ( textures.length > 1 ); 13046 13047 if ( ! isMultipleRenderTargets ) { 13048 13049 if ( textureProperties.__webglTexture === undefined ) { 13050 13051 textureProperties.__webglTexture = _gl.createTexture(); 13052 13053 } 13054 13055 textureProperties.__version = texture.version; 13056 info.memory.textures ++; 13057 13058 } 13059 13060 // Setup framebuffer 13061 13062 if ( isCube ) { 13063 13064 renderTargetProperties.__webglFramebuffer = []; 13065 13066 for ( let i = 0; i < 6; i ++ ) { 13067 13068 if ( texture.mipmaps && texture.mipmaps.length > 0 ) { 13069 13070 renderTargetProperties.__webglFramebuffer[ i ] = []; 13071 13072 for ( let level = 0; level < texture.mipmaps.length; level ++ ) { 13073 13074 renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer(); 13075 13076 } 13077 13078 } else { 13079 13080 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); 13081 13082 } 13083 13084 } 13085 13086 } else { 13087 13088 if ( texture.mipmaps && texture.mipmaps.length > 0 ) { 13089 13090 renderTargetProperties.__webglFramebuffer = []; 13091 13092 for ( let level = 0; level < texture.mipmaps.length; level ++ ) { 13093 13094 renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer(); 13095 13096 } 13097 13098 } else { 13099 13100 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); 13101 13102 } 13103 13104 if ( isMultipleRenderTargets ) { 13105 13106 for ( let i = 0, il = textures.length; i < il; i ++ ) { 13107 13108 const attachmentProperties = properties.get( textures[ i ] ); 13109 13110 if ( attachmentProperties.__webglTexture === undefined ) { 13111 13112 attachmentProperties.__webglTexture = _gl.createTexture(); 13113 13114 info.memory.textures ++; 13115 13116 } 13117 13118 } 13119 13120 } 13121 13122 if ( ( renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { 13123 13124 renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); 13125 renderTargetProperties.__webglColorRenderbuffer = []; 13126 13127 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 13128 13129 for ( let i = 0; i < textures.length; i ++ ) { 13130 13131 const texture = textures[ i ]; 13132 renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer(); 13133 13134 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); 13135 13136 const glFormat = utils.convert( texture.format, texture.colorSpace ); 13137 const glType = utils.convert( texture.type ); 13138 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace, renderTarget.isXRRenderTarget === true ); 13139 const samples = getRenderTargetSamples( renderTarget ); 13140 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); 13141 13142 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); 13143 13144 } 13145 13146 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); 13147 13148 if ( renderTarget.depthBuffer ) { 13149 13150 renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); 13151 setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true ); 13152 13153 } 13154 13155 state.bindFramebuffer( _gl.FRAMEBUFFER, null ); 13156 13157 } 13158 13159 } 13160 13161 // Setup color buffer 13162 13163 if ( isCube ) { 13164 13165 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); 13166 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture ); 13167 13168 for ( let i = 0; i < 6; i ++ ) { 13169 13170 if ( texture.mipmaps && texture.mipmaps.length > 0 ) { 13171 13172 for ( let level = 0; level < texture.mipmaps.length; level ++ ) { 13173 13174 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ][ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level ); 13175 13176 } 13177 13178 } else { 13179 13180 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0 ); 13181 13182 } 13183 13184 } 13185 13186 if ( textureNeedsGenerateMipmaps( texture ) ) { 13187 13188 generateMipmap( _gl.TEXTURE_CUBE_MAP ); 13189 13190 } 13191 13192 state.unbindTexture(); 13193 13194 } else if ( isMultipleRenderTargets ) { 13195 13196 for ( let i = 0, il = textures.length; i < il; i ++ ) { 13197 13198 const attachment = textures[ i ]; 13199 const attachmentProperties = properties.get( attachment ); 13200 13201 let glTextureType = _gl.TEXTURE_2D; 13202 13203 if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { 13204 13205 glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; 13206 13207 } 13208 13209 state.bindTexture( glTextureType, attachmentProperties.__webglTexture ); 13210 setTextureParameters( glTextureType, attachment ); 13211 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, glTextureType, 0 ); 13212 13213 if ( textureNeedsGenerateMipmaps( attachment ) ) { 13214 13215 generateMipmap( glTextureType ); 13216 13217 } 13218 13219 } 13220 13221 state.unbindTexture(); 13222 13223 } else { 13224 13225 let glTextureType = _gl.TEXTURE_2D; 13226 13227 if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { 13228 13229 glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; 13230 13231 } 13232 13233 state.bindTexture( glTextureType, textureProperties.__webglTexture ); 13234 setTextureParameters( glTextureType, texture ); 13235 13236 if ( texture.mipmaps && texture.mipmaps.length > 0 ) { 13237 13238 for ( let level = 0; level < texture.mipmaps.length; level ++ ) { 13239 13240 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level ); 13241 13242 } 13243 13244 } else { 13245 13246 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 ); 13247 13248 } 13249 13250 if ( textureNeedsGenerateMipmaps( texture ) ) { 13251 13252 generateMipmap( glTextureType ); 13253 13254 } 13255 13256 state.unbindTexture(); 13257 13258 } 13259 13260 // Setup depth and stencil buffers 13261 13262 if ( renderTarget.depthBuffer ) { 13263 13264 setupDepthRenderbuffer( renderTarget ); 13265 13266 } 13267 13268 } 13269 13270 function updateRenderTargetMipmap( renderTarget ) { 13271 13272 const textures = renderTarget.textures; 13273 13274 for ( let i = 0, il = textures.length; i < il; i ++ ) { 13275 13276 const texture = textures[ i ]; 13277 13278 if ( textureNeedsGenerateMipmaps( texture ) ) { 13279 13280 const targetType = getTargetType( renderTarget ); 13281 const webglTexture = properties.get( texture ).__webglTexture; 13282 13283 state.bindTexture( targetType, webglTexture ); 13284 generateMipmap( targetType ); 13285 state.unbindTexture(); 13286 13287 } 13288 13289 } 13290 13291 } 13292 13293 const invalidationArrayRead = []; 13294 const invalidationArrayDraw = []; 13295 13296 function updateMultisampleRenderTarget( renderTarget ) { 13297 13298 if ( renderTarget.samples > 0 ) { 13299 13300 if ( useMultisampledRTT( renderTarget ) === false ) { 13301 13302 const textures = renderTarget.textures; 13303 const width = renderTarget.width; 13304 const height = renderTarget.height; 13305 let mask = _gl.COLOR_BUFFER_BIT; 13306 const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 13307 const renderTargetProperties = properties.get( renderTarget ); 13308 const isMultipleRenderTargets = ( textures.length > 1 ); 13309 13310 // If MRT we need to remove FBO attachments 13311 if ( isMultipleRenderTargets ) { 13312 13313 for ( let i = 0; i < textures.length; i ++ ) { 13314 13315 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 13316 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null ); 13317 13318 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 13319 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 ); 13320 13321 } 13322 13323 } 13324 13325 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 13326 13327 const mipmaps = renderTarget.texture.mipmaps; 13328 13329 if ( mipmaps && mipmaps.length > 0 ) { 13330 13331 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ 0 ] ); 13332 13333 } else { 13334 13335 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 13336 13337 } 13338 13339 for ( let i = 0; i < textures.length; i ++ ) { 13340 13341 if ( renderTarget.resolveDepthBuffer ) { 13342 13343 if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT; 13344 13345 // resolving stencil is slow with a D3D backend. disable it for all transmission render targets (see #27799) 13346 13347 if ( renderTarget.stencilBuffer && renderTarget.resolveStencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT; 13348 13349 } 13350 13351 if ( isMultipleRenderTargets ) { 13352 13353 _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); 13354 13355 const webglTexture = properties.get( textures[ i ] ).__webglTexture; 13356 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 ); 13357 13358 } 13359 13360 _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST ); 13361 13362 if ( supportsInvalidateFramebuffer === true ) { 13363 13364 invalidationArrayRead.length = 0; 13365 invalidationArrayDraw.length = 0; 13366 13367 invalidationArrayRead.push( _gl.COLOR_ATTACHMENT0 + i ); 13368 13369 if ( renderTarget.depthBuffer && renderTarget.storeMultisampledDepthBuffer === false ) { 13370 13371 invalidationArrayRead.push( depthStyle ); 13372 invalidationArrayDraw.push( depthStyle ); 13373 13374 _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, invalidationArrayDraw ); 13375 13376 } 13377 13378 _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArrayRead ); 13379 13380 } 13381 13382 } 13383 13384 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null ); 13385 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null ); 13386 13387 // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments 13388 if ( isMultipleRenderTargets ) { 13389 13390 for ( let i = 0; i < textures.length; i ++ ) { 13391 13392 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 13393 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); 13394 13395 const webglTexture = properties.get( textures[ i ] ).__webglTexture; 13396 13397 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 13398 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 ); 13399 13400 } 13401 13402 } 13403 13404 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 13405 13406 } else { 13407 13408 if ( renderTarget.depthBuffer && renderTarget.storeMultisampledDepthBuffer === false && supportsInvalidateFramebuffer ) { 13409 13410 const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 13411 13412 _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] ); 13413 13414 } 13415 13416 } 13417 13418 } 13419 13420 } 13421 13422 function getRenderTargetSamples( renderTarget ) { 13423 13424 return Math.min( capabilities.maxSamples, renderTarget.samples ); 13425 13426 } 13427 13428 function useMultisampledRTT( renderTarget ) { 13429 13430 const renderTargetProperties = properties.get( renderTarget ); 13431 13432 return renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false; 13433 13434 } 13435 13436 function updateVideoTexture( texture ) { 13437 13438 const frame = info.render.frame; 13439 13440 // Check the last frame we updated the VideoTexture 13441 13442 if ( _videoTextures.get( texture ) !== frame ) { 13443 13444 _videoTextures.set( texture, frame ); 13445 texture.update(); 13446 13447 } 13448 13449 } 13450 13451 function verifyColorSpace( texture, image ) { 13452 13453 const colorSpace = texture.colorSpace; 13454 const format = texture.format; 13455 const type = texture.type; 13456 13457 if ( texture.isCompressedTexture === true || texture.isVideoTexture === true ) return image; 13458 13459 if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) { 13460 13461 // sRGB 13462 13463 if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) { 13464 13465 // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format 13466 13467 if ( format !== RGBAFormat || type !== UnsignedByteType ) { 13468 13469 warn( 'WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' ); 13470 13471 } 13472 13473 } else { 13474 13475 error( 'WebGLTextures: Unsupported texture color space:', colorSpace ); 13476 13477 } 13478 13479 } 13480 13481 return image; 13482 13483 } 13484 13485 function getDimensions( image ) { 13486 13487 if ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) { 13488 13489 // if intrinsic data are not available, fallback to width/height 13490 13491 _imageDimensions.width = image.naturalWidth || image.width; 13492 _imageDimensions.height = image.naturalHeight || image.height; 13493 13494 } else if ( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) { 13495 13496 _imageDimensions.width = image.displayWidth; 13497 _imageDimensions.height = image.displayHeight; 13498 13499 } else { 13500 13501 _imageDimensions.width = image.width; 13502 _imageDimensions.height = image.height; 13503 13504 } 13505 13506 return _imageDimensions; 13507 13508 } 13509 13510 // 13511 13512 this.allocateTextureUnit = allocateTextureUnit; 13513 this.resetTextureUnits = resetTextureUnits; 13514 this.getTextureUnits = getTextureUnits; 13515 this.setTextureUnits = setTextureUnits; 13516 13517 this.setTexture2D = setTexture2D; 13518 this.setTexture2DArray = setTexture2DArray; 13519 this.setTexture3D = setTexture3D; 13520 this.setTextureCube = setTextureCube; 13521 this.rebindTextures = rebindTextures; 13522 this.setupRenderTarget = setupRenderTarget; 13523 this.updateRenderTargetMipmap = updateRenderTargetMipmap; 13524 this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; 13525 this.setupDepthRenderbuffer = setupDepthRenderbuffer; 13526 this.setupFrameBufferTexture = setupFrameBufferTexture; 13527 this.useMultisampledRTT = useMultisampledRTT; 13528 13529 this.isReversedDepthBuffer = function () { 13530 13531 return state.buffers.depth.getReversed(); 13532 13533 }; 13534 13535} 13536 13537function WebGLUtils( gl, extensions ) { 13538 13539 function convert( p, colorSpace = NoColorSpace ) { 13540 13541 let extension; 13542 13543 const transfer = ColorManagement.getTransfer( colorSpace ); 13544 13545 if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE; 13546 if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4; 13547 if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1; 13548 if ( p === UnsignedInt5999Type ) return gl.UNSIGNED_INT_5_9_9_9_REV; 13549 if ( p === UnsignedInt101111Type ) return gl.UNSIGNED_INT_10F_11F_11F_REV; 13550 13551 if ( p === ByteType ) return gl.BYTE; 13552 if ( p === ShortType ) return gl.SHORT; 13553 if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT; 13554 if ( p === IntType ) return gl.INT; 13555 if ( p === UnsignedIntType ) return gl.UNSIGNED_INT; 13556 if ( p === FloatType ) return gl.FLOAT; 13557 if ( p === HalfFloatType ) return gl.HALF_FLOAT; 13558 13559 if ( p === AlphaFormat ) return gl.ALPHA; 13560 if ( p === RGBFormat ) return gl.RGB; 13561 if ( p === RGBAFormat ) return gl.RGBA; 13562 if ( p === DepthFormat ) return gl.DEPTH_COMPONENT; 13563 if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL; 13564 13565 // WebGL2 formats. 13566 13567 if ( p === RedFormat ) return gl.RED; 13568 if ( p === RedIntegerFormat ) return gl.RED_INTEGER; 13569 if ( p === RGFormat ) return gl.RG; 13570 if ( p === RGIntegerFormat ) return gl.RG_INTEGER; 13571 if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER; 13572 13573 // S3TC 13574 13575 if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { 13576 13577 if ( transfer === SRGBTransfer ) { 13578 13579 extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); 13580 13581 if ( extension !== null ) { 13582 13583 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; 13584 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; 13585 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; 13586 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; 13587 13588 } else { 13589 13590 return null; 13591 13592 } 13593 13594 } else { 13595 13596 extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); 13597 13598 if ( extension !== null ) { 13599 13600 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; 13601 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; 13602 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; 13603 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; 13604 13605 } else { 13606 13607 return null; 13608 13609 } 13610 13611 } 13612 13613 } 13614 13615 // PVRTC 13616 13617 if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { 13618 13619 extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); 13620 13621 if ( extension !== null ) { 13622 13623 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; 13624 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; 13625 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; 13626 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; 13627 13628 } else { 13629 13630 return null; 13631 13632 } 13633 13634 } 13635 13636 // ETC 13637 13638 if ( p === RGB_ETC1_Format || p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format || p === R11_EAC_Format || p === SIGNED_R11_EAC_Format || p === RG11_EAC_Format || p === SIGNED_RG11_EAC_Format ) { 13639 13640 extension = extensions.get( 'WEBGL_compressed_texture_etc' ); 13641 13642 if ( extension !== null ) { 13643 13644 if ( p === RGB_ETC1_Format || p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; 13645 if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; 13646 if ( p === R11_EAC_Format ) return extension.COMPRESSED_R11_EAC; 13647 if ( p === SIGNED_R11_EAC_Format ) return extension.COMPRESSED_SIGNED_R11_EAC; 13648 if ( p === RG11_EAC_Format ) return extension.COMPRESSED_RG11_EAC; 13649 if ( p === SIGNED_RG11_EAC_Format ) return extension.COMPRESSED_SIGNED_RG11_EAC; 13650 13651 } else { 13652 13653 return null; 13654 13655 } 13656 13657 } 13658 13659 // ASTC 13660 13661 if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || 13662 p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || 13663 p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || 13664 p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || 13665 p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) { 13666 13667 extension = extensions.get( 'WEBGL_compressed_texture_astc' ); 13668 13669 if ( extension !== null ) { 13670 13671 if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; 13672 if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; 13673 if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; 13674 if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; 13675 if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; 13676 if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; 13677 if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; 13678 if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; 13679 if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; 13680 if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; 13681 if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; 13682 if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; 13683 if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; 13684 if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; 13685 13686 } else { 13687 13688 return null; 13689 13690 } 13691 13692 } 13693 13694 // BPTC 13695 13696 if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) { 13697 13698 extension = extensions.get( 'EXT_texture_compression_bptc' ); 13699 13700 if ( extension !== null ) { 13701 13702 if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; 13703 if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; 13704 if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; 13705 13706 } else { 13707 13708 return null; 13709 13710 } 13711 13712 } 13713 13714 // RGTC 13715 13716 if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) { 13717 13718 extension = extensions.get( 'EXT_texture_compression_rgtc' ); 13719 13720 if ( extension !== null ) { 13721 13722 if ( p === RED_RGTC1_Format ) return extension.COMPRESSED_RED_RGTC1_EXT; 13723 if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; 13724 if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; 13725 if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; 13726 13727 } else { 13728 13729 return null; 13730 13731 } 13732 13733 } 13734 13735 // 13736 13737 if ( p === UnsignedInt248Type ) return gl.UNSIGNED_INT_24_8; 13738 13739 // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats) 13740 13741 return ( gl[ p ] !== undefined ) ? gl[ p ] : null; 13742 13743 } 13744 13745 return { convert: convert }; 13746 13747} 13748 13749const _occlusion_vertex = ` 13750void main() { 13751 13752 gl_Position = vec4( position, 1.0 ); 13753 13754}`; 13755 13756const _occlusion_fragment = ` 13757uniform sampler2DArray depthColor; 13758uniform float depthWidth; 13759uniform float depthHeight; 13760 13761void main() { 13762 13763 vec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight ); 13764 13765 if ( coord.x >= 1.0 ) { 13766 13767 gl_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r; 13768 13769 } else { 13770 13771 gl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r; 13772 13773 } 13774 13775}`; 13776 13777/** 13778 * A XR module that manages the access to the Depth Sensing API. 13779 */ 13780class WebXRDepthSensing { 13781 13782 /** 13783 * Constructs a new depth sensing module. 13784 */ 13785 constructor() { 13786 13787 /** 13788 * An opaque texture representing the depth of the user's environment. 13789 * 13790 * @type {?ExternalTexture} 13791 */ 13792 this.texture = null; 13793 13794 /** 13795 * A plane mesh for visualizing the depth texture. 13796 * 13797 * @type {?Mesh} 13798 */ 13799 this.mesh = null; 13800 13801 /** 13802 * The depth near value. 13803 * 13804 * @type {number} 13805 */ 13806 this.depthNear = 0; 13807 13808 /** 13809 * The depth near far. 13810 * 13811 * @type {number} 13812 */ 13813 this.depthFar = 0; 13814 13815 } 13816 13817 /** 13818 * Inits the depth sensing module 13819 * 13820 * @param {XRWebGLDepthInformation} depthData - The XR depth data. 13821 * @param {XRRenderState} renderState - The XR render state. 13822 */ 13823 init( depthData, renderState ) { 13824 13825 if ( this.texture === null ) { 13826 13827 const texture = new ExternalTexture( depthData.texture ); 13828 13829 if ( ( depthData.depthNear !== renderState.depthNear ) || ( depthData.depthFar !== renderState.depthFar ) ) { 13830 13831 this.depthNear = depthData.depthNear; 13832 this.depthFar = depthData.depthFar; 13833 13834 } 13835 13836 this.texture = texture; 13837 13838 } 13839 13840 } 13841 13842 /** 13843 * Returns a plane mesh that visualizes the depth texture. 13844 * 13845 * @param {ArrayCamera} cameraXR - The XR camera. 13846 * @return {?Mesh} The plane mesh. 13847 */ 13848 getMesh( cameraXR ) { 13849 13850 if ( this.texture !== null ) { 13851 13852 if ( this.mesh === null ) { 13853 13854 const viewport = cameraXR.cameras[ 0 ].viewport; 13855 const material = new ShaderMaterial( { 13856 vertexShader: _occlusion_vertex, 13857 fragmentShader: _occlusion_fragment, 13858 uniforms: { 13859 depthColor: { value: this.texture }, 13860 depthWidth: { value: viewport.z }, 13861 depthHeight: { value: viewport.w } 13862 } 13863 } ); 13864 13865 this.mesh = new Mesh( new PlaneGeometry( 20, 20 ), material ); 13866 13867 } 13868 13869 } 13870 13871 return this.mesh; 13872 13873 } 13874 13875 /** 13876 * Resets the module 13877 */ 13878 reset() { 13879 13880 this.texture = null; 13881 this.mesh = null; 13882 13883 } 13884 13885 /** 13886 * Returns a texture representing the depth of the user's environment. 13887 * 13888 * @return {?ExternalTexture} The depth texture. 13889 */ 13890 getDepthTexture() { 13891 13892 return this.texture; 13893 13894 } 13895 13896} 13897 13898/** 13899 * This class represents an abstraction of the WebXR Device API and is 13900 * internally used by {@link WebGLRenderer}. `WebXRManager` also provides a public 13901 * interface that allows users to enable/disable XR and perform XR related 13902 * tasks like for instance retrieving controllers. 13903 * 13904 * @augments EventDispatcher 13905 * @hideconstructor 13906 */ 13907class WebXRManager extends EventDispatcher { 13908 13909 /** 13910 * Constructs a new WebGL renderer. 13911 * 13912 * @param {WebGLRenderer} renderer - The renderer. 13913 * @param {WebGL2RenderingContext} gl - The rendering context. 13914 */ 13915 constructor( renderer, gl ) { 13916 13917 super(); 13918 13919 const scope = this; 13920 13921 let session = null; 13922 13923 let framebufferScaleFactor = 1.0; 13924 13925 let referenceSpace = null; 13926 let referenceSpaceType = 'local-floor'; 13927 // Set default foveation to maximum. 13928 let foveation = 1.0; 13929 let customReferenceSpace = null; 13930 13931 let pose = null; 13932 let glBinding = null; 13933 let glProjLayer = null; 13934 let glBaseLayer = null; 13935 let xrFrame = null; 13936 13937 const supportsGlBinding = typeof XRWebGLBinding !== 'undefined'; 13938 13939 const depthSensing = new WebXRDepthSensing(); 13940 const cameraAccessTextures = {}; 13941 const attributes = gl.getContextAttributes(); 13942 13943 let initialRenderTarget = null; 13944 let newRenderTarget = null; 13945 13946 const controllers = []; 13947 const controllerInputSources = []; 13948 13949 const currentSize = new Vector2(); 13950 let currentPixelRatio = null; 13951 let currentCameraSettings = null; 13952 13953 // 13954 13955 const cameraL = new PerspectiveCamera(); 13956 cameraL.viewport = new Vector4(); 13957 13958 const cameraR = new PerspectiveCamera(); 13959 cameraR.viewport = new Vector4(); 13960 13961 const cameras = [ cameraL, cameraR ]; 13962 13963 const cameraXR = new ArrayCamera(); 13964 13965 let _currentDepthNear = null; 13966 let _currentDepthFar = null; 13967 13968 // 13969 13970 /** 13971 * Whether the manager's XR camera should be automatically updated or not. 13972 * 13973 * @type {boolean} 13974 * @default true 13975 */ 13976 this.cameraAutoUpdate = true; 13977 13978 /** 13979 * This flag notifies the renderer to be ready for XR rendering. Set it to `true` 13980 * if you are going to use XR in your app. 13981 * 13982 * @type {boolean} 13983 * @default false 13984 */ 13985 this.enabled = false; 13986 13987 /** 13988 * Whether XR presentation is active or not. 13989 * 13990 * @type {boolean} 13991 * @readonly 13992 * @default false 13993 */ 13994 this.isPresenting = false; 13995 13996 /** 13997 * Returns a group representing the `target ray` space of the XR controller. 13998 * Use this space for visualizing 3D objects that support the user in pointing 13999 * tasks like UI interaction. 14000 * 14001 * @param {number} index - The index of the controller. 14002 * @return {Group} A group representing the `target ray` space. 14003 */ 14004 this.getController = function ( index ) { 14005 14006 let controller = controllers[ index ]; 14007 14008 if ( controller === undefined ) { 14009 14010 controller = new WebXRController(); 14011 controllers[ index ] = controller; 14012 14013 } 14014 14015 return controller.getTargetRaySpace(); 14016 14017 }; 14018 14019 /** 14020 * Returns a group representing the `grip` space of the XR controller. 14021 * Use this space for visualizing 3D objects that support the user in pointing 14022 * tasks like UI interaction. 14023 * 14024 * Note: If you want to show something in the user's hand AND offer a 14025 * pointing ray at the same time, you'll want to attached the handheld object 14026 * to the group returned by `getControllerGrip()` and the ray to the 14027 * group returned by `getController()`. The idea is to have two 14028 * different groups in two different coordinate spaces for the same WebXR 14029 * controller. 14030 * 14031 * @param {number} index - The index of the controller. 14032 * @return {Group} A group representing the `grip` space. 14033 */ 14034 this.getControllerGrip = function ( index ) { 14035 14036 let controller = controllers[ index ]; 14037 14038 if ( controller === undefined ) { 14039 14040 controller = new WebXRController(); 14041 controllers[ index ] = controller; 14042 14043 } 14044 14045 return controller.getGripSpace(); 14046 14047 }; 14048 14049 /** 14050 * Returns a group representing the `hand` space of the XR controller. 14051 * Use this space for visualizing 3D objects that support the user in pointing 14052 * tasks like UI interaction. 14053 * 14054 * @param {number} index - The index of the controller. 14055 * @return {Group} A group representing the `hand` space. 14056 */ 14057 this.getHand = function ( index ) { 14058 14059 let controller = controllers[ index ]; 14060 14061 if ( controller === undefined ) { 14062 14063 controller = new WebXRController(); 14064 controllers[ index ] = controller; 14065 14066 } 14067 14068 return controller.getHandSpace(); 14069 14070 }; 14071 14072 // 14073 14074 function onSessionEvent( event ) { 14075 14076 const controllerIndex = controllerInputSources.indexOf( event.inputSource ); 14077 14078 if ( controllerIndex === -1 ) { 14079 14080 return; 14081 14082 } 14083 14084 const controller = controllers[ controllerIndex ]; 14085 14086 if ( controller !== undefined ) { 14087 14088 controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace ); 14089 controller.dispatchEvent( { type: event.type, data: event.inputSource } ); 14090 14091 } 14092 14093 } 14094 14095 function onSessionEnd() { 14096 14097 session.removeEventListener( 'select', onSessionEvent ); 14098 session.removeEventListener( 'selectstart', onSessionEvent ); 14099 session.removeEventListener( 'selectend', onSessionEvent ); 14100 session.removeEventListener( 'squeeze', onSessionEvent ); 14101 session.removeEventListener( 'squeezestart', onSessionEvent ); 14102 session.removeEventListener( 'squeezeend', onSessionEvent ); 14103 session.removeEventListener( 'end', onSessionEnd ); 14104 session.removeEventListener( 'inputsourceschange', onInputSourcesChange ); 14105 14106 for ( let i = 0; i < controllers.length; i ++ ) { 14107 14108 const inputSource = controllerInputSources[ i ]; 14109 14110 if ( inputSource === null ) continue; 14111 14112 controllerInputSources[ i ] = null; 14113 14114 controllers[ i ].disconnect( inputSource ); 14115 14116 } 14117 14118 _currentDepthNear = null; 14119 _currentDepthFar = null; 14120 14121 depthSensing.reset(); 14122 for ( const key in cameraAccessTextures ) { 14123 14124 delete cameraAccessTextures[ key ]; 14125 14126 } 14127 14128 // restore framebuffer/rendering state 14129 14130 renderer.setRenderTarget( initialRenderTarget ); 14131 14132 glBaseLayer = null; 14133 glProjLayer = null; 14134 glBinding = null; 14135 session = null; 14136 newRenderTarget = null; 14137 14138 // 14139 14140 animation.stop(); 14141 14142 scope.isPresenting = false; 14143 14144 renderer.setPixelRatio( currentPixelRatio ); 14145 renderer.setSize( currentSize.width, currentSize.height, false ); 14146 14147 if ( currentCameraSettings !== null ) { 14148 14149 const camera = currentCameraSettings.camera; 14150 14151 camera.fov = currentCameraSettings.fov; 14152 camera.zoom = currentCameraSettings.zoom; 14153 camera.updateProjectionMatrix(); 14154 14155 currentCameraSettings = null; 14156 14157 } 14158 14159 scope.dispatchEvent( { type: 'sessionend' } ); 14160 14161 } 14162 14163 /** 14164 * Sets the framebuffer scale factor. 14165 * 14166 * This method can not be used during a XR session. 14167 * 14168 * @param {number} value - The framebuffer scale factor. 14169 */ 14170 this.setFramebufferScaleFactor = function ( value ) { 14171 14172 framebufferScaleFactor = value; 14173 14174 if ( scope.isPresenting === true ) { 14175 14176 warn( 'WebXRManager: Cannot change framebuffer scale while presenting.' ); 14177 14178 } 14179 14180 }; 14181 14182 /** 14183 * Sets the reference space type. Can be used to configure a spatial relationship with the user's physical 14184 * environment. Depending on how the user moves in 3D space, setting an appropriate reference space can 14185 * improve tracking. Default is `local-floor`. Valid values can be found here 14186 * https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpace#reference_space_types. 14187 * 14188 * This method can not be used during a XR session. 14189 * 14190 * @param {string} value - The reference space type. 14191 */ 14192 this.setReferenceSpaceType = function ( value ) { 14193 14194 referenceSpaceType = value; 14195 14196 if ( scope.isPresenting === true ) { 14197 14198 warn( 'WebXRManager: Cannot change reference space type while presenting.' ); 14199 14200 } 14201 14202 }; 14203 14204 /** 14205 * Returns the XR reference space. 14206 * 14207 * @return {XRReferenceSpace} The XR reference space. 14208 */ 14209 this.getReferenceSpace = function () { 14210 14211 return customReferenceSpace || referenceSpace; 14212 14213 }; 14214 14215 /** 14216 * Sets a custom XR reference space. 14217 * 14218 * @param {XRReferenceSpace} space - The XR reference space. 14219 */ 14220 this.setReferenceSpace = function ( space ) { 14221 14222 customReferenceSpace = space; 14223 14224 }; 14225 14226 /** 14227 * Returns the current base layer. 14228 * 14229 * This is an `XRProjectionLayer` when the targeted XR device supports the 14230 * WebXR Layers API, or an `XRWebGLLayer` otherwise. 14231 * 14232 * @return {?(XRWebGLLayer|XRProjectionLayer)} The XR base layer. 14233 */ 14234 this.getBaseLayer = function () { 14235 14236 return glProjLayer !== null ? glProjLayer : glBaseLayer; 14237 14238 }; 14239 14240 /** 14241 * Returns the current XR binding. 14242 * 14243 * Creates a new binding if needed and the browser is 14244 * capable of doing so. 14245 * 14246 * @return {?XRWebGLBinding} The XR binding. Returns `null` if one cannot be created. 14247 */ 14248 this.getBinding = function () { 14249 14250 if ( glBinding === null && supportsGlBinding ) { 14251 14252 glBinding = new XRWebGLBinding( session, gl ); 14253 14254 } 14255 14256 return glBinding; 14257 14258 }; 14259 14260 /** 14261 * Returns the current XR frame. 14262 * 14263 * @return {?XRFrame} The XR frame. Returns `null` when used outside a XR session. 14264 */ 14265 this.getFrame = function () { 14266 14267 return xrFrame; 14268 14269 }; 14270 14271 /** 14272 * Returns the current XR session. 14273 * 14274 * @return {?XRSession} The XR session. Returns `null` when used outside a XR session. 14275 */ 14276 this.getSession = function () { 14277 14278 return session; 14279 14280 }; 14281 14282 /** 14283 * After a XR session has been requested usually with one of the `*Button` modules, it 14284 * is injected into the renderer with this method. This method triggers the start of 14285 * the actual XR rendering. 14286 * 14287 * @async 14288 * @param {XRSession} value - The XR session to set. 14289 * @return {Promise} A Promise that resolves when the session has been set. 14290 */ 14291 this.setSession = async function ( value ) { 14292 14293 session = value; 14294 14295 if ( session !== null ) { 14296 14297 initialRenderTarget = renderer.getRenderTarget(); 14298 14299 session.addEventListener( 'select', onSessionEvent ); 14300 session.addEventListener( 'selectstart', onSessionEvent ); 14301 session.addEventListener( 'selectend', onSessionEvent ); 14302 session.addEventListener( 'squeeze', onSessionEvent ); 14303 session.addEventListener( 'squeezestart', onSessionEvent ); 14304 session.addEventListener( 'squeezeend', onSessionEvent ); 14305 session.addEventListener( 'end', onSessionEnd ); 14306 session.addEventListener( 'inputsourceschange', onInputSourcesChange ); 14307 14308 if ( attributes.xrCompatible !== true ) { 14309 14310 await gl.makeXRCompatible(); 14311 14312 } 14313 14314 currentPixelRatio = renderer.getPixelRatio(); 14315 renderer.getSize( currentSize ); 14316 14317 14318 // Check that the browser implements the necessary APIs to use an 14319 // XRProjectionLayer rather than an XRWebGLLayer 14320 const supportsLayers = supportsGlBinding && 'createProjectionLayer' in XRWebGLBinding.prototype; 14321 14322 if ( ! supportsLayers ) { 14323 14324 const layerInit = { 14325 antialias: attributes.antialias, 14326 alpha: true, 14327 depth: attributes.depth, 14328 stencil: attributes.stencil, 14329 framebufferScaleFactor: framebufferScaleFactor 14330 }; 14331 14332 glBaseLayer = new XRWebGLLayer( session, gl, layerInit ); 14333 14334 session.updateRenderState( { baseLayer: glBaseLayer } ); 14335 14336 renderer.setPixelRatio( 1 ); 14337 renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false ); 14338 14339 newRenderTarget = new WebGLRenderTarget( 14340 glBaseLayer.framebufferWidth, 14341 glBaseLayer.framebufferHeight, 14342 { 14343 format: RGBAFormat, 14344 type: UnsignedByteType, 14345 colorSpace: renderer.outputColorSpace, 14346 stencilBuffer: attributes.stencil, 14347 resolveDepthBuffer: ( glBaseLayer.ignoreDepthValues === false ), 14348 resolveStencilBuffer: ( glBaseLayer.ignoreDepthValues === false ), 14349 storeMultisampledDepthBuffer: ( glBaseLayer.ignoreDepthValues === false ), 14350 storeMultisampledStencilBuffer: ( glBaseLayer.ignoreDepthValues === false ) 14351 14352 } 14353 ); 14354 14355 } else { 14356 14357 let depthFormat = null; 14358 let depthType = null; 14359 let glDepthFormat = null; 14360 14361 if ( attributes.depth ) { 14362 14363 glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; 14364 depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; 14365 depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; 14366 14367 } 14368 14369 const projectionlayerInit = { 14370 colorFormat: gl.RGBA8, 14371 depthFormat: glDepthFormat, 14372 scaleFactor: framebufferScaleFactor 14373 }; 14374 14375 glBinding = this.getBinding(); 14376 14377 glProjLayer = glBinding.createProjectionLayer( projectionlayerInit ); 14378 14379 session.updateRenderState( { layers: [ glProjLayer ] } ); 14380 14381 renderer.setPixelRatio( 1 ); 14382 renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false ); 14383 14384 newRenderTarget = new WebGLRenderTarget( 14385 glProjLayer.textureWidth, 14386 glProjLayer.textureHeight, 14387 { 14388 format: RGBAFormat, 14389 type: UnsignedByteType, 14390 depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ), 14391 stencilBuffer: attributes.stencil, 14392 colorSpace: renderer.outputColorSpace, 14393 samples: attributes.antialias ? 4 : 0, 14394 resolveDepthBuffer: ( glProjLayer.ignoreDepthValues === false ), 14395 resolveStencilBuffer: ( glProjLayer.ignoreDepthValues === false ), 14396 storeMultisampledDepthBuffer: ( glProjLayer.ignoreDepthValues === false ), 14397 storeMultisampledStencilBuffer: ( glProjLayer.ignoreDepthValues === false ) 14398 } ); 14399 14400 } 14401 14402 newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 14403 14404 this.setFoveation( foveation ); 14405 14406 customReferenceSpace = null; 14407 referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); 14408 14409 animation.setContext( session ); 14410 animation.start(); 14411 14412 scope.isPresenting = true; 14413 14414 scope.dispatchEvent( { type: 'sessionstart' } ); 14415 14416 } 14417 14418 }; 14419 14420 /** 14421 * Returns the environment blend mode from the current XR session. 14422 * 14423 * @return {'opaque'|'additive'|'alpha-blend'|undefined} The environment blend mode. Returns `undefined` when used outside of a XR session. 14424 */ 14425 this.getEnvironmentBlendMode = function () { 14426 14427 if ( session !== null ) { 14428 14429 return session.environmentBlendMode; 14430 14431 } 14432 14433 }; 14434 14435 /** 14436 * Returns the current depth texture computed via depth sensing. 14437 * 14438 * See {@link WebXRDepthSensing#getDepthTexture}. 14439 * 14440 * @return {?Texture} The depth texture. 14441 */ 14442 this.getDepthTexture = function () { 14443 14444 return depthSensing.getDepthTexture(); 14445 14446 }; 14447 14448 function onInputSourcesChange( event ) { 14449 14450 // Notify disconnected 14451 14452 for ( let i = 0; i < event.removed.length; i ++ ) { 14453 14454 const inputSource = event.removed[ i ]; 14455 const index = controllerInputSources.indexOf( inputSource ); 14456 14457 if ( index >= 0 ) { 14458 14459 controllerInputSources[ index ] = null; 14460 controllers[ index ].disconnect( inputSource ); 14461 14462 } 14463 14464 } 14465 14466 // Notify connected 14467 14468 for ( let i = 0; i < event.added.length; i ++ ) { 14469 14470 const inputSource = event.added[ i ]; 14471 14472 let controllerIndex = controllerInputSources.indexOf( inputSource ); 14473 14474 if ( controllerIndex === -1 ) { 14475 14476 // Assign input source a controller that currently has no input source 14477 14478 for ( let i = 0; i < controllers.length; i ++ ) { 14479 14480 if ( i >= controllerInputSources.length ) { 14481 14482 controllerInputSources.push( inputSource ); 14483 controllerIndex = i; 14484 break; 14485 14486 } else if ( controllerInputSources[ i ] === null ) { 14487 14488 controllerInputSources[ i ] = inputSource; 14489 controllerIndex = i; 14490 break; 14491 14492 } 14493 14494 } 14495 14496 // If all controllers do currently receive input we ignore new ones 14497 14498 if ( controllerIndex === -1 ) break; 14499 14500 } 14501 14502 const controller = controllers[ controllerIndex ]; 14503 14504 if ( controller ) { 14505 14506 controller.connect( inputSource ); 14507 14508 } 14509 14510 } 14511 14512 } 14513 14514 // 14515 14516 const cameraLPos = new Vector3(); 14517 const cameraRPos = new Vector3(); 14518 14519 /** 14520 * Assumes 2 cameras that are parallel and share an X-axis, and that 14521 * the cameras' projection and world matrices have already been set. 14522 * And that near and far planes are identical for both cameras. 14523 * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765 14524 * 14525 * @param {ArrayCamera} camera - The camera to update. 14526 * @param {PerspectiveCamera} cameraL - The left camera. 14527 * @param {PerspectiveCamera} cameraR - The right camera. 14528 */ 14529 function setProjectionFromUnion( camera, cameraL, cameraR ) { 14530 14531 cameraLPos.setFromMatrixPosition( cameraL.matrixWorld ); 14532 cameraRPos.setFromMatrixPosition( cameraR.matrixWorld ); 14533 14534 const ipd = cameraLPos.distanceTo( cameraRPos ); 14535 14536 const projL = cameraL.projectionMatrix.elements; 14537 const projR = cameraR.projectionMatrix.elements; 14538 14539 // VR systems will have identical far and near planes, and 14540 // most likely identical top and bottom frustum extents. 14541 // Use the left camera for these values. 14542 const near = projL[ 14 ] / ( projL[ 10 ] - 1 ); 14543 const far = projL[ 14 ] / ( projL[ 10 ] + 1 ); 14544 const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ]; 14545 const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ]; 14546 14547 const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ]; 14548 const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ]; 14549 const left = near * leftFov; 14550 const right = near * rightFov; 14551 14552 // Calculate the new camera's position offset from the 14553 // left camera. xOffset should be roughly half `ipd`. 14554 const zOffset = ipd / ( - leftFov + rightFov ); 14555 const xOffset = zOffset * - leftFov; 14556 14557 // TODO: Better way to apply this offset? 14558 cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale ); 14559 camera.translateX( xOffset ); 14560 camera.translateZ( zOffset ); 14561 camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale ); 14562 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); 14563 14564 // Check if the projection uses an infinite far plane. 14565 if ( projL[ 10 ] === -1 ) { 14566 14567 // Use the projection matrix from the left eye. 14568 // The camera offset is sufficient to include the view volumes 14569 // of both eyes (assuming symmetric projections). 14570 camera.projectionMatrix.copy( cameraL.projectionMatrix ); 14571 camera.projectionMatrixInverse.copy( cameraL.projectionMatrixInverse ); 14572 14573 } else { 14574 14575 // Find the union of the frustum values of the cameras and scale 14576 // the values so that the near plane's position does not change in world space, 14577 // although must now be relative to the new union camera. 14578 const near2 = near + zOffset; 14579 const far2 = far + zOffset; 14580 const left2 = left - xOffset; 14581 const right2 = right + ( ipd - xOffset ); 14582 const top2 = topFov * far / far2 * near2; 14583 const bottom2 = bottomFov * far / far2 * near2; 14584 14585 camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); 14586 camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); 14587 14588 } 14589 14590 } 14591 14592 function updateCamera( camera, parent ) { 14593 14594 if ( parent === null ) { 14595 14596 camera.matrixWorld.copy( camera.matrix ); 14597 14598 } else { 14599 14600 camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); 14601 14602 } 14603 14604 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); 14605 14606 } 14607 14608 /** 14609 * Updates the state of the XR camera. Use this method on app level if you 14610 * set `cameraAutoUpdate` to `false`. The method requires the non-XR 14611 * camera of the scene as a parameter. The passed in camera's transformation 14612 * is automatically adjusted to the position of the XR camera when calling 14613 * this method. 14614 * 14615 * @param {Camera} camera - The camera. 14616 */ 14617 this.updateCamera = function ( camera ) { 14618 14619 if ( session === null ) return; 14620 14621 let depthNear = camera.near; 14622 let depthFar = camera.far; 14623 14624 if ( depthSensing.texture !== null ) { 14625 14626 if ( depthSensing.depthNear > 0 ) depthNear = depthSensing.depthNear; 14627 if ( depthSensing.depthFar > 0 ) depthFar = depthSensing.depthFar; 14628 14629 } 14630 14631 cameraXR.near = cameraR.near = cameraL.near = depthNear; 14632 cameraXR.far = cameraR.far = cameraL.far = depthFar; 14633 14634 if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) { 14635 14636 // Note that the new renderState won't apply until the next frame. See #18320 14637 14638 session.updateRenderState( { 14639 depthNear: cameraXR.near, 14640 depthFar: cameraXR.far 14641 } ); 14642 14643 _currentDepthNear = cameraXR.near; 14644 _currentDepthFar = cameraXR.far; 14645 14646 } 14647 14648 // inherit camera layers and enable eye layers (1 = left, 2 = right) 14649 cameraXR.layers.mask = camera.layers.mask | 0b110; 14650 cameraL.layers.mask = cameraXR.layers.mask & -5; 14651 cameraR.layers.mask = cameraXR.layers.mask & -3; 14652 14653 const parent = camera.parent; 14654 const cameras = cameraXR.cameras; 14655 14656 updateCamera( cameraXR, parent ); 14657 14658 for ( let i = 0; i < cameras.length; i ++ ) { 14659 14660 updateCamera( cameras[ i ], parent ); 14661 14662 } 14663 14664 // update projection matrix for proper view frustum culling 14665 14666 if ( cameras.length === 2 ) { 14667 14668 setProjectionFromUnion( cameraXR, cameraL, cameraR ); 14669 14670 } else { 14671 14672 // assume single camera setup (AR) 14673 14674 cameraXR.projectionMatrix.copy( cameraL.projectionMatrix ); 14675 14676 } 14677 14678 // update user camera and its children 14679 14680 if ( currentCameraSettings === null && camera.isPerspectiveCamera ) { 14681 14682 currentCameraSettings = { camera: camera, fov: camera.fov, zoom: camera.zoom }; 14683 14684 } 14685 14686 updateUserCamera( camera, cameraXR, parent ); 14687 14688 }; 14689 14690 function updateUserCamera( camera, cameraXR, parent ) { 14691 14692 if ( parent === null ) { 14693 14694 camera.matrix.copy( cameraXR.matrixWorld ); 14695 14696 } else { 14697 14698 camera.matrix.copy( parent.matrixWorld ); 14699 camera.matrix.invert(); 14700 camera.matrix.multiply( cameraXR.matrixWorld ); 14701 14702 } 14703 14704 camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); 14705 camera.updateMatrixWorld( true ); 14706 14707 camera.projectionMatrix.copy( cameraXR.projectionMatrix ); 14708 camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse ); 14709 14710 if ( camera.isPerspectiveCamera ) { 14711 14712 camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] ); 14713 camera.zoom = 1; 14714 14715 } 14716 14717 } 14718 14719 /** 14720 * Returns an instance of {@link ArrayCamera} which represents the XR camera 14721 * of the active XR session. For each view it holds a separate camera object. 14722 * 14723 * The camera's `fov` is currently not used and does not reflect the fov of 14724 * the XR camera. If you need the fov on app level, you have to compute in 14725 * manually from the XR camera's projection matrices. 14726 * 14727 * @return {ArrayCamera} The XR camera. 14728 */ 14729 this.getCamera = function () { 14730 14731 return cameraXR; 14732 14733 }; 14734 14735 /** 14736 * Returns the amount of foveation used by the XR compositor for the projection layer. 14737 * 14738 * @return {number|undefined} The amount of foveation. 14739 */ 14740 this.getFoveation = function () { 14741 14742 if ( glProjLayer === null && glBaseLayer === null ) { 14743 14744 return undefined; 14745 14746 } 14747 14748 return foveation; 14749 14750 }; 14751 14752 /** 14753 * Sets the foveation value. 14754 * 14755 * @param {number} value - A number in the range `[0,1]` where `0` means no foveation (full resolution) 14756 * and `1` means maximum foveation (the edges render at lower resolution). 14757 */ 14758 this.setFoveation = function ( value ) { 14759 14760 // 0 = no foveation = full resolution 14761 // 1 = maximum foveation = the edges render at lower resolution 14762 14763 foveation = value; 14764 14765 if ( glProjLayer !== null ) { 14766 14767 glProjLayer.fixedFoveation = value; 14768 14769 } 14770 14771 if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { 14772 14773 glBaseLayer.fixedFoveation = value; 14774 14775 } 14776 14777 }; 14778 14779 /** 14780 * Returns `true` if depth sensing is supported. 14781 * 14782 * @return {boolean} Whether depth sensing is supported or not. 14783 */ 14784 this.hasDepthSensing = function () { 14785 14786 return depthSensing.texture !== null; 14787 14788 }; 14789 14790 /** 14791 * Returns the depth sensing mesh. 14792 * 14793 * See {@link WebXRDepthSensing#getMesh}. 14794 * 14795 * @return {Mesh} The depth sensing mesh. 14796 */ 14797 this.getDepthSensingMesh = function () { 14798 14799 return depthSensing.getMesh( cameraXR ); 14800 14801 }; 14802 14803 /** 14804 * Retrieves an opaque texture from the view-aligned {@link XRCamera}. 14805 * Only available during the current animation loop. 14806 * 14807 * @param {XRCamera} xrCamera - The camera to query. 14808 * @return {?Texture} An opaque texture representing the current raw camera frame. 14809 */ 14810 this.getCameraTexture = function ( xrCamera ) { 14811 14812 return cameraAccessTextures[ xrCamera ]; 14813 14814 }; 14815 14816 // Animation Loop 14817 14818 let onAnimationFrameCallback = null; 14819 14820 function onAnimationFrame( time, frame ) { 14821 14822 pose = frame.getViewerPose( customReferenceSpace || referenceSpace ); 14823 xrFrame = frame; 14824 14825 if ( pose !== null ) { 14826 14827 const views = pose.views; 14828 14829 if ( glBaseLayer !== null ) { 14830 14831 renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer ); 14832 renderer.setRenderTarget( newRenderTarget ); 14833 14834 } 14835 14836 let cameraXRNeedsUpdate = false; 14837 14838 // check if it's necessary to rebuild cameraXR's camera list 14839 14840 if ( views.length !== cameraXR.cameras.length ) { 14841 14842 cameraXR.cameras.length = 0; 14843 cameraXRNeedsUpdate = true; 14844 14845 } 14846 14847 for ( let i = 0; i < views.length; i ++ ) { 14848 14849 const view = views[ i ]; 14850 14851 let viewport = null; 14852 14853 if ( glBaseLayer !== null ) { 14854 14855 viewport = glBaseLayer.getViewport( view ); 14856 14857 } else { 14858 14859 const glSubImage = glBinding.getViewSubImage( glProjLayer, view ); 14860 viewport = glSubImage.viewport; 14861 14862 // For side-by-side projection, we only produce a single texture for both eyes. 14863 if ( i === 0 ) { 14864 14865 renderer.setRenderTargetTextures( 14866 newRenderTarget, 14867 glSubImage.colorTexture, 14868 glSubImage.depthStencilTexture ); 14869 14870 renderer.setRenderTarget( newRenderTarget ); 14871 14872 } 14873 14874 } 14875 14876 let camera = cameras[ i ]; 14877 14878 if ( camera === undefined ) { 14879 14880 camera = new PerspectiveCamera(); 14881 camera.layers.enable( i ); 14882 camera.viewport = new Vector4(); 14883 cameras[ i ] = camera; 14884 14885 } 14886 14887 camera.matrix.fromArray( view.transform.matrix ); 14888 camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); 14889 camera.projectionMatrix.fromArray( view.projectionMatrix ); 14890 camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); 14891 camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); 14892 14893 if ( i === 0 ) { 14894 14895 cameraXR.matrix.copy( camera.matrix ); 14896 cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale ); 14897 14898 } 14899 14900 if ( cameraXRNeedsUpdate === true ) { 14901 14902 cameraXR.cameras.push( camera ); 14903 14904 } 14905 14906 } 14907 14908 // 14909 14910 const enabledFeatures = session.enabledFeatures; 14911 const gpuDepthSensingEnabled = enabledFeatures && 14912 enabledFeatures.includes( 'depth-sensing' ) && 14913 session.depthUsage == 'gpu-optimized'; 14914 14915 if ( gpuDepthSensingEnabled && supportsGlBinding ) { 14916 14917 glBinding = scope.getBinding(); 14918 14919 const depthData = glBinding.getDepthInformation( views[ 0 ] ); 14920 14921 if ( depthData && depthData.isValid && depthData.texture ) { 14922 14923 depthSensing.init( depthData, session.renderState ); 14924 14925 } 14926 14927 } 14928 14929 const cameraAccessEnabled = enabledFeatures && 14930 enabledFeatures.includes( 'camera-access' ); 14931 14932 if ( cameraAccessEnabled && supportsGlBinding ) { 14933 14934 renderer.state.unbindTexture(); 14935 14936 glBinding = scope.getBinding(); 14937 14938 for ( let i = 0; i < views.length; i ++ ) { 14939 14940 const camera = views[ i ].camera; 14941 14942 if ( camera ) { 14943 14944 let cameraTex = cameraAccessTextures[ camera ]; 14945 14946 if ( ! cameraTex ) { 14947 14948 cameraTex = new ExternalTexture(); 14949 cameraAccessTextures[ camera ] = cameraTex; 14950 14951 } 14952 14953 const glTexture = glBinding.getCameraImage( camera ); 14954 cameraTex.sourceTexture = glTexture; 14955 14956 } 14957 14958 } 14959 14960 } 14961 14962 } 14963 14964 // 14965 14966 for ( let i = 0; i < controllers.length; i ++ ) { 14967 14968 const inputSource = controllerInputSources[ i ]; 14969 const controller = controllers[ i ]; 14970 14971 if ( inputSource !== null && controller !== undefined ) { 14972 14973 controller.update( inputSource, frame, customReferenceSpace || referenceSpace ); 14974 14975 } 14976 14977 } 14978 14979 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame ); 14980 14981 if ( frame.detectedPlanes ) { 14982 14983 scope.dispatchEvent( { type: 'planesdetected', data: frame } ); 14984 14985 } 14986 14987 xrFrame = null; 14988 14989 } 14990 14991 const animation = new WebGLAnimation(); 14992 14993 animation.setAnimationLoop( onAnimationFrame ); 14994 14995 this.setAnimationLoop = function ( callback ) { 14996 14997 onAnimationFrameCallback = callback; 14998 14999 }; 15000 15001 this.dispose = function () {}; 15002 15003 } 15004 15005} 15006 15007const _m1 = /*@__PURE__*/ new Matrix4(); 15008const _m = /*@__PURE__*/ new Matrix3(); 15009 15010_m.set( -1, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ); 15011 15012function WebGLMaterials( renderer, properties ) { 15013 15014 function refreshTransformUniform( map, uniform ) { 15015 15016 if ( map.matrixAutoUpdate === true ) { 15017 15018 map.updateMatrix(); 15019 15020 } 15021 15022 uniform.value.copy( map.matrix ); 15023 15024 } 15025 15026 function refreshFogUniforms( uniforms, fog ) { 15027 15028 fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) ); 15029 15030 if ( fog.isFog ) { 15031 15032 uniforms.fogNear.value = fog.near; 15033 uniforms.fogFar.value = fog.far; 15034 15035 } else if ( fog.isFogExp2 ) { 15036 15037 uniforms.fogDensity.value = fog.density; 15038 15039 } 15040 15041 } 15042 15043 function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) { 15044 15045 if ( material.isNodeMaterial ) { 15046 15047 material.uniformsNeedUpdate = false; 15048 15049 } else if ( material.isMeshBasicMaterial ) { 15050 15051 refreshUniformsCommon( uniforms, material ); 15052 15053 } else if ( material.isMeshLambertMaterial ) { 15054 15055 refreshUniformsCommon( uniforms, material ); 15056 15057 if ( material.envMap ) { 15058 15059 uniforms.envMapIntensity.value = material.envMapIntensity; 15060 15061 } 15062 15063 } else if ( material.isMeshToonMaterial ) { 15064 15065 refreshUniformsCommon( uniforms, material ); 15066 refreshUniformsToon( uniforms, material ); 15067 15068 } else if ( material.isMeshPhongMaterial ) { 15069 15070 refreshUniformsCommon( uniforms, material ); 15071 refreshUniformsPhong( uniforms, material ); 15072 15073 if ( material.envMap ) { 15074 15075 uniforms.envMapIntensity.value = material.envMapIntensity; 15076 15077 } 15078 15079 } else if ( material.isMeshStandardMaterial ) { 15080 15081 refreshUniformsCommon( uniforms, material ); 15082 refreshUniformsStandard( uniforms, material ); 15083 15084 if ( material.isMeshPhysicalMaterial ) { 15085 15086 refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ); 15087 15088 } 15089 15090 } else if ( material.isMeshMatcapMaterial ) { 15091 15092 refreshUniformsCommon( uniforms, material ); 15093 refreshUniformsMatcap( uniforms, material ); 15094 15095 } else if ( material.isMeshDepthMaterial ) { 15096 15097 refreshUniformsCommon( uniforms, material ); 15098 15099 } else if ( material.isMeshDistanceMaterial ) { 15100 15101 refreshUniformsCommon( uniforms, material ); 15102 refreshUniformsDistance( uniforms, material ); 15103 15104 } else if ( material.isMeshNormalMaterial ) { 15105 15106 refreshUniformsCommon( uniforms, material ); 15107 15108 } else if ( material.isLineBasicMaterial ) { 15109 15110 refreshUniformsLine( uniforms, material ); 15111 15112 if ( material.isLineDashedMaterial ) { 15113 15114 refreshUniformsDash( uniforms, material ); 15115 15116 } 15117 15118 } else if ( material.isPointsMaterial ) { 15119 15120 refreshUniformsPoints( uniforms, material, pixelRatio, height ); 15121 15122 } else if ( material.isSpriteMaterial ) { 15123 15124 refreshUniformsSprites( uniforms, material ); 15125 15126 } else if ( material.isShadowMaterial ) { 15127 15128 uniforms.color.value.copy( material.color ); 15129 uniforms.opacity.value = material.opacity; 15130 15131 } else if ( material.isShaderMaterial ) { 15132 15133 material.uniformsNeedUpdate = false; // #15581 15134 15135 } 15136 15137 } 15138 15139 function refreshUniformsCommon( uniforms, material ) { 15140 15141 uniforms.opacity.value = material.opacity; 15142 15143 if ( material.color ) { 15144 15145 uniforms.diffuse.value.copy( material.color ); 15146 15147 } 15148 15149 if ( material.emissive ) { 15150 15151 uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); 15152 15153 } 15154 15155 if ( material.map ) { 15156 15157 uniforms.map.value = material.map; 15158 15159 refreshTransformUniform( material.map, uniforms.mapTransform ); 15160 15161 } 15162 15163 if ( material.alphaMap ) { 15164 15165 uniforms.alphaMap.value = material.alphaMap; 15166 15167 refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); 15168 15169 } 15170 15171 if ( material.bumpMap ) { 15172 15173 uniforms.bumpMap.value = material.bumpMap; 15174 15175 refreshTransformUniform( material.bumpMap, uniforms.bumpMapTransform ); 15176 15177 uniforms.bumpScale.value = material.bumpScale; 15178 15179 if ( material.side === BackSide ) { 15180 15181 uniforms.bumpScale.value *= -1; 15182 15183 } 15184 15185 } 15186 15187 if ( material.normalMap ) { 15188 15189 uniforms.normalMap.value = material.normalMap; 15190 15191 refreshTransformUniform( material.normalMap, uniforms.normalMapTransform ); 15192 15193 uniforms.normalScale.value.copy( material.normalScale ); 15194 15195 if ( material.side === BackSide ) { 15196 15197 uniforms.normalScale.value.negate(); 15198 15199 } 15200 15201 } 15202 15203 if ( material.displacementMap ) { 15204 15205 uniforms.displacementMap.value = material.displacementMap; 15206 15207 refreshTransformUniform( material.displacementMap, uniforms.displacementMapTransform ); 15208 15209 uniforms.displacementScale.value = material.displacementScale; 15210 uniforms.displacementBias.value = material.displacementBias; 15211 15212 } 15213 15214 if ( material.emissiveMap ) { 15215 15216 uniforms.emissiveMap.value = material.emissiveMap; 15217 15218 refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform ); 15219 15220 } 15221 15222 if ( material.specularMap ) { 15223 15224 uniforms.specularMap.value = material.specularMap; 15225 15226 refreshTransformUniform( material.specularMap, uniforms.specularMapTransform ); 15227 15228 } 15229 15230 if ( material.alphaTest > 0 ) { 15231 15232 uniforms.alphaTest.value = material.alphaTest; 15233 15234 } 15235 15236 const materialProperties = properties.get( material ); 15237 15238 const envMap = materialProperties.envMap; 15239 const envMapRotation = materialProperties.envMapRotation; 15240 15241 if ( envMap ) { 15242 15243 uniforms.envMap.value = envMap; 15244 15245 // note: since the matrix is orthonormal, we can use the more-efficient transpose() in lieu of invert() 15246 uniforms.envMapRotation.value.setFromMatrix4( _m1.makeRotationFromEuler( envMapRotation ) ).transpose(); 15247 15248 15249 if ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) { 15250 15251 uniforms.envMapRotation.value.premultiply( _m ); 15252 15253 } 15254 15255 uniforms.reflectivity.value = material.reflectivity; 15256 uniforms.ior.value = material.ior; 15257 uniforms.refractionRatio.value = material.refractionRatio; 15258 15259 } 15260 15261 if ( material.lightMap ) { 15262 15263 uniforms.lightMap.value = material.lightMap; 15264 uniforms.lightMapIntensity.value = material.lightMapIntensity; 15265 15266 refreshTransformUniform( material.lightMap, uniforms.lightMapTransform ); 15267 15268 } 15269 15270 if ( material.aoMap ) { 15271 15272 uniforms.aoMap.value = material.aoMap; 15273 uniforms.aoMapIntensity.value = material.aoMapIntensity; 15274 15275 refreshTransformUniform( material.aoMap, uniforms.aoMapTransform ); 15276 15277 } 15278 15279 } 15280 15281 function refreshUniformsLine( uniforms, material ) { 15282 15283 uniforms.diffuse.value.copy( material.color ); 15284 uniforms.opacity.value = material.opacity; 15285 15286 if ( material.map ) { 15287 15288 uniforms.map.value = material.map; 15289 15290 refreshTransformUniform( material.map, uniforms.mapTransform ); 15291 15292 } 15293 15294 } 15295 15296 function refreshUniformsDash( uniforms, material ) { 15297 15298 uniforms.dashSize.value = material.dashSize; 15299 uniforms.totalSize.value = material.dashSize + material.gapSize; 15300 uniforms.scale.value = material.scale; 15301 15302 } 15303 15304 function refreshUniformsPoints( uniforms, material, pixelRatio, height ) { 15305 15306 uniforms.diffuse.value.copy( material.color ); 15307 uniforms.opacity.value = material.opacity; 15308 uniforms.size.value = material.size * pixelRatio; 15309 uniforms.scale.value = height * 0.5; 15310 15311 if ( material.map ) { 15312 15313 uniforms.map.value = material.map; 15314 15315 refreshTransformUniform( material.map, uniforms.uvTransform ); 15316 15317 } 15318 15319 if ( material.alphaMap ) { 15320 15321 uniforms.alphaMap.value = material.alphaMap; 15322 15323 refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); 15324 15325 } 15326 15327 if ( material.alphaTest > 0 ) { 15328 15329 uniforms.alphaTest.value = material.alphaTest; 15330 15331 } 15332 15333 } 15334 15335 function refreshUniformsSprites( uniforms, material ) { 15336 15337 uniforms.diffuse.value.copy( material.color ); 15338 uniforms.opacity.value = material.opacity; 15339 uniforms.rotation.value = material.rotation; 15340 15341 if ( material.map ) { 15342 15343 uniforms.map.value = material.map; 15344 15345 refreshTransformUniform( material.map, uniforms.mapTransform ); 15346 15347 } 15348 15349 if ( material.alphaMap ) { 15350 15351 uniforms.alphaMap.value = material.alphaMap; 15352 15353 refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); 15354 15355 } 15356 15357 if ( material.alphaTest > 0 ) { 15358 15359 uniforms.alphaTest.value = material.alphaTest; 15360 15361 } 15362 15363 } 15364 15365 function refreshUniformsPhong( uniforms, material ) { 15366 15367 uniforms.specular.value.copy( material.specular ); 15368 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) 15369 15370 } 15371 15372 function refreshUniformsToon( uniforms, material ) { 15373 15374 if ( material.gradientMap ) { 15375 15376 uniforms.gradientMap.value = material.gradientMap; 15377 15378 } 15379 15380 } 15381 15382 function refreshUniformsStandard( uniforms, material ) { 15383 15384 uniforms.metalness.value = material.metalness; 15385 15386 if ( material.metalnessMap ) { 15387 15388 uniforms.metalnessMap.value = material.metalnessMap; 15389 15390 refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform ); 15391 15392 } 15393 15394 uniforms.roughness.value = material.roughness; 15395 15396 if ( material.roughnessMap ) { 15397 15398 uniforms.roughnessMap.value = material.roughnessMap; 15399 15400 refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform ); 15401 15402 } 15403 15404 if ( material.envMap ) { 15405 15406 //uniforms.envMap.value = material.envMap; // part of uniforms common 15407 15408 uniforms.envMapIntensity.value = material.envMapIntensity; 15409 15410 } 15411 15412 } 15413 15414 function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) { 15415 15416 uniforms.ior.value = material.ior; // also part of uniforms common 15417 15418 if ( material.sheen > 0 ) { 15419 15420 uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen ); 15421 15422 uniforms.sheenRoughness.value = material.sheenRoughness; 15423 15424 if ( material.sheenColorMap ) { 15425 15426 uniforms.sheenColorMap.value = material.sheenColorMap; 15427 15428 refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform ); 15429 15430 } 15431 15432 if ( material.sheenRoughnessMap ) { 15433 15434 uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; 15435 15436 refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform ); 15437 15438 } 15439 15440 } 15441 15442 if ( material.clearcoat > 0 ) { 15443 15444 uniforms.clearcoat.value = material.clearcoat; 15445 uniforms.clearcoatRoughness.value = material.clearcoatRoughness; 15446 15447 if ( material.clearcoatMap ) { 15448 15449 uniforms.clearcoatMap.value = material.clearcoatMap; 15450 15451 refreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform ); 15452 15453 } 15454 15455 if ( material.clearcoatRoughnessMap ) { 15456 15457 uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap; 15458 15459 refreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform ); 15460 15461 } 15462 15463 if ( material.clearcoatNormalMap ) { 15464 15465 uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; 15466 15467 refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform ); 15468 15469 uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); 15470 15471 if ( material.side === BackSide ) { 15472 15473 uniforms.clearcoatNormalScale.value.negate(); 15474 15475 } 15476 15477 } 15478 15479 } 15480 15481 if ( material.dispersion > 0 ) { 15482 15483 uniforms.dispersion.value = material.dispersion; 15484 15485 } 15486 15487 if ( material.retroreflectivity > 0 ) { 15488 15489 uniforms.retroreflectivity.value = material.retroreflectivity; 15490 15491 } 15492 15493 if ( material.iridescence > 0 ) { 15494 15495 uniforms.iridescence.value = material.iridescence; 15496 uniforms.iridescenceIOR.value = material.iridescenceIOR; 15497 uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ]; 15498 uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ]; 15499 15500 if ( material.iridescenceMap ) { 15501 15502 uniforms.iridescenceMap.value = material.iridescenceMap; 15503 15504 refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform ); 15505 15506 } 15507 15508 if ( material.iridescenceThicknessMap ) { 15509 15510 uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; 15511 15512 refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform ); 15513 15514 } 15515 15516 } 15517 15518 if ( material.transmission > 0 ) { 15519 15520 uniforms.transmission.value = material.transmission; 15521 uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture; 15522 uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height ); 15523 15524 if ( material.transmissionMap ) { 15525 15526 uniforms.transmissionMap.value = material.transmissionMap; 15527 15528 refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform ); 15529 15530 } 15531 15532 uniforms.thickness.value = material.thickness; 15533 15534 if ( material.thicknessMap ) { 15535 15536 uniforms.thicknessMap.value = material.thicknessMap; 15537 15538 refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform ); 15539 15540 } 15541 15542 uniforms.attenuationDistance.value = material.attenuationDistance; 15543 uniforms.attenuationColor.value.copy( material.attenuationColor ); 15544 15545 } 15546 15547 if ( material.anisotropy > 0 ) { 15548 15549 uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) ); 15550 15551 if ( material.anisotropyMap ) { 15552 15553 uniforms.anisotropyMap.value = material.anisotropyMap; 15554 15555 refreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform ); 15556 15557 } 15558 15559 } 15560 15561 uniforms.specularIntensity.value = material.specularIntensity; 15562 uniforms.specularColor.value.copy( material.specularColor ); 15563 15564 if ( material.specularColorMap ) { 15565 15566 uniforms.specularColorMap.value = material.specularColorMap; 15567 15568 refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform ); 15569 15570 } 15571 15572 if ( material.specularIntensityMap ) { 15573 15574 uniforms.specularIntensityMap.value = material.specularIntensityMap; 15575 15576 refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform ); 15577 15578 } 15579 15580 } 15581 15582 function refreshUniformsMatcap( uniforms, material ) { 15583 15584 if ( material.matcap ) { 15585 15586 uniforms.matcap.value = material.matcap; 15587 15588 } 15589 15590 } 15591 15592 function refreshUniformsDistance( uniforms, material ) { 15593 15594 const light = properties.get( material ).light; 15595 15596 uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld ); 15597 uniforms.nearDistance.value = light.shadow.camera.near; 15598 uniforms.farDistance.value = light.shadow.camera.far; 15599 15600 } 15601 15602 return { 15603 refreshFogUniforms: refreshFogUniforms, 15604 refreshMaterialUniforms: refreshMaterialUniforms 15605 }; 15606 15607} 15608 15609function WebGLUniformsGroups( gl, info, capabilities, state ) { 15610 15611 let buffers = {}; 15612 let updateList = {}; 15613 let allocatedBindingPoints = []; 15614 15615 const maxBindingPoints = gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ); // binding points are global whereas block indices are per shader program 15616 15617 function bind( uniformsGroup, program ) { 15618 15619 const webglProgram = program.program; 15620 state.uniformBlockBinding( uniformsGroup, webglProgram ); 15621 15622 } 15623 15624 function update( uniformsGroup, program ) { 15625 15626 let buffer = buffers[ uniformsGroup.id ]; 15627 15628 if ( buffer === undefined ) { 15629 15630 prepareUniformsGroup( uniformsGroup ); 15631 15632 buffer = createBuffer( uniformsGroup ); 15633 buffers[ uniformsGroup.id ] = buffer; 15634 15635 uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose ); 15636 15637 } 15638 15639 // ensure to update the binding points/block indices mapping for this program 15640 15641 const webglProgram = program.program; 15642 state.updateUBOMapping( uniformsGroup, webglProgram ); 15643 15644 // update UBO once per frame 15645 15646 const frame = info.render.frame; 15647 15648 if ( updateList[ uniformsGroup.id ] !== frame ) { 15649 15650 updateBufferData( uniformsGroup ); 15651 15652 updateList[ uniformsGroup.id ] = frame; 15653 15654 } 15655 15656 } 15657 15658 function createBuffer( uniformsGroup ) { 15659 15660 // the setup of an UBO is independent of a particular shader program but global 15661 15662 const bindingPointIndex = allocateBindingPointIndex(); 15663 uniformsGroup.__bindingPointIndex = bindingPointIndex; 15664 15665 const buffer = gl.createBuffer(); 15666 const size = uniformsGroup.__size; 15667 const usage = uniformsGroup.usage; 15668 15669 gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); 15670 gl.bufferData( gl.UNIFORM_BUFFER, size, usage ); 15671 gl.bindBuffer( gl.UNIFORM_BUFFER, null ); 15672 gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer ); 15673 15674 return buffer; 15675 15676 } 15677 15678 function allocateBindingPointIndex() { 15679 15680 for ( let i = 0; i < maxBindingPoints; i ++ ) { 15681 15682 if ( allocatedBindingPoints.indexOf( i ) === -1 ) { 15683 15684 allocatedBindingPoints.push( i ); 15685 return i; 15686 15687 } 15688 15689 } 15690 15691 error( 'WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' ); 15692 15693 return 0; 15694 15695 } 15696 15697 function updateBufferData( uniformsGroup ) { 15698 15699 const buffer = buffers[ uniformsGroup.id ]; 15700 const uniforms = uniformsGroup.uniforms; 15701 const cache = uniformsGroup.__cache; 15702 15703 gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); 15704 15705 for ( let i = 0, il = uniforms.length; i < il; i ++ ) { 15706 15707 const uniformItem = uniforms[ i ]; 15708 15709 if ( Array.isArray( uniformItem ) ) { 15710 15711 for ( let j = 0, jl = uniformItem.length; j < jl; j ++ ) { 15712 15713 updateUniform( uniformItem[ j ], i, j, cache ); 15714 15715 } 15716 15717 } else { 15718 15719 updateUniform( uniformItem, i, 0, cache ); 15720 15721 } 15722 15723 } 15724 15725 gl.bindBuffer( gl.UNIFORM_BUFFER, null ); 15726 15727 } 15728 15729 function updateUniform( uniform, index, indexArray, cache ) { 15730 15731 if ( hasUniformChanged( uniform, index, indexArray, cache ) === true ) { 15732 15733 const offset = uniform.__offset; 15734 const value = uniform.value; 15735 15736 if ( Array.isArray( value ) ) { 15737 15738 let arrayOffset = 0; 15739 15740 for ( let k = 0; k < value.length; k ++ ) { 15741 15742 const val = value[ k ]; 15743 const info = getUniformSize( val ); 15744 15745 writeUniformValue( val, uniform.__data, arrayOffset ); 15746 15747 // only toArray() values advance arrayOffset 15748 if ( typeof val !== 'number' && typeof val !== 'boolean' && ! val.isMatrix3 && ! ArrayBuffer.isView( val ) ) { 15749 15750 arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT; 15751 15752 } 15753 15754 } 15755 15756 } else { 15757 15758 writeUniformValue( value, uniform.__data, 0 ); 15759 15760 } 15761 15762 gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data ); 15763 15764 } 15765 15766 } 15767 15768 function writeUniformValue( value, data, offset ) { 15769 15770 // TODO add integer and struct support 15771 if ( typeof value === 'number' || typeof value === 'boolean' ) { 15772 15773 data[ 0 ] = value; 15774 15775 } else if ( value.isMatrix3 ) { 15776 15777 // manually converting 3x3 to 3x4 15778 15779 data[ 0 ] = value.elements[ 0 ]; 15780 data[ 1 ] = value.elements[ 1 ]; 15781 data[ 2 ] = value.elements[ 2 ]; 15782 data[ 3 ] = 0; 15783 data[ 4 ] = value.elements[ 3 ]; 15784 data[ 5 ] = value.elements[ 4 ]; 15785 data[ 6 ] = value.elements[ 5 ]; 15786 data[ 7 ] = 0; 15787 data[ 8 ] = value.elements[ 6 ]; 15788 data[ 9 ] = value.elements[ 7 ]; 15789 data[ 10 ] = value.elements[ 8 ]; 15790 data[ 11 ] = 0; 15791 15792 } else if ( ArrayBuffer.isView( value ) ) { 15793 15794 // copy the buffer data using "set" 15795 data.set( new value.constructor( value.buffer, value.byteOffset, data.length ) ); 15796 15797 } else { 15798 15799 value.toArray( data, offset ); 15800 15801 } 15802 15803 } 15804 15805 function hasUniformChanged( uniform, index, indexArray, cache ) { 15806 15807 const value = uniform.value; 15808 const indexString = index + '_' + indexArray; 15809 15810 if ( cache[ indexString ] === undefined ) { 15811 15812 // cache entry does not exist so far 15813 15814 if ( typeof value === 'number' || typeof value === 'boolean' ) { 15815 15816 cache[ indexString ] = value; 15817 15818 } else if ( ArrayBuffer.isView( value ) ) { 15819 15820 cache[ indexString ] = value.slice(); 15821 15822 } else { 15823 15824 cache[ indexString ] = value.clone(); 15825 15826 } 15827 15828 return true; 15829 15830 } else { 15831 15832 const cachedObject = cache[ indexString ]; 15833 15834 // compare current value with cached entry 15835 15836 if ( typeof value === 'number' || typeof value === 'boolean' ) { 15837 15838 if ( cachedObject !== value ) { 15839 15840 cache[ indexString ] = value; 15841 return true; 15842 15843 } 15844 15845 } else if ( ArrayBuffer.isView( value ) ) { 15846 15847 // always update the array buffers 15848 return true; 15849 15850 } else { 15851 15852 if ( cachedObject.equals( value ) === false ) { 15853 15854 cachedObject.copy( value ); 15855 return true; 15856 15857 } 15858 15859 } 15860 15861 } 15862 15863 return false; 15864 15865 } 15866 15867 function prepareUniformsGroup( uniformsGroup ) { 15868 15869 // determine total buffer size according to the STD140 layout 15870 // Hint: STD140 is the only supported layout in WebGL 2 15871 15872 const uniforms = uniformsGroup.uniforms; 15873 15874 let offset = 0; // global buffer offset in bytes 15875 const chunkSize = 16; // size of a chunk in bytes 15876 15877 for ( let i = 0, l = uniforms.length; i < l; i ++ ) { 15878 15879 const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; 15880 15881 for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { 15882 15883 const uniform = uniformArray[ j ]; 15884 15885 const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; 15886 15887 for ( let k = 0, kl = values.length; k < kl; k ++ ) { 15888 15889 const value = values[ k ]; 15890 15891 const info = getUniformSize( value ); 15892 15893 const chunkOffset = offset % chunkSize; // offset in the current chunk 15894 const chunkPadding = chunkOffset % info.boundary; // required padding to match boundary 15895 const chunkStart = chunkOffset + chunkPadding; // the start position in the current chunk for the data 15896 15897 offset += chunkPadding; 15898 15899 // Check for chunk overflow 15900 if ( chunkStart !== 0 && ( chunkSize - chunkStart ) < info.storage ) { 15901 15902 // Add padding and adjust offset 15903 offset += ( chunkSize - chunkStart ); 15904 15905 } 15906 15907 // the following two properties will be used for partial buffer updates 15908 uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); 15909 uniform.__offset = offset; 15910 15911 // Update the global offset 15912 offset += info.storage; 15913 15914 } 15915 15916 } 15917 15918 } 15919 15920 // ensure correct final padding 15921 15922 const chunkOffset = offset % chunkSize; 15923 15924 if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); 15925 15926 // 15927 15928 uniformsGroup.__size = offset; 15929 uniformsGroup.__cache = {}; 15930 15931 return this; 15932 15933 } 15934 15935 function getUniformSize( value ) { 15936 15937 const info = { 15938 boundary: 0, // bytes 15939 storage: 0 // bytes 15940 }; 15941 15942 // determine sizes according to STD140 15943 15944 if ( typeof value === 'number' || typeof value === 'boolean' ) { 15945 15946 // float/int/bool 15947 15948 info.boundary = 4; 15949 info.storage = 4; 15950 15951 } else if ( value.isVector2 ) { 15952 15953 // vec2 15954 15955 info.boundary = 8; 15956 info.storage = 8; 15957 15958 } else if ( value.isVector3 || value.isColor ) { 15959 15960 // vec3 15961 15962 info.boundary = 16; 15963 info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes 15964 15965 } else if ( value.isVector4 ) { 15966 15967 // vec4 15968 15969 info.boundary = 16; 15970 info.storage = 16; 15971 15972 } else if ( value.isMatrix3 ) { 15973 15974 // mat3 (in STD140 a 3x3 matrix is represented as 3x4) 15975 15976 info.boundary = 48; 15977 info.storage = 48; 15978 15979 } else if ( value.isMatrix4 ) { 15980 15981 // mat4 15982 15983 info.boundary = 64; 15984 info.storage = 64; 15985 15986 } else if ( value.isTexture ) { 15987 15988 warn( 'WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); 15989 15990 } else if ( ArrayBuffer.isView( value ) ) { 15991 15992 info.boundary = 16; 15993 info.storage = value.byteLength; 15994 15995 } else { 15996 15997 warn( 'WebGLRenderer: Unsupported uniform value type.', value ); 15998 15999 } 16000 16001 return info; 16002 16003 } 16004 16005 function onUniformsGroupsDispose( event ) { 16006 16007 const uniformsGroup = event.target; 16008 16009 uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); 16010 16011 const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); 16012 allocatedBindingPoints.splice( index, 1 ); 16013 16014 gl.deleteBuffer( buffers[ uniformsGroup.id ] ); 16015 16016 delete buffers[ uniformsGroup.id ]; 16017 delete updateList[ uniformsGroup.id ]; 16018 16019 } 16020 16021 function dispose() { 16022 16023 for ( const id in buffers ) { 16024 16025 gl.deleteBuffer( buffers[ id ] ); 16026 16027 } 16028 16029 allocatedBindingPoints = []; 16030 buffers = {}; 16031 updateList = {}; 16032 16033 } 16034 16035 return { 16036 16037 bind: bind, 16038 update: update, 16039 16040 dispose: dispose 16041 16042 }; 16043 16044} 16045 16046/** 16047 * Precomputed DFG LUT for physically based specular lighting, used by both 16048 * image-based lighting and direct-light multi-scattering energy compensation 16049 * Resolution: 16x16 16050 * Samples: 4096 per texel 16051 * Format: RG16F (2 half floats per texel: scale, bias) 16052 */ 16053 16054 16055const DATA = new Uint16Array( [ 16056 0x30b5, 0x3ad1, 0x314c, 0x3a4d, 0x33d2, 0x391c, 0x35ef, 0x3828, 0x37f3, 0x36a6, 0x38d1, 0x3539, 0x3979, 0x3410, 0x39f8, 0x3252, 0x3a53, 0x30f0, 0x3a94, 0x2fc9, 0x3abf, 0x2e35, 0x3ada, 0x2d05, 0x3ae8, 0x2c1f, 0x3aed, 0x2ae0, 0x3aea, 0x29d1, 0x3ae1, 0x28ff, 16057 0x3638, 0x38e4, 0x364a, 0x38ce, 0x3699, 0x385e, 0x374e, 0x372c, 0x3839, 0x35a4, 0x38dc, 0x3462, 0x396e, 0x32c4, 0x39de, 0x3134, 0x3a2b, 0x3003, 0x3a59, 0x2e3a, 0x3a6d, 0x2ce1, 0x3a6e, 0x2bba, 0x3a5f, 0x2a33, 0x3a49, 0x290a, 0x3a2d, 0x2826, 0x3a0a, 0x26e8, 16058 0x3894, 0x36d7, 0x3897, 0x36c9, 0x38a3, 0x3675, 0x38bc, 0x35ac, 0x38ee, 0x349c, 0x393e, 0x3332, 0x3997, 0x3186, 0x39e2, 0x3038, 0x3a13, 0x2e75, 0x3a29, 0x2cf5, 0x3a2d, 0x2bac, 0x3a21, 0x29ff, 0x3a04, 0x28bc, 0x39dc, 0x2790, 0x39ad, 0x261a, 0x3978, 0x24fa, 16059 0x39ac, 0x34a8, 0x39ac, 0x34a3, 0x39ae, 0x3480, 0x39ae, 0x3423, 0x39b1, 0x330e, 0x39c2, 0x31a9, 0x39e0, 0x3063, 0x39fc, 0x2eb5, 0x3a0c, 0x2d1d, 0x3a14, 0x2bcf, 0x3a07, 0x29ff, 0x39e9, 0x28a3, 0x39be, 0x273c, 0x3989, 0x25b3, 0x394a, 0x2488, 0x3907, 0x2345, 16060 0x3a77, 0x3223, 0x3a76, 0x321f, 0x3a73, 0x3204, 0x3a6a, 0x31b3, 0x3a58, 0x3114, 0x3a45, 0x303b, 0x3a34, 0x2eb6, 0x3a26, 0x2d31, 0x3a1e, 0x2bef, 0x3a0b, 0x2a0d, 0x39ec, 0x28a1, 0x39c0, 0x271b, 0x3987, 0x2580, 0x3944, 0x2449, 0x38fa, 0x22bd, 0x38ac, 0x2155, 16061 0x3b07, 0x2fca, 0x3b06, 0x2fca, 0x3b00, 0x2fb8, 0x3af4, 0x2f7c, 0x3adb, 0x2eea, 0x3ab4, 0x2e00, 0x3a85, 0x2cec, 0x3a5e, 0x2bc5, 0x3a36, 0x2a00, 0x3a0d, 0x2899, 0x39dc, 0x2707, 0x39a0, 0x2562, 0x395a, 0x2424, 0x390b, 0x2268, 0x38b7, 0x20fd, 0x385f, 0x1fd1, 16062 0x3b69, 0x2cb9, 0x3b68, 0x2cbb, 0x3b62, 0x2cbb, 0x3b56, 0x2cae, 0x3b3b, 0x2c78, 0x3b0d, 0x2c0a, 0x3acf, 0x2ae3, 0x3a92, 0x2998, 0x3a54, 0x2867, 0x3a17, 0x26d0, 0x39d3, 0x253c, 0x3989, 0x2402, 0x3935, 0x2226, 0x38dc, 0x20bd, 0x387d, 0x1f54, 0x381d, 0x1db3, 16063 0x3ba9, 0x296b, 0x3ba8, 0x296f, 0x3ba3, 0x297b, 0x3b98, 0x2987, 0x3b7f, 0x2976, 0x3b4e, 0x2927, 0x3b0e, 0x2895, 0x3ac2, 0x27b7, 0x3a73, 0x263b, 0x3a23, 0x24e7, 0x39d0, 0x239b, 0x3976, 0x21d9, 0x3917, 0x207e, 0x38b2, 0x1ee7, 0x384b, 0x1d53, 0x37c7, 0x1c1e, 16064 0x3bd2, 0x25cb, 0x3bd1, 0x25d3, 0x3bcd, 0x25f0, 0x3bc2, 0x261f, 0x3bad, 0x2645, 0x3b7d, 0x262d, 0x3b3e, 0x25c4, 0x3aec, 0x250f, 0x3a93, 0x243a, 0x3a32, 0x22ce, 0x39d0, 0x215b, 0x3969, 0x202a, 0x38fe, 0x1e6e, 0x388f, 0x1cf1, 0x381f, 0x1b9b, 0x3762, 0x19dd, 16065 0x3be9, 0x21ab, 0x3be9, 0x21b7, 0x3be5, 0x21e5, 0x3bdd, 0x2241, 0x3bc9, 0x22a7, 0x3ba0, 0x22ec, 0x3b62, 0x22cd, 0x3b0f, 0x2247, 0x3aae, 0x2175, 0x3a44, 0x2088, 0x39d4, 0x1f49, 0x3960, 0x1dbe, 0x38e9, 0x1c77, 0x3870, 0x1ae8, 0x37f1, 0x1953, 0x3708, 0x181b, 16066 0x3bf6, 0x1cea, 0x3bf6, 0x1cfb, 0x3bf3, 0x1d38, 0x3bec, 0x1dbd, 0x3bda, 0x1e7c, 0x3bb7, 0x1f25, 0x3b7d, 0x1f79, 0x3b2c, 0x1f4c, 0x3ac6, 0x1ea6, 0x3a55, 0x1dbb, 0x39da, 0x1cbd, 0x395a, 0x1b9d, 0x38d8, 0x1a00, 0x3855, 0x18ac, 0x37ab, 0x173c, 0x36b7, 0x1598, 16067 0x3bfc, 0x1736, 0x3bfc, 0x1759, 0x3bf9, 0x17e7, 0x3bf4, 0x1896, 0x3be4, 0x1997, 0x3bc6, 0x1aa8, 0x3b91, 0x1b84, 0x3b43, 0x1bd2, 0x3ade, 0x1b8a, 0x3a65, 0x1acd, 0x39e2, 0x19d3, 0x3957, 0x18cd, 0x38ca, 0x17b3, 0x383e, 0x1613, 0x376d, 0x14bf, 0x366f, 0x135e, 16068 0x3bff, 0x101b, 0x3bff, 0x1039, 0x3bfc, 0x10c8, 0x3bf9, 0x1226, 0x3bea, 0x1428, 0x3bcf, 0x1584, 0x3b9f, 0x16c5, 0x3b54, 0x179a, 0x3af0, 0x17ce, 0x3a76, 0x1771, 0x39ea, 0x16a4, 0x3956, 0x15a7, 0x38bf, 0x14a7, 0x3829, 0x1379, 0x3735, 0x11ea, 0x362d, 0x10a1, 16069 0x3c00, 0x061b, 0x3c00, 0x066a, 0x3bfe, 0x081c, 0x3bfa, 0x0a4c, 0x3bed, 0x0d16, 0x3bd5, 0x0fb3, 0x3ba9, 0x114d, 0x3b63, 0x127c, 0x3b01, 0x132f, 0x3a85, 0x1344, 0x39f4, 0x12d2, 0x3957, 0x120d, 0x38b5, 0x1122, 0x3817, 0x103c, 0x3703, 0x0ed3, 0x35f0, 0x0d6d, 16070 0x3c00, 0x007a, 0x3c00, 0x0089, 0x3bfe, 0x011d, 0x3bfb, 0x027c, 0x3bf0, 0x04fa, 0x3bda, 0x0881, 0x3bb1, 0x0acd, 0x3b6f, 0x0c97, 0x3b10, 0x0d7b, 0x3a93, 0x0df1, 0x39fe, 0x0def, 0x3959, 0x0d8a, 0x38af, 0x0ce9, 0x3808, 0x0c31, 0x36d5, 0x0af0, 0x35b9, 0x09a3, 16071 0x3c00, 0x0000, 0x3c00, 0x0001, 0x3bff, 0x0015, 0x3bfb, 0x0059, 0x3bf2, 0x00fd, 0x3bdd, 0x01df, 0x3bb7, 0x031c, 0x3b79, 0x047c, 0x3b1d, 0x05d4, 0x3aa0, 0x06d5, 0x3a08, 0x075a, 0x395d, 0x075e, 0x38aa, 0x06f7, 0x37f4, 0x0648, 0x36ac, 0x0576, 0x3586, 0x049f 16072] ); 16073 16074let lut = null; 16075 16076function getDFGLUT() { 16077 16078 if ( lut === null ) { 16079 16080 lut = new DataTexture( DATA, 16, 16, RGFormat, HalfFloatType ); 16081 lut.name = 'DFG_LUT'; 16082 lut.minFilter = LinearFilter; 16083 lut.magFilter = LinearFilter; 16084 lut.wrapS = ClampToEdgeWrapping; 16085 lut.wrapT = ClampToEdgeWrapping; 16086 lut.generateMipmaps = false; 16087 lut.needsUpdate = true; 16088 16089 } 16090 16091 return lut; 16092 16093} 16094 16095/** 16096 * This renderer uses WebGL 2 to display scenes. 16097 * 16098 * WebGL 1 is not supported since `r163`. 16099 */ 16100class WebGLRenderer { 16101 16102 /** 16103 * Constructs a new WebGL renderer. 16104 * 16105 * @param {WebGLRenderer~Options} [parameters] - The configuration parameter. 16106 */ 16107 constructor( parameters = {} ) { 16108 16109 const { 16110 canvas = createCanvasElement(), 16111 context = null, 16112 depth = true, 16113 stencil = false, 16114 alpha = false, 16115 antialias = false, 16116 premultipliedAlpha = true, 16117 preserveDrawingBuffer = false, 16118 powerPreference = 'default', 16119 failIfMajorPerformanceCaveat = false, 16120 reversedDepthBuffer = false, 16121 outputBufferType = UnsignedByteType, 16122 } = parameters; 16123 16124 /** 16125 * This flag can be used for type testing. 16126 * 16127 * @type {boolean} 16128 * @readonly 16129 * @default true 16130 */ 16131 this.isWebGLRenderer = true; 16132 16133 let _alpha; 16134 16135 if ( context !== null ) { 16136 16137 if ( typeof WebGLRenderingContext !== 'undefined' && context instanceof WebGLRenderingContext ) { 16138 16139 throw new Error( 'THREE.WebGLRenderer: WebGL 1 is not supported since r163.' ); 16140 16141 } 16142 16143 _alpha = context.getContextAttributes().alpha; 16144 16145 } else { 16146 16147 _alpha = alpha; 16148 16149 } 16150 16151 const _outputBufferType = outputBufferType; 16152 16153 const INTEGER_FORMATS = new Set( [ 16154 RGBAIntegerFormat, 16155 RGIntegerFormat, 16156 RedIntegerFormat 16157 ] ); 16158 16159 const UNSIGNED_TYPES = new Set( [ 16160 UnsignedByteType, 16161 UnsignedIntType, 16162 UnsignedShortType, 16163 UnsignedInt248Type, 16164 UnsignedShort4444Type, 16165 UnsignedShort5551Type 16166 ] ); 16167 16168 const uintClearColor = new Uint32Array( 4 ); 16169 const intClearColor = new Int32Array( 4 ); 16170 const objectPosition = new Vector3(); 16171 16172 let currentRenderList = null; 16173 let currentRenderState = null; 16174 16175 // render() can be called from within a callback triggered by another render. 16176 // We track this so that the nested render call gets its list and state isolated from the parent render call. 16177 16178 const renderListStack = []; 16179 const renderStateStack = []; 16180 16181 // internal render target for non-UnsignedByteType color buffer 16182 16183 let output = null; 16184 16185 // public properties 16186 16187 /** 16188 * A canvas where the renderer draws its output. This is automatically created by the renderer 16189 * in the constructor (if not provided already); you just need to add it to your page like so: 16190 * ```js 16191 * document.body.appendChild( renderer.domElement ); 16192 * ``` 16193 * 16194 * @type {HTMLCanvasElement|OffscreenCanvas} 16195 */ 16196 this.domElement = canvas; 16197 16198 /** 16199 * A object with debug configuration settings. 16200 * 16201 * - `checkShaderErrors`: If it is `true`, defines whether material shader programs are 16202 * checked for errors during compilation and linkage process. It may be useful to disable 16203 * this check in production for performance gain. It is strongly recommended to keep these 16204 * checks enabled during development. If the shader does not compile and link, it will not 16205 * work and associated material will not render. 16206 * - `onShaderError(gl, program, glVertexShader,glFragmentShader)`: A callback function that 16207 * can be used for custom error reporting. The callback receives the WebGL context, an instance 16208 * of WebGLProgram as well two instances of WebGLShader representing the vertex and fragment shader. 16209 * Assigning a custom function disables the default error reporting. 16210 * 16211 * @type {Object} 16212 */ 16213 this.debug = { 16214 16215 /** 16216 * Enables error checking and reporting when shader programs are being compiled. 16217 * @type {boolean} 16218 */ 16219 checkShaderErrors: true, 16220 /** 16221 * Diagnostics configuration for the shader generation. Only relevant for TSL. 16222 * @type {Object} 16223 * @property {boolean} keywords - Whether declaration names that collide with reserved keywords of the shading language should be renamed or not. 16224 */ 16225 diagnostics: { 16226 keywords: false 16227 }, 16228 /** 16229 * Callback for custom error reporting. 16230 * @type {?Function} 16231 */ 16232 onShaderError: null 16233 }; 16234 16235 // clearing 16236 16237 /** 16238 * Whether the renderer should automatically clear its output before rendering a frame or not. 16239 * 16240 * @type {boolean} 16241 * @default true 16242 */ 16243 this.autoClear = true; 16244 16245 /** 16246 * If {@link WebGLRenderer#autoClear} set to `true`, whether the renderer should clear 16247 * the color buffer or not. 16248 * 16249 * @type {boolean} 16250 * @default true 16251 */ 16252 this.autoClearColor = true; 16253 16254 /** 16255 * If {@link WebGLRenderer#autoClear} set to `true`, whether the renderer should clear 16256 * the depth buffer or not. 16257 * 16258 * @type {boolean} 16259 * @default true 16260 */ 16261 this.autoClearDepth = true; 16262 16263 /** 16264 * If {@link WebGLRenderer#autoClear} set to `true`, whether the renderer should clear 16265 * the stencil buffer or not. 16266 * 16267 * @type {boolean} 16268 * @default true 16269 */ 16270 this.autoClearStencil = true; 16271 16272 // scene graph 16273 16274 /** 16275 * Whether the renderer should sort objects or not. 16276 * 16277 * Note: Sorting is used to attempt to properly render objects that have some 16278 * degree of transparency. By definition, sorting objects may not work in all 16279 * cases. Depending on the needs of application, it may be necessary to turn 16280 * off sorting and use other methods to deal with transparency rendering e.g. 16281 * manually determining each object's rendering order. 16282 * 16283 * @type {boolean} 16284 * @default true 16285 */ 16286 this.sortObjects = true; 16287 16288 // user-defined clipping 16289 16290 /** 16291 * User-defined clipping planes specified in world space. These planes apply globally. 16292 * Points in space whose dot product with the plane is negative are cut away. 16293 * 16294 * @type {Array<Plane>} 16295 */ 16296 this.clippingPlanes = []; 16297 16298 /** 16299 * Whether the renderer respects object-level clipping planes or not. 16300 * 16301 * @type {boolean} 16302 * @default false 16303 */ 16304 this.localClippingEnabled = false; 16305 16306 // tone mapping 16307 16308 /** 16309 * The tone mapping technique of the renderer. 16310 * 16311 * @type {(NoToneMapping|LinearToneMapping|ReinhardToneMapping|CineonToneMapping|ACESFilmicToneMapping|CustomToneMapping|AgXToneMapping|NeutralToneMapping)} 16312 * @default NoToneMapping 16313 */ 16314 this.toneMapping = NoToneMapping; 16315 16316 /** 16317 * Exposure level of tone mapping. 16318 * 16319 * @type {number} 16320 * @default 1 16321 */ 16322 this.toneMappingExposure = 1.0; 16323 16324 // transmission 16325 16326 /** 16327 * The normalized resolution scale for the transmission render target, measured in percentage 16328 * of viewport dimensions. Lowering this value can result in significant performance improvements 16329 * when using {@link MeshPhysicalMaterial#transmission}. 16330 * 16331 * @type {number} 16332 * @default 1 16333 */ 16334 this.transmissionResolutionScale = 1.0; 16335 16336 // internal properties 16337 16338 const _this = this; 16339 16340 let _isContextLost = false; 16341 let _nodesHandler = null; 16342 16343 let _scratchFramebuffer = null; 16344 let _srcFramebuffer = null; 16345 let _dstFramebuffer = null; 16346 16347 // internal state cache 16348 16349 this._outputColorSpace = SRGBColorSpace; 16350 16351 let _currentActiveCubeFace = 0; 16352 let _currentActiveMipmapLevel = 0; 16353 let _currentRenderTarget = null; 16354 let _currentMaterialId = -1; 16355 16356 let _currentCamera = null; 16357 16358 const _currentViewport = new Vector4(); 16359 const _currentScissor = new Vector4(); 16360 let _currentScissorTest = null; 16361 16362 const _currentClearColor = new Color( 0x000000 ); 16363 let _currentClearAlpha = 0; 16364 16365 // 16366 16367 let _width = canvas.width; 16368 let _height = canvas.height; 16369 16370 let _pixelRatio = 1; 16371 let _opaqueSort = null; 16372 let _transparentSort = null; 16373 16374 const _viewport = new Vector4( 0, 0, _width, _height ); 16375 const _scissor = new Vector4( 0, 0, _width, _height ); 16376 let _scissorTest = false; 16377 16378 // frustum 16379 16380 const _frustum = new Frustum(); 16381 16382 // clipping 16383 16384 let _clippingEnabled = false; 16385 let _localClippingEnabled = false; 16386 16387 // camera matrices cache 16388 16389 const _projScreenMatrix = new Matrix4(); 16390 16391 const _vector3 = new Vector3(); 16392 16393 const _vector4 = new Vector4(); 16394 16395 const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; 16396 16397 let _renderBackground = false; 16398 16399 function getTargetPixelRatio() { 16400 16401 return _currentRenderTarget === null ? _pixelRatio : 1; 16402 16403 } 16404 16405 // initialize 16406 16407 let _gl = context; 16408 16409 function getContext( contextName, contextAttributes ) { 16410 16411 return canvas.getContext( contextName, contextAttributes ); 16412 16413 } 16414 16415 let extensions, capabilities, state, info; 16416 let properties, textures, environments, attributes, geometries, objects; 16417 let programCache, materials, renderLists, renderStates, clipping, shadowMap; 16418 16419 let background, morphtargets, bufferRenderer, indexedBufferRenderer; 16420 16421 let utils, bindingStates, uniformsGroups; 16422 16423 try { 16424 16425 const contextAttributes = { 16426 alpha: true, 16427 depth, 16428 stencil, 16429 antialias, 16430 premultipliedAlpha, 16431 preserveDrawingBuffer, 16432 powerPreference, 16433 failIfMajorPerformanceCaveat, 16434 }; 16435 16436 // OffscreenCanvas does not have setAttribute, see #22811 16437 if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); 16438 16439 // event listeners must be registered before WebGL context is created, see #12753 16440 canvas.addEventListener( 'webglcontextlost', onContextLost, false ); 16441 canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); 16442 canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); 16443 16444 if ( _gl === null ) { 16445 16446 const contextName = 'webgl2'; 16447 16448 _gl = getContext( contextName, contextAttributes ); 16449 16450 if ( _gl === null ) { 16451 16452 if ( getContext( contextName ) ) { 16453 16454 throw new Error( 'THREE.WebGLRenderer: Error creating WebGL context with your selected attributes.' ); 16455 16456 } else { 16457 16458 throw new Error( 'THREE.WebGLRenderer: Error creating WebGL context.' ); 16459 16460 } 16461 16462 } 16463 16464 } 16465 16466 initGLContext(); 16467 16468 } catch ( e ) { 16469 16470 canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); 16471 canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); 16472 canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); 16473 16474 error( 'WebGLRenderer: ' + e.message ); 16475 throw e; 16476 16477 } 16478 16479 function initGLContext() { 16480 16481 extensions = new WebGLExtensions( _gl ); 16482 extensions.init(); 16483 16484 utils = new WebGLUtils( _gl, extensions ); 16485 16486 capabilities = new WebGLCapabilities( _gl, extensions, parameters, utils ); 16487 16488 state = new WebGLState( _gl, extensions ); 16489 16490 if ( capabilities.reversedDepthBuffer && reversedDepthBuffer ) { 16491 16492 state.buffers.depth.setReversed( true ); 16493 16494 } 16495 16496 _scratchFramebuffer = _gl.createFramebuffer(); 16497 _srcFramebuffer = _gl.createFramebuffer(); 16498 _dstFramebuffer = _gl.createFramebuffer(); 16499 16500 info = new WebGLInfo( _gl ); 16501 properties = new WebGLProperties(); 16502 textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); 16503 environments = new WebGLEnvironments( _this ); 16504 attributes = new WebGLAttributes( _gl ); 16505 bindingStates = new WebGLBindingStates( _gl, attributes ); 16506 geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); 16507 objects = new WebGLObjects( _gl, geometries, attributes, bindingStates, info ); 16508 morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); 16509 clipping = new WebGLClipping( properties ); 16510 programCache = new WebGLPrograms( _this, environments, extensions, capabilities, bindingStates, clipping ); 16511 materials = new WebGLMaterials( _this, properties ); 16512 renderLists = new WebGLRenderLists(); 16513 renderStates = new WebGLRenderStates( extensions ); 16514 background = new WebGLBackground( _this, environments, state, objects, _alpha, premultipliedAlpha ); 16515 shadowMap = new WebGLShadowMap( _this, objects, capabilities ); 16516 uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); 16517 16518 bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info ); 16519 indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info ); 16520 16521 info.programs = programCache.programs; 16522 16523 /** 16524 * Holds details about the capabilities of the current rendering context. 16525 * 16526 * @name WebGLRenderer#capabilities 16527 * @type {WebGLRenderer~Capabilities} 16528 */ 16529 _this.capabilities = capabilities; 16530 16531 /** 16532 * Provides methods for retrieving and testing WebGL extensions. 16533 * 16534 * - `get(extensionName:string)`: Used to check whether a WebGL extension is supported 16535 * and return the extension object if available. 16536 * - `has(extensionName:string)`: returns `true` if the extension is supported. 16537 * 16538 * @name WebGLRenderer#extensions 16539 * @type {Object} 16540 */ 16541 _this.extensions = extensions; 16542 16543 /** 16544 * Used to track properties of other objects like native WebGL objects. 16545 * 16546 * @name WebGLRenderer#properties 16547 * @type {Object} 16548 */ 16549 _this.properties = properties; 16550 16551 /** 16552 * Manages the render lists of the renderer. 16553 * 16554 * @name WebGLRenderer#renderLists 16555 * @type {Object} 16556 */ 16557 _this.renderLists = renderLists; 16558 16559 16560 16561 /** 16562 * Interface for managing shadows. 16563 * 16564 * @name WebGLRenderer#shadowMap 16565 * @type {WebGLRenderer~ShadowMap} 16566 */ 16567 _this.shadowMap = shadowMap; 16568 16569 /** 16570 * Interface for managing the WebGL state. 16571 * 16572 * @name WebGLRenderer#state 16573 * @type {Object} 16574 */ 16575 _this.state = state; 16576 16577 /** 16578 * Holds a series of statistical information about the GPU memory 16579 * and the rendering process. Useful for debugging and monitoring. 16580 * 16581 * By default these data are reset at each render call but when having 16582 * multiple render passes per frame (e.g. when using post processing) it can 16583 * be preferred to reset with a custom pattern. First, set `autoReset` to 16584 * `false`. 16585 * ```js 16586 * renderer.info.autoReset = false; 16587 * ``` 16588 * Call `reset()` whenever you have finished to render a single frame. 16589 * ```js 16590 * renderer.info.reset(); 16591 * ``` 16592 * 16593 * @name WebGLRenderer#info 16594 * @type {WebGLRenderer~Info} 16595 */ 16596 _this.info = info; 16597 16598 } 16599 16600 // initialize internal render target for non-UnsignedByteType color buffer 16601 16602 if ( _outputBufferType !== UnsignedByteType ) { 16603 16604 output = new WebGLOutput( _outputBufferType, canvas.width, canvas.height, antialias, depth, stencil ); 16605 16606 } 16607 16608 // xr 16609 16610 const xr = new WebXRManager( _this, _gl ); 16611 16612 /** 16613 * A reference to the XR manager. 16614 * 16615 * @type {WebXRManager} 16616 */ 16617 this.xr = xr; 16618 16619 /** 16620 * Returns the rendering context. 16621 * 16622 * @return {WebGL2RenderingContext} The rendering context. 16623 */ 16624 this.getContext = function () { 16625 16626 return _gl; 16627 16628 }; 16629 16630 /** 16631 * Returns the rendering context attributes. 16632 * 16633 * @return {WebGLContextAttributes} The rendering context attributes. 16634 */ 16635 this.getContextAttributes = function () { 16636 16637 return _gl.getContextAttributes(); 16638 16639 }; 16640 16641 /** 16642 * Simulates a loss of the WebGL context. This requires support for the `WEBGL_lose_context` extension. 16643 */ 16644 this.forceContextLoss = function () { 16645 16646 const extension = extensions.get( 'WEBGL_lose_context' ); 16647 if ( extension ) extension.loseContext(); 16648 16649 }; 16650 16651 /** 16652 * Simulates a restore of the WebGL context. This requires support for the `WEBGL_lose_context` extension. 16653 */ 16654 this.forceContextRestore = function () { 16655 16656 const extension = extensions.get( 'WEBGL_lose_context' ); 16657 if ( extension ) extension.restoreContext(); 16658 16659 }; 16660 16661 /** 16662 * Returns the pixel ratio. 16663 * 16664 * @return {number} The pixel ratio. 16665 */ 16666 this.getPixelRatio = function () { 16667 16668 return _pixelRatio; 16669 16670 }; 16671 16672 /** 16673 * Sets the given pixel ratio and resizes the canvas if necessary. 16674 * 16675 * @param {number} value - The pixel ratio. 16676 */ 16677 this.setPixelRatio = function ( value ) { 16678 16679 if ( value === undefined ) return; 16680 16681 _pixelRatio = value; 16682 16683 this.setSize( _width, _height, false ); 16684 16685 }; 16686 16687 /** 16688 * Returns the renderer's size in logical pixels. This method does not honor the pixel ratio. 16689 * 16690 * @param {Vector2} target - The method writes the result in this target object. 16691 * @return {Vector2} The renderer's size in logical pixels. 16692 */ 16693 this.getSize = function ( target ) { 16694 16695 return target.set( _width, _height ); 16696 16697 }; 16698 16699 /** 16700 * Resizes the output canvas to (width, height) with device pixel ratio taken 16701 * into account, and also sets the viewport to fit that size, starting in (0, 16702 * 0). Setting `updateStyle` to false prevents any style changes to the output canvas. 16703 * 16704 * @param {number} width - The width in logical pixels. 16705 * @param {number} height - The height in logical pixels. 16706 * @param {boolean} [updateStyle=true] - Whether to update the `style` attribute of the canvas or not. 16707 */ 16708 this.setSize = function ( width, height, updateStyle = true ) { 16709 16710 if ( xr.isPresenting ) { 16711 16712 warn( 'WebGLRenderer: Can\'t change size while VR device is presenting.' ); 16713 return; 16714 16715 } 16716 16717 _width = width; 16718 _height = height; 16719 16720 canvas.width = Math.floor( width * _pixelRatio ); 16721 canvas.height = Math.floor( height * _pixelRatio ); 16722 16723 if ( updateStyle === true ) { 16724 16725 canvas.style.width = width + 'px'; 16726 canvas.style.height = height + 'px'; 16727 16728 } 16729 16730 if ( output !== null ) { 16731 16732 output.setSize( canvas.width, canvas.height ); 16733 16734 } 16735 16736 this.setViewport( 0, 0, width, height ); 16737 16738 }; 16739 16740 /** 16741 * Returns the drawing buffer size in physical pixels. This method honors the pixel ratio. 16742 * 16743 * @param {Vector2} target - The method writes the result in this target object. 16744 * @return {Vector2} The drawing buffer size. 16745 */ 16746 this.getDrawingBufferSize = function ( target ) { 16747 16748 return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); 16749 16750 }; 16751 16752 /** 16753 * This method allows to define the drawing buffer size by specifying 16754 * width, height and pixel ratio all at once. The size of the drawing 16755 * buffer is computed with this formula: 16756 * ```js 16757 * size.x = width * pixelRatio; 16758 * size.y = height * pixelRatio; 16759 * ``` 16760 * 16761 * @param {number} width - The width in logical pixels. 16762 * @param {number} height - The height in logical pixels. 16763 * @param {number} pixelRatio - The pixel ratio. 16764 */ 16765 this.setDrawingBufferSize = function ( width, height, pixelRatio ) { 16766 16767 _width = width; 16768 _height = height; 16769 16770 _pixelRatio = pixelRatio; 16771 16772 canvas.width = Math.floor( width * pixelRatio ); 16773 canvas.height = Math.floor( height * pixelRatio ); 16774 16775 this.setViewport( 0, 0, width, height ); 16776 16777 }; 16778 16779 /** 16780 * Sets the post-processing effects to be applied after rendering. 16781 * 16782 * @param {Array} effects - An array of post-processing effects. 16783 */ 16784 this.setEffects = function ( effects ) { 16785 16786 if ( _outputBufferType === UnsignedByteType ) { 16787 16788 error( 'WebGLRenderer: setEffects() requires outputBufferType set to HalfFloatType or FloatType.' ); 16789 return; 16790 16791 } 16792 16793 if ( effects ) { 16794 16795 for ( let i = 0; i < effects.length; i ++ ) { 16796 16797 if ( effects[ i ].isOutputPass === true ) { 16798 16799 warn( 'WebGLRenderer: OutputPass is not needed in setEffects(). Tone mapping and color space conversion are applied automatically.' ); 16800 break; 16801 16802 } 16803 16804 } 16805 16806 } 16807 16808 output.setEffects( effects || [] ); 16809 16810 }; 16811 16812 /** 16813 * Returns the current viewport definition. 16814 * 16815 * @param {Vector2} target - The method writes the result in this target object. 16816 * @return {Vector2} The current viewport definition. 16817 */ 16818 this.getCurrentViewport = function ( target ) { 16819 16820 return target.copy( _currentViewport ); 16821 16822 }; 16823 16824 /** 16825 * Returns the viewport definition. 16826 * 16827 * @param {Vector4} target - The method writes the result in this target object. 16828 * @return {Vector4} The viewport definition. 16829 */ 16830 this.getViewport = function ( target ) { 16831 16832 return target.copy( _viewport ); 16833 16834 }; 16835 16836 /** 16837 * Sets the viewport to render from `(x, y)` to `(x + width, y + height)`. 16838 * 16839 * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit. 16840 * Or alternatively a four-component vector specifying all the parameters of the viewport. 16841 * @param {number} y - The vertical coordinate for the lower left corner of the viewport origin in logical pixel unit. 16842 * @param {number} width - The width of the viewport in logical pixel unit. 16843 * @param {number} height - The height of the viewport in logical pixel unit. 16844 */ 16845 this.setViewport = function ( x, y, width, height ) { 16846 16847 if ( x.isVector4 ) { 16848 16849 _viewport.set( x.x, x.y, x.z, x.w ); 16850 16851 } else { 16852 16853 _viewport.set( x, y, width, height ); 16854 16855 } 16856 16857 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).round() ); 16858 16859 }; 16860 16861 /** 16862 * Returns the scissor region. 16863 * 16864 * @param {Vector4} target - The method writes the result in this target object. 16865 * @return {Vector4} The scissor region. 16866 */ 16867 this.getScissor = function ( target ) { 16868 16869 return target.copy( _scissor ); 16870 16871 }; 16872 16873 /** 16874 * Sets the scissor region to render from `(x, y)` to `(x + width, y + height)`. 16875 * 16876 * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the scissor region origin in logical pixel unit. 16877 * Or alternatively a four-component vector specifying all the parameters of the scissor region. 16878 * @param {number} y - The vertical coordinate for the lower left corner of the scissor region origin in logical pixel unit. 16879 * @param {number} width - The width of the scissor region in logical pixel unit. 16880 * @param {number} height - The height of the scissor region in logical pixel unit. 16881 */ 16882 this.setScissor = function ( x, y, width, height ) { 16883 16884 if ( x.isVector4 ) { 16885 16886 _scissor.set( x.x, x.y, x.z, x.w ); 16887 16888 } else { 16889 16890 _scissor.set( x, y, width, height ); 16891 16892 } 16893 16894 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).round() ); 16895 16896 }; 16897 16898 /** 16899 * Returns `true` if the scissor test is enabled. 16900 * 16901 * @return {boolean} Whether the scissor test is enabled or not. 16902 */ 16903 this.getScissorTest = function () { 16904 16905 return _scissorTest; 16906 16907 }; 16908 16909 /** 16910 * Enable or disable the scissor test. When this is enabled, only the pixels 16911 * within the defined scissor area will be affected by further renderer 16912 * actions. 16913 * 16914 * @param {boolean} boolean - Whether the scissor test is enabled or not. 16915 */ 16916 this.setScissorTest = function ( boolean ) { 16917 16918 state.setScissorTest( _scissorTest = boolean ); 16919 16920 }; 16921 16922 /** 16923 * Sets a custom opaque sort function for the render lists. Pass `null` 16924 * to use the default `painterSortStable` function. 16925 * 16926 * @param {?Function} method - The opaque sort function. 16927 */ 16928 this.setOpaqueSort = function ( method ) { 16929 16930 _opaqueSort = method; 16931 16932 }; 16933 16934 /** 16935 * Sets a custom transparent sort function for the render lists. Pass `null` 16936 * to use the default `reversePainterSortStable` function. 16937 * 16938 * @param {?Function} method - The opaque sort function. 16939 */ 16940 this.setTransparentSort = function ( method ) { 16941 16942 _transparentSort = method; 16943 16944 }; 16945 16946 // Clearing 16947 16948 /** 16949 * Returns the clear color. 16950 * 16951 * @param {Color} target - The method writes the result in this target object. 16952 * @return {Color} The clear color. 16953 */ 16954 this.getClearColor = function ( target ) { 16955 16956 return target.copy( background.getClearColor() ); 16957 16958 }; 16959 16960 /** 16961 * Sets the clear color and alpha. 16962 * 16963 * @param {Color} color - The clear color. 16964 * @param {number} [alpha=1] - The clear alpha. 16965 */ 16966 this.setClearColor = function () { 16967 16968 background.setClearColor( ...arguments ); 16969 16970 }; 16971 16972 /** 16973 * Returns the clear alpha. Ranges within `[0,1]`. 16974 * 16975 * @return {number} The clear alpha. 16976 */ 16977 this.getClearAlpha = function () { 16978 16979 return background.getClearAlpha(); 16980 16981 }; 16982 16983 /** 16984 * Sets the clear alpha. 16985 * 16986 * @param {number} alpha - The clear alpha. 16987 */ 16988 this.setClearAlpha = function () { 16989 16990 background.setClearAlpha( ...arguments ); 16991 16992 }; 16993 16994 /** 16995 * Tells the renderer to clear its color, depth or stencil drawing buffer(s). 16996 * This method initializes the buffers to the current clear color values. 16997 * 16998 * @param {boolean} [color=true] - Whether the color buffer should be cleared or not. 16999 * @param {boolean} [depth=true] - Whether the depth buffer should be cleared or not. 17000 * @param {boolean} [stencil=true] - Whether the stencil buffer should be cleared or not. 17001 */ 17002 this.clear = function ( color = true, depth = true, stencil = true ) { 17003 17004 let bits = 0; 17005 17006 if ( color ) { 17007 17008 // check if we're trying to clear an integer target 17009 let isIntegerFormat = false; 17010 if ( _currentRenderTarget !== null ) { 17011 17012 const targetFormat = _currentRenderTarget.texture.format; 17013 isIntegerFormat = INTEGER_FORMATS.has( targetFormat ); 17014 17015 } 17016 17017 // use the appropriate clear functions to clear the target if it's a signed 17018 // or unsigned integer target 17019 if ( isIntegerFormat ) { 17020 17021 const targetType = _currentRenderTarget.texture.type; 17022 const isUnsignedType = UNSIGNED_TYPES.has( targetType ); 17023 17024 const clearColor = background.getClearColor(); 17025 const a = background.getClearAlpha(); 17026 const r = clearColor.r; 17027 const g = clearColor.g; 17028 const b = clearColor.b; 17029 17030 if ( isUnsignedType ) { 17031 17032 uintClearColor[ 0 ] = r; 17033 uintClearColor[ 1 ] = g; 17034 uintClearColor[ 2 ] = b; 17035 uintClearColor[ 3 ] = a; 17036 _gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor ); 17037 17038 } else { 17039 17040 intClearColor[ 0 ] = r; 17041 intClearColor[ 1 ] = g; 17042 intClearColor[ 2 ] = b; 17043 intClearColor[ 3 ] = a; 17044 _gl.clearBufferiv( _gl.COLOR, 0, intClearColor ); 17045 17046 } 17047 17048 } else { 17049 17050 bits |= _gl.COLOR_BUFFER_BIT; 17051 17052 } 17053 17054 } 17055 17056 if ( depth ) { 17057 17058 bits |= _gl.DEPTH_BUFFER_BIT; 17059 this.state.buffers.depth.setMask( true ); 17060 17061 } 17062 17063 if ( stencil ) { 17064 17065 bits |= _gl.STENCIL_BUFFER_BIT; 17066 this.state.buffers.stencil.setMask( 0xffffffff ); 17067 17068 } 17069 17070 if ( bits !== 0 ) { 17071 17072 _gl.clear( bits ); 17073 17074 } 17075 17076 }; 17077 17078 /** 17079 * Clears the color buffer. Equivalent to calling `renderer.clear( true, false, false )`. 17080 */ 17081 this.clearColor = function () { 17082 17083 this.clear( true, false, false ); 17084 17085 }; 17086 17087 /** 17088 * Clears the depth buffer. Equivalent to calling `renderer.clear( false, true, false )`. 17089 */ 17090 this.clearDepth = function () { 17091 17092 this.clear( false, true, false ); 17093 17094 }; 17095 17096 /** 17097 * Clears the stencil buffer. Equivalent to calling `renderer.clear( false, false, true )`. 17098 */ 17099 this.clearStencil = function () { 17100 17101 this.clear( false, false, true ); 17102 17103 }; 17104 17105 /** 17106 * Sets a compatibility node builder for rendering node materials with WebGLRenderer. 17107 * This enables using TSL (Three.js Shading Language) node materials to prepare 17108 * for migration to WebGPURenderer. 17109 * 17110 * @param {WebGLNodesHandler} nodesHandler - The node builder instance. 17111 */ 17112 this.setNodesHandler = function ( nodesHandler ) { 17113 17114 nodesHandler.setRenderer( this ); 17115 _nodesHandler = nodesHandler; 17116 17117 }; 17118 17119 /** 17120 * Frees the GPU-related resources allocated by this instance. Call this 17121 * method whenever this instance is no longer used in your app. 17122 */ 17123 this.dispose = function () { 17124 17125 canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); 17126 canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); 17127 canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); 17128 17129 background.dispose(); 17130 renderLists.dispose(); 17131 renderStates.dispose(); 17132 properties.dispose(); 17133 environments.dispose(); 17134 objects.dispose(); 17135 bindingStates.dispose(); 17136 uniformsGroups.dispose(); 17137 programCache.dispose(); 17138 17139 xr.dispose(); 17140 17141 xr.removeEventListener( 'sessionstart', onXRSessionStart ); 17142 xr.removeEventListener( 'sessionend', onXRSessionEnd ); 17143 17144 animation.stop(); 17145 17146 }; 17147 17148 // Events 17149 17150 function onContextLost( event ) { 17151 17152 event.preventDefault(); 17153 17154 log( 'WebGLRenderer: Context Lost.' ); 17155 17156 _isContextLost = true; 17157 17158 } 17159 17160 function onContextRestore( /* event */ ) { 17161 17162 log( 'WebGLRenderer: Context Restored.' ); 17163 17164 _isContextLost = false; 17165 17166 const infoAutoReset = info.autoReset; 17167 const shadowMapEnabled = shadowMap.enabled; 17168 const shadowMapAutoUpdate = shadowMap.autoUpdate; 17169 const shadowMapNeedsUpdate = shadowMap.needsUpdate; 17170 const shadowMapType = shadowMap.type; 17171 17172 initGLContext(); 17173 17174 info.autoReset = infoAutoReset; 17175 shadowMap.enabled = shadowMapEnabled; 17176 shadowMap.autoUpdate = shadowMapAutoUpdate; 17177 shadowMap.needsUpdate = shadowMapNeedsUpdate; 17178 shadowMap.type = shadowMapType; 17179 17180 } 17181 17182 function onContextCreationError( event ) { 17183 17184 error( 'WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); 17185 17186 } 17187 17188 function onMaterialDispose( event ) { 17189 17190 const material = event.target; 17191 17192 material.removeEventListener( 'dispose', onMaterialDispose ); 17193 17194 deallocateMaterial( material ); 17195 17196 } 17197 17198 // Buffer deallocation 17199 17200 function deallocateMaterial( material ) { 17201 17202 releaseMaterialProgramReferences( material ); 17203 17204 properties.remove( material ); 17205 17206 } 17207 17208 17209 function releaseMaterialProgramReferences( material ) { 17210 17211 const programs = properties.get( material ).programs; 17212 17213 if ( programs !== undefined ) { 17214 17215 programs.forEach( function ( program ) { 17216 17217 programCache.releaseProgram( program ); 17218 17219 } ); 17220 17221 if ( material.isShaderMaterial ) { 17222 17223 programCache.releaseShaderCache( material ); 17224 17225 } 17226 17227 } 17228 17229 } 17230 17231 // Buffer rendering 17232 17233 this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { 17234 17235 if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) 17236 17237 const frontFaceCW = ( object.isMesh && object.matrixWorld.determinantAffine() < 0 ); 17238 17239 const program = setProgram( camera, scene, geometry, material, object ); 17240 17241 state.setMaterial( material, frontFaceCW ); 17242 17243 // 17244 17245 let index = geometry.index; 17246 let rangeFactor = 1; 17247 17248 if ( material.wireframe === true ) { 17249 17250 index = geometries.getWireframeAttribute( geometry ); 17251 17252 if ( index === undefined ) return; 17253 17254 rangeFactor = 2; 17255 17256 } 17257 17258 // 17259 17260 const drawRange = geometry.drawRange; 17261 const position = geometry.attributes.position; 17262 17263 let drawStart = drawRange.start * rangeFactor; 17264 let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; 17265 17266 if ( group !== null ) { 17267 17268 drawStart = Math.max( drawStart, group.start * rangeFactor ); 17269 drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); 17270 17271 } 17272 17273 if ( index !== null ) { 17274 17275 drawStart = Math.max( drawStart, 0 ); 17276 drawEnd = Math.min( drawEnd, index.count ); 17277 17278 } else if ( position !== undefined && position !== null ) { 17279 17280 drawStart = Math.max( drawStart, 0 ); 17281 drawEnd = Math.min( drawEnd, position.count ); 17282 17283 } 17284 17285 const drawCount = drawEnd - drawStart; 17286 17287 if ( drawCount < 0 || drawCount === Infinity ) return; 17288 17289 // 17290 17291 bindingStates.setup( object, material, program, geometry, index ); 17292 17293 let attribute; 17294 let renderer = bufferRenderer; 17295 17296 if ( index !== null ) { 17297 17298 attribute = attributes.get( index ); 17299 17300 renderer = indexedBufferRenderer; 17301 renderer.setIndex( attribute ); 17302 17303 } 17304 17305 // 17306 17307 if ( object.isMesh ) { 17308 17309 if ( material.wireframe === true ) { 17310 17311 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); 17312 renderer.setMode( _gl.LINES ); 17313 17314 } else { 17315 17316 renderer.setMode( _gl.TRIANGLES ); 17317 17318 } 17319 17320 } else if ( object.isLine ) { 17321 17322 let lineWidth = material.linewidth; 17323 17324 if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material 17325 17326 state.setLineWidth( lineWidth * getTargetPixelRatio() ); 17327 17328 if ( object.isLineSegments ) { 17329 17330 renderer.setMode( _gl.LINES ); 17331 17332 } else if ( object.isLineLoop ) { 17333 17334 renderer.setMode( _gl.LINE_LOOP ); 17335 17336 } else { 17337 17338 renderer.setMode( _gl.LINE_STRIP ); 17339 17340 } 17341 17342 } else if ( object.isPoints ) { 17343 17344 renderer.setMode( _gl.POINTS ); 17345 17346 } else if ( object.isSprite ) { 17347 17348 renderer.setMode( _gl.TRIANGLES ); 17349 17350 } 17351 17352 if ( object.isBatchedMesh ) { 17353 17354 if ( ! extensions.get( 'WEBGL_multi_draw' ) ) { 17355 17356 const starts = object._multiDrawStarts; 17357 const counts = object._multiDrawCounts; 17358 const drawCount = object._multiDrawCount; 17359 const bytesPerElement = index ? attributes.get( index ).bytesPerElement : 1; 17360 const uniforms = properties.get( material ).currentProgram.getUniforms(); 17361 for ( let i = 0; i < drawCount; i ++ ) { 17362 17363 uniforms.setValue( _gl, '_gl_DrawID', i ); 17364 renderer.render( starts[ i ] / bytesPerElement, counts[ i ] ); 17365 17366 } 17367 17368 } else { 17369 17370 renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ); 17371 17372 } 17373 17374 } else if ( object.isInstancedMesh ) { 17375 17376 renderer.renderInstances( drawStart, drawCount, object.count ); 17377 17378 } else if ( geometry.isInstancedBufferGeometry ) { 17379 17380 const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; 17381 const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); 17382 17383 renderer.renderInstances( drawStart, drawCount, instanceCount ); 17384 17385 } else { 17386 17387 renderer.render( drawStart, drawCount ); 17388 17389 } 17390 17391 }; 17392 17393 // Compile 17394 17395 function prepareMaterial( material, scene, camera, object ) { 17396 17397 if ( _nodesHandler !== null && material.isNodeMaterial ) _nodesHandler.setObject( object, material ); 17398 17399 if ( _clippingEnabled === true ) clipping.setState( material, camera, false ); 17400 17401 if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { 17402 17403 material.side = BackSide; 17404 material.needsUpdate = true; 17405 getProgram( material, scene, object ); 17406 17407 material.side = FrontSide; 17408 material.needsUpdate = true; 17409 getProgram( material, scene, object ); 17410 17411 material.side = DoubleSide; 17412 17413 } else { 17414 17415 getProgram( material, scene, object ); 17416 17417 } 17418 17419 } 17420 17421 /** 17422 * Compiles all materials in the scene with the camera. This is useful to precompile shaders 17423 * before the first rendering. If you want to add a 3D object to an existing scene, use the third 17424 * optional parameter for applying the target scene. 17425 * 17426 * Note that the (target) scene's lighting and environment must be configured before calling this method. 17427 * 17428 * @param {Object3D} scene - The scene or another type of 3D object to precompile. 17429 * @param {Camera} camera - The camera. 17430 * @param {?Scene} [targetScene=null] - The target scene. 17431 * @return {Set<Material>} The precompiled materials. 17432 */ 17433 this.compile = function ( scene, camera, targetScene = null ) { 17434 17435 if ( targetScene === null ) targetScene = scene; 17436 if ( _nodesHandler !== null ) _nodesHandler.renderStart( scene, camera, targetScene ); 17437 17438 currentRenderState = renderStates.get( targetScene ); 17439 currentRenderState.init( camera ); 17440 17441 renderStateStack.push( currentRenderState ); 17442 17443 // gather lights from both the target scene and the new object that will be added to the scene. 17444 17445 targetScene.traverseVisible( function ( object ) { 17446 17447 if ( object.isLight && object.layers.test( camera.layers ) ) { 17448 17449 currentRenderState.pushLight( object ); 17450 17451 if ( object.castShadow ) { 17452 17453 currentRenderState.pushShadow( object ); 17454 17455 } 17456 17457 } 17458 17459 } ); 17460 17461 if ( scene !== targetScene ) { 17462 17463 scene.traverseVisible( function ( object ) { 17464 17465 if ( object.isLight && object.layers.test( camera.layers ) ) { 17466 17467 currentRenderState.pushLight( object ); 17468 17469 if ( object.castShadow ) { 17470 17471 currentRenderState.pushShadow( object ); 17472 17473 } 17474 17475 } 17476 17477 } ); 17478 17479 } 17480 17481 currentRenderState.setupLights(); 17482 if ( _nodesHandler !== null ) _nodesHandler.updateLights( currentRenderState.state.lightsArray ); 17483 17484 _localClippingEnabled = this.localClippingEnabled; 17485 _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled ); 17486 17487 if ( _clippingEnabled === true ) clipping.setGlobalState( this.clippingPlanes, camera ); 17488 17489 // node materials reference the shadow map when they are built, so it must exist by now 17490 17491 if ( _nodesHandler !== null ) shadowMap.render( currentRenderState.state.shadowsArray, targetScene, camera ); 17492 17493 // Only initialize materials in the new scene, not the targetScene. 17494 17495 const materials = new Set(); 17496 17497 scene.traverse( function ( object ) { 17498 17499 if ( ! ( object.isMesh || object.isPoints || object.isLine || object.isSprite ) ) { 17500 17501 return; 17502 17503 } 17504 17505 const material = object.material; 17506 17507 if ( material ) { 17508 17509 if ( Array.isArray( material ) ) { 17510 17511 for ( let i = 0; i < material.length; i ++ ) { 17512 17513 const material2 = material[ i ]; 17514 17515 prepareMaterial( material2, targetScene, camera, object ); 17516 materials.add( material2 ); 17517 17518 } 17519 17520 } else { 17521 17522 prepareMaterial( material, targetScene, camera, object ); 17523 materials.add( material ); 17524 17525 } 17526 17527 } 17528 17529 } ); 17530 17531 currentRenderState = renderStateStack.pop(); 17532 if ( _nodesHandler !== null ) _nodesHandler.renderEnd(); 17533 17534 return materials; 17535 17536 }; 17537 17538 // compileAsync 17539 17540 /** 17541 * Asynchronous version of {@link WebGLRenderer#compile}. 17542 * 17543 * This method makes use of the `KHR_parallel_shader_compile` WebGL extension. Hence, 17544 * it is recommended to use this version of `compile()` whenever possible. 17545 * 17546 * @async 17547 * @param {Object3D} scene - The scene or another type of 3D object to precompile. 17548 * @param {Camera} camera - The camera. 17549 * @param {?Scene} [targetScene=null] - The target scene. 17550 * @return {Promise} A Promise that resolves when the given scene can be rendered without unnecessary stalling due to shader compilation. 17551 */ 17552 this.compileAsync = function ( scene, camera, targetScene = null ) { 17553 17554 const materials = this.compile( scene, camera, targetScene ); 17555 17556 // Wait for all the materials in the new object to indicate that they're 17557 // ready to be used before resolving the promise. 17558 17559 return new Promise( ( resolve ) => { 17560 17561 function checkMaterialsReady() { 17562 17563 materials.forEach( function ( material ) { 17564 17565 const materialProperties = properties.get( material ); 17566 const program = materialProperties.currentProgram; 17567 17568 if ( program === undefined || program.isReady() ) { 17569 17570 // stop waiting for materials that are ready to use or have been disposed 17571 materials.delete( material ); 17572 17573 } 17574 17575 } ); 17576 17577 // once the list of compiling materials is empty, call the callback 17578 17579 if ( materials.size === 0 ) { 17580 17581 resolve( scene ); 17582 return; 17583 17584 } 17585 17586 // if some materials are still not ready, wait a bit and check again 17587 17588 setTimeout( checkMaterialsReady, 10 ); 17589 17590 } 17591 17592 if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) { 17593 17594 // If we can check the compilation status of the materials without 17595 // blocking then do so right away. 17596 17597 checkMaterialsReady(); 17598 17599 } else { 17600 17601 // Otherwise start by waiting a bit to give the materials we just 17602 // initialized a chance to finish. 17603 17604 setTimeout( checkMaterialsReady, 10 ); 17605 17606 } 17607 17608 } ); 17609 17610 }; 17611 17612 // Animation Loop 17613 17614 let onAnimationFrameCallback = null; 17615 17616 function onAnimationFrame( time ) { 17617 17618 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); 17619 17620 } 17621 17622 function onXRSessionStart() { 17623 17624 animation.stop(); 17625 17626 } 17627 17628 function onXRSessionEnd() { 17629 17630 animation.start(); 17631 17632 } 17633 17634 const animation = new WebGLAnimation(); 17635 animation.setAnimationLoop( onAnimationFrame ); 17636 17637 if ( typeof self !== 'undefined' ) animation.setContext( self ); 17638 17639 /** 17640 * Applications are advised to always define the animation loop 17641 * with this method and not manually with `requestAnimationFrame()` 17642 * for best compatibility. 17643 * 17644 * @param {?onAnimationCallback} callback - The application's animation loop. 17645 */ 17646 this.setAnimationLoop = function ( callback ) { 17647 17648 onAnimationFrameCallback = callback; 17649 xr.setAnimationLoop( callback ); 17650 17651 ( callback === null ) ? animation.stop() : animation.start(); 17652 17653 }; 17654 17655 xr.addEventListener( 'sessionstart', onXRSessionStart ); 17656 xr.addEventListener( 'sessionend', onXRSessionEnd ); 17657 17658 // Rendering 17659 17660 /** 17661 * Renders the given scene (or other type of 3D object) using the given camera. 17662 * 17663 * The render is done to a previously specified render target set by calling {@link WebGLRenderer#setRenderTarget} 17664 * or to the canvas as usual. 17665 * 17666 * By default render buffers are cleared before rendering but you can prevent 17667 * this by setting the property `autoClear` to `false`. If you want to prevent 17668 * only certain buffers being cleared you can `autoClearColor`, `autoClearDepth` 17669 * or `autoClearStencil` to `false`. To force a clear, use {@link WebGLRenderer#clear}. 17670 * 17671 * @param {Object3D} scene - The scene to render. 17672 * @param {Camera} camera - The camera. 17673 */ 17674 this.render = function ( scene, camera ) { 17675 17676 if ( camera !== undefined && camera.isCamera !== true ) { 17677 17678 error( 'WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); 17679 return; 17680 17681 } 17682 17683 if ( _isContextLost === true ) return; 17684 17685 // update node builder if available 17686 if ( _nodesHandler !== null ) { 17687 17688 _nodesHandler.renderStart( scene, camera ); 17689 17690 } 17691 17692 // use internal render target for HalfFloatType color buffer (only when tone mapping is enabled) 17693 17694 const isXRPresenting = xr.enabled === true && xr.isPresenting === true; 17695 17696 const useOutput = output !== null && ( _currentRenderTarget === null || isXRPresenting ) && output.begin( _this, _currentRenderTarget ); 17697 17698 // update scene graph 17699 17700 if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); 17701 17702 // update camera matrices and frustum 17703 17704 if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); 17705 17706 if ( xr.enabled === true && xr.isPresenting === true && ( output === null || output.isCompositing() === false ) ) { 17707 17708 if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); 17709 17710 camera = xr.getCamera(); // use XR camera for rendering 17711 17712 } 17713 17714 // 17715 if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); 17716 17717 currentRenderState = renderStates.get( scene, renderStateStack.length ); 17718 currentRenderState.init( camera ); 17719 17720 currentRenderState.state.textureUnits = textures.getTextureUnits(); 17721 renderStateStack.push( currentRenderState ); 17722 17723 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); 17724 _frustum.setFromProjectionMatrix( _projScreenMatrix, WebGLCoordinateSystem, camera.reversedDepth ); 17725 17726 _localClippingEnabled = this.localClippingEnabled; 17727 _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled ); 17728 17729 currentRenderList = renderLists.get( scene, renderListStack.length ); 17730 currentRenderList.init(); 17731 17732 renderListStack.push( currentRenderList ); 17733 17734 if ( xr.enabled === true && xr.isPresenting === true ) { 17735 17736 const depthSensingMesh = _this.xr.getDepthSensingMesh(); 17737 17738 if ( depthSensingMesh !== null ) { 17739 17740 projectObject( depthSensingMesh, camera, - Infinity, _this.sortObjects ); 17741 17742 } 17743 17744 } 17745 17746 projectObject( scene, camera, 0, _this.sortObjects ); 17747 17748 currentRenderList.finish(); 17749 if ( _nodesHandler !== null ) _nodesHandler.updateLights( currentRenderState.state.lightsArray ); 17750 17751 if ( _this.sortObjects === true ) { 17752 17753 currentRenderList.sort( _opaqueSort, _transparentSort ); 17754 17755 } 17756 17757 _renderBackground = xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false; 17758 if ( _renderBackground ) { 17759 17760 background.addToRenderList( currentRenderList, scene ); 17761 17762 } 17763 17764 // 17765 17766 this.info.render.frame ++; 17767 17768 if ( this.info.autoReset === true ) this.info.reset(); 17769 17770 if ( _clippingEnabled === true ) clipping.beginShadows(); 17771 17772 const shadowsArray = currentRenderState.state.shadowsArray; 17773 17774 shadowMap.render( shadowsArray, scene, camera ); 17775 17776 if ( _clippingEnabled === true ) clipping.endShadows(); 17777 17778 // 17779 17780 // render scene (skip if first effect is a render pass - it will render the scene itself) 17781 17782 const skipSceneRender = useOutput && output.hasRenderPass(); 17783 17784 if ( skipSceneRender === false ) { 17785 17786 const opaqueObjects = currentRenderList.opaque; 17787 const transmissiveObjects = currentRenderList.transmissive; 17788 17789 currentRenderState.setupLights(); 17790 17791 if ( camera.isArrayCamera ) { 17792 17793 const cameras = camera.cameras; 17794 17795 if ( transmissiveObjects.length > 0 ) { 17796 17797 for ( let i = 0, l = cameras.length; i < l; i ++ ) { 17798 17799 const camera2 = cameras[ i ]; 17800 17801 renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera2 ); 17802 17803 } 17804 17805 } 17806 17807 if ( _renderBackground ) background.render( scene ); 17808 17809 for ( let i = 0, l = cameras.length; i < l; i ++ ) { 17810 17811 const camera2 = cameras[ i ]; 17812 17813 renderScene( currentRenderList, scene, camera2, camera2.viewport ); 17814 17815 } 17816 17817 } else { 17818 17819 if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ); 17820 17821 if ( _renderBackground ) background.render( scene ); 17822 17823 renderScene( currentRenderList, scene, camera ); 17824 17825 } 17826 17827 } 17828 17829 // 17830 17831 if ( _currentRenderTarget !== null && _currentActiveMipmapLevel === 0 ) { 17832 17833 // resolve multisample renderbuffers to a single-sample texture if necessary 17834 17835 textures.updateMultisampleRenderTarget( _currentRenderTarget ); 17836 17837 // Generate mipmap if we're using any kind of mipmap filtering 17838 17839 textures.updateRenderTargetMipmap( _currentRenderTarget ); 17840 17841 } 17842 17843 // copy from internal render target to canvas using fullscreen quad 17844 17845 if ( useOutput ) { 17846 17847 output.end( _this ); 17848 17849 } 17850 17851 // 17852 17853 if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); 17854 17855 // _gl.finish(); 17856 17857 bindingStates.resetDefaultState(); 17858 _currentMaterialId = -1; 17859 _currentCamera = null; 17860 17861 renderStateStack.pop(); 17862 17863 if ( renderStateStack.length > 0 ) { 17864 17865 currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; 17866 17867 textures.setTextureUnits( currentRenderState.state.textureUnits ); 17868 17869 if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, currentRenderState.state.camera ); 17870 17871 } else { 17872 17873 currentRenderState = null; 17874 17875 } 17876 17877 renderListStack.pop(); 17878 17879 if ( renderListStack.length > 0 ) { 17880 17881 currentRenderList = renderListStack[ renderListStack.length - 1 ]; 17882 17883 } else { 17884 17885 currentRenderList = null; 17886 17887 } 17888 17889 if ( _nodesHandler !== null ) { 17890 17891 _nodesHandler.renderEnd(); 17892 17893 } 17894 17895 }; 17896 17897 function projectObject( object, camera, groupOrder, sortObjects ) { 17898 17899 if ( object.visible === false ) return; 17900 17901 const visible = object.layers.test( camera.layers ); 17902 17903 if ( visible ) { 17904 17905 if ( object.isGroup ) { 17906 17907 groupOrder = object.renderOrder; 17908 17909 } else if ( object.isLOD ) { 17910 17911 if ( object.autoUpdate === true ) object.update( camera ); 17912 17913 } else if ( object.isLightProbeGrid ) { 17914 17915 currentRenderState.pushLightProbeGrid( object ); 17916 17917 } else if ( object.isLight ) { 17918 17919 currentRenderState.pushLight( object ); 17920 17921 if ( object.castShadow ) { 17922 17923 currentRenderState.pushShadow( object ); 17924 17925 } 17926 17927 } else if ( object.isSprite ) { 17928 17929 if ( ! object.frustumCulled || object.intersectsFrustum( _frustum ) ) { 17930 17931 if ( sortObjects ) { 17932 17933 _vector4.setFromMatrixPosition( object.matrixWorld ) 17934 .applyMatrix4( _projScreenMatrix ); 17935 17936 } 17937 17938 const geometry = objects.update( object ); 17939 const material = object.material; 17940 17941 if ( material.visible ) { 17942 17943 currentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null, camera ); 17944 17945 } 17946 17947 } 17948 17949 } else if ( object.isMesh || object.isLine || object.isPoints ) { 17950 17951 if ( ! object.frustumCulled || object.intersectsFrustum( _frustum ) ) { 17952 17953 const geometry = objects.update( object ); 17954 const material = object.material; 17955 17956 if ( sortObjects ) { 17957 17958 if ( object.boundingSphere !== undefined ) { 17959 17960 if ( object.boundingSphere === null ) object.computeBoundingSphere(); 17961 _vector4.copy( object.boundingSphere.center ); 17962 17963 } else { 17964 17965 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 17966 _vector4.copy( geometry.boundingSphere.center ); 17967 17968 } 17969 17970 _vector4 17971 .applyMatrix4( object.matrixWorld ) 17972 .applyMatrix4( _projScreenMatrix ); 17973 17974 } 17975 17976 if ( Array.isArray( material ) ) { 17977 17978 const groups = geometry.groups; 17979 17980 for ( let i = 0, l = groups.length; i < l; i ++ ) { 17981 17982 const group = groups[ i ]; 17983 const groupMaterial = material[ group.materialIndex ]; 17984 17985 if ( groupMaterial && groupMaterial.visible ) { 17986 17987 currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector4.z, group, camera ); 17988 17989 } 17990 17991 } 17992 17993 } else if ( material.visible ) { 17994 17995 currentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null, camera ); 17996 17997 } 17998 17999 } 18000 18001 } 18002 18003 } 18004 18005 const children = object.children; 18006 18007 for ( let i = 0, l = children.length; i < l; i ++ ) { 18008 18009 projectObject( children[ i ], camera, groupOrder, sortObjects ); 18010 18011 } 18012 18013 } 18014 18015 function renderScene( currentRenderList, scene, camera, viewport ) { 18016 18017 const { opaque: opaqueObjects, transmissive: transmissiveObjects, transparent: transparentObjects } = currentRenderList; 18018 18019 currentRenderState.setupLightsView( camera ); 18020 18021 if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera ); 18022 18023 if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); 18024 18025 if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); 18026 if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); 18027 if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); 18028 18029 // Ensure depth buffer writing is enabled so it can be cleared on next render 18030 18031 state.buffers.depth.setTest( true ); 18032 state.buffers.depth.setMask( true ); 18033 state.buffers.color.setMask( true ); 18034 18035 state.setPolygonOffset( false ); 18036 18037 } 18038 18039 function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) { 18040 18041 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; 18042 18043 if ( overrideMaterial !== null ) { 18044 18045 return; 18046 18047 } 18048 18049 if ( currentRenderState.state.transmissionRenderTarget[ camera.id ] === undefined ) { 18050 18051 const hasHalfFloatSupport = extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ); 18052 18053 currentRenderState.state.transmissionRenderTarget[ camera.id ] = new WebGLRenderTarget( 1, 1, { 18054 generateMipmaps: true, 18055 type: hasHalfFloatSupport ? HalfFloatType : UnsignedByteType, 18056 minFilter: LinearMipmapLinearFilter, 18057 samples: Math.max( 4, capabilities.samples ), // to avoid feedback loops, the transmission render target requires a resolve, see #26177 18058 stencilBuffer: stencil, 18059 resolveDepthBuffer: false, 18060 resolveStencilBuffer: false, 18061 storeMultisampledDepthBuffer: false, 18062 storeMultisampledStencilBuffer: false, 18063 colorSpace: ColorManagement.workingColorSpace, 18064 } ); 18065 18066 // debug 18067 18068 /* 18069 const geometry = new PlaneGeometry(); 18070 const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } ); 18071 18072 const mesh = new Mesh( geometry, material ); 18073 scene.add( mesh ); 18074 */ 18075 18076 } 18077 18078 const transmissionRenderTarget = currentRenderState.state.transmissionRenderTarget[ camera.id ]; 18079 18080 const activeViewport = camera.viewport || _currentViewport; 18081 transmissionRenderTarget.setSize( activeViewport.z * _this.transmissionResolutionScale, activeViewport.w * _this.transmissionResolutionScale ); 18082 18083 // 18084 18085 const currentRenderTarget = _this.getRenderTarget(); 18086 const currentActiveCubeFace = _this.getActiveCubeFace(); 18087 const currentActiveMipmapLevel = _this.getActiveMipmapLevel(); 18088 18089 _this.setRenderTarget( transmissionRenderTarget ); 18090 18091 _this.getClearColor( _currentClearColor ); 18092 _currentClearAlpha = _this.getClearAlpha(); 18093 if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 ); 18094 18095 _this.clear(); 18096 18097 if ( _renderBackground ) background.render( scene ); 18098 18099 // Turn off the features which can affect the frag color for opaque objects pass. 18100 // Otherwise they are applied twice in opaque objects pass and transmission objects pass. 18101 const currentToneMapping = _this.toneMapping; 18102 _this.toneMapping = NoToneMapping; 18103 18104 // Remove viewport from camera to avoid nested render calls resetting viewport to it (e.g Reflector). 18105 // Transmission render pass requires viewport to match the transmissionRenderTarget. 18106 const currentCameraViewport = camera.viewport; 18107 if ( camera.viewport !== undefined ) camera.viewport = undefined; 18108 18109 currentRenderState.setupLightsView( camera ); 18110 18111 if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera ); 18112 18113 renderObjects( opaqueObjects, scene, camera ); 18114 18115 textures.updateMultisampleRenderTarget( transmissionRenderTarget ); 18116 textures.updateRenderTargetMipmap( transmissionRenderTarget ); 18117 18118 if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === false ) { // see #28131 18119 18120 let renderTargetNeedsUpdate = false; 18121 18122 for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) { 18123 18124 const renderItem = transmissiveObjects[ i ]; 18125 18126 const { object, geometry, material, group } = renderItem; 18127 18128 if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) { 18129 18130 const currentSide = material.side; 18131 18132 material.side = BackSide; 18133 material.needsUpdate = true; 18134 18135 renderObject( object, scene, camera, geometry, material, group ); 18136 18137 material.side = currentSide; 18138 material.needsUpdate = true; 18139 18140 renderTargetNeedsUpdate = true; 18141 18142 } 18143 18144 } 18145 18146 if ( renderTargetNeedsUpdate === true ) { 18147 18148 textures.updateMultisampleRenderTarget( transmissionRenderTarget ); 18149 textures.updateRenderTargetMipmap( transmissionRenderTarget ); 18150 18151 } 18152 18153 } 18154 18155 _this.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel ); 18156 18157 _this.setClearColor( _currentClearColor, _currentClearAlpha ); 18158 18159 if ( currentCameraViewport !== undefined ) camera.viewport = currentCameraViewport; 18160 18161 _this.toneMapping = currentToneMapping; 18162 18163 } 18164 18165 function renderObjects( renderList, scene, camera ) { 18166 18167 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; 18168 18169 for ( let i = 0, l = renderList.length; i < l; i ++ ) { 18170 18171 const renderItem = renderList[ i ]; 18172 18173 const { object, geometry, group } = renderItem; 18174 let material = renderItem.material; 18175 18176 if ( material.allowOverride === true && overrideMaterial !== null ) { 18177 18178 material = overrideMaterial; 18179 18180 } 18181 18182 if ( object.layers.test( camera.layers ) ) { 18183 18184 renderObject( object, scene, camera, geometry, material, group ); 18185 18186 } 18187 18188 } 18189 18190 } 18191 18192 function renderObject( object, scene, camera, geometry, material, group ) { 18193 18194 if ( _nodesHandler !== null && material.isNodeMaterial ) _nodesHandler.setObject( object, material ); 18195 object.onBeforeRender( _this, scene, camera, geometry, material, group ); 18196 18197 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); 18198 object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); 18199 18200 material.onBeforeRender( _this, scene, camera, geometry, object, group ); 18201 18202 if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { 18203 18204 material.side = BackSide; 18205 material.needsUpdate = true; 18206 _this.renderBufferDirect( camera, scene, geometry, material, object, group ); 18207 18208 material.side = FrontSide; 18209 material.needsUpdate = true; 18210 _this.renderBufferDirect( camera, scene, geometry, material, object, group ); 18211 18212 material.side = DoubleSide; 18213 18214 } else { 18215 18216 _this.renderBufferDirect( camera, scene, geometry, material, object, group ); 18217 18218 } 18219 18220 object.onAfterRender( _this, scene, camera, geometry, material, group ); 18221 18222 } 18223 18224 function getProgram( material, scene, object ) { 18225 18226 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... 18227 18228 const materialProperties = properties.get( material ); 18229 18230 const lights = currentRenderState.state.lights; 18231 const shadowsArray = currentRenderState.state.shadowsArray; 18232 18233 const lightsStateVersion = lights.state.version; 18234 18235 const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object, currentRenderState.state.lightProbeGridArray ); 18236 const programCacheKey = programCache.getProgramCacheKey( parameters ); 18237 18238 let programs = materialProperties.programs; 18239 18240 // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change 18241 18242 materialProperties.environment = ( material.isMeshStandardMaterial || material.isMeshLambertMaterial || material.isMeshPhongMaterial ) ? scene.environment : null; 18243 materialProperties.fog = scene.fog; 18244 18245 const usePMREM = material.isMeshStandardMaterial || ( material.isMeshLambertMaterial && ! material.envMap ) || ( material.isMeshPhongMaterial && ! material.envMap ); 18246 materialProperties.envMap = environments.get( material.envMap || materialProperties.environment, usePMREM ); 18247 materialProperties.envMapRotation = ( materialProperties.environment !== null && material.envMap === null ) ? scene.environmentRotation : material.envMapRotation; 18248 18249 if ( programs === undefined ) { 18250 18251 // new material 18252 18253 material.addEventListener( 'dispose', onMaterialDispose ); 18254 18255 programs = new Map(); 18256 materialProperties.programs = programs; 18257 18258 } 18259 18260 let program = programs.get( programCacheKey ); 18261 18262 if ( program !== undefined ) { 18263 18264 // early out if program and light state is identical 18265 18266 if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { 18267 18268 updateCommonMaterialProperties( material, parameters ); 18269 18270 return program; 18271 18272 } 18273 18274 } else { 18275 18276 parameters.uniforms = programCache.getUniforms( material ); 18277 18278 // Use node builder for node materials if available 18279 if ( _nodesHandler !== null && material.isNodeMaterial ) { 18280 18281 _nodesHandler.build( material, object, parameters ); 18282 18283 } 18284 18285 material.onBeforeCompile( parameters, _this ); 18286 18287 program = programCache.acquireProgram( parameters, programCacheKey ); 18288 programs.set( programCacheKey, program ); 18289 18290 materialProperties.uniforms = parameters.uniforms; 18291 18292 } 18293 18294 const uniforms = materialProperties.uniforms; 18295 18296 if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { 18297 18298 uniforms.clippingPlanes = clipping.uniform; 18299 18300 } 18301 18302 updateCommonMaterialProperties( material, parameters ); 18303 18304 // store the light setup it was created for 18305 18306 materialProperties.needsLights = materialNeedsLights( material ); 18307 materialProperties.lightsStateVersion = lightsStateVersion; 18308 18309 if ( materialProperties.needsLights ) { 18310 18311 // wire up the material to this renderer's lighting state 18312 18313 uniforms.ambientLightColor.value = lights.state.ambient; 18314 uniforms.lightProbe.value = lights.state.probe; 18315 uniforms.sunLights.value = lights.state.sun; 18316 uniforms.sunLightShadows.value = lights.state.sunShadow; 18317 uniforms.directionalLights.value = lights.state.directional; 18318 uniforms.directionalLightShadows.value = lights.state.directionalShadow; 18319 uniforms.spotLights.value = lights.state.spot; 18320 uniforms.spotLightShadows.value = lights.state.spotShadow; 18321 uniforms.rectAreaLights.value = lights.state.rectArea; 18322 uniforms.ltc_1.value = lights.state.rectAreaLTC1; 18323 uniforms.ltc_2.value = lights.state.rectAreaLTC2; 18324 uniforms.pointLights.value = lights.state.point; 18325 uniforms.pointLightShadows.value = lights.state.pointShadow; 18326 uniforms.hemisphereLights.value = lights.state.hemi; 18327 18328 uniforms.sunShadowMatrix.value = lights.state.sunShadowMatrix; 18329 uniforms.sunShadowCascade.value = lights.state.sunShadowCascade; 18330 uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; 18331 uniforms.spotLightMatrix.value = lights.state.spotLightMatrix; 18332 uniforms.spotLightMap.value = lights.state.spotLightMap; 18333 uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; 18334 // TODO (abelnation): add area lights shadow info to uniforms 18335 18336 } 18337 18338 materialProperties.lightProbeGrid = currentRenderState.state.lightProbeGridArray.length > 0; 18339 18340 materialProperties.currentProgram = program; 18341 materialProperties.uniformsList = null; 18342 18343 return program; 18344 18345 } 18346 18347 function getUniformList( materialProperties ) { 18348 18349 if ( materialProperties.uniformsList === null ) { 18350 18351 const progUniforms = materialProperties.currentProgram.getUniforms(); 18352 materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms ); 18353 18354 } 18355 18356 return materialProperties.uniformsList; 18357 18358 } 18359 18360 function updateCommonMaterialProperties( material, parameters ) { 18361 18362 const materialProperties = properties.get( material ); 18363 18364 materialProperties.outputColorSpace = parameters.outputColorSpace; 18365 materialProperties.batching = parameters.batching; 18366 materialProperties.batchingColor = parameters.batchingColor; 18367 materialProperties.instancing = parameters.instancing; 18368 materialProperties.instancingColor = parameters.instancingColor; 18369 materialProperties.instancingMorph = parameters.instancingMorph; 18370 materialProperties.skinning = parameters.skinning; 18371 materialProperties.morphTargets = parameters.morphTargets; 18372 materialProperties.morphNormals = parameters.morphNormals; 18373 materialProperties.morphColors = parameters.morphColors; 18374 materialProperties.morphTargetsCount = parameters.morphTargetsCount; 18375 materialProperties.numClippingPlanes = parameters.numClippingPlanes; 18376 materialProperties.numIntersection = parameters.numClipIntersection; 18377 materialProperties.vertexAlphas = parameters.vertexAlphas; 18378 materialProperties.vertexTangents = parameters.vertexTangents; 18379 materialProperties.toneMapping = parameters.toneMapping; 18380 18381 } 18382 18383 function findLightProbeGrid( volumes, object ) { 18384 18385 if ( volumes.length === 0 ) return null; 18386 18387 if ( volumes.length === 1 ) { 18388 18389 return volumes[ 0 ].texture !== null ? volumes[ 0 ] : null; 18390 18391 } 18392 18393 objectPosition.setFromMatrixPosition( object.matrixWorld ); 18394 18395 for ( let i = 0, l = volumes.length; i < l; i ++ ) { 18396 18397 const v = volumes[ i ]; 18398 18399 if ( v.texture !== null && v.boundingBox.containsPoint( objectPosition ) ) return v; 18400 18401 } 18402 18403 return null; 18404 18405 } 18406 18407 function setProgram( camera, scene, geometry, material, object ) { 18408 18409 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... 18410 18411 textures.resetTextureUnits(); 18412 18413 const fog = scene.fog; 18414 const environment = ( material.isMeshStandardMaterial || material.isMeshLambertMaterial || material.isMeshPhongMaterial ) ? scene.environment : null; 18415 const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : ColorManagement.workingColorSpace ); 18416 const usePMREM = material.isMeshStandardMaterial || ( material.isMeshLambertMaterial && ! material.envMap ) || ( material.isMeshPhongMaterial && ! material.envMap ); 18417 const envMap = environments.get( material.envMap || environment, usePMREM ); 18418 const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; 18419 const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 ); 18420 const morphTargets = !! geometry.morphAttributes.position; 18421 const morphNormals = !! geometry.morphAttributes.normal; 18422 const morphColors = !! geometry.morphAttributes.color; 18423 18424 let toneMapping = NoToneMapping; 18425 18426 if ( material.toneMapped ) { 18427 18428 if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) { 18429 18430 toneMapping = _this.toneMapping; 18431 18432 } 18433 18434 } 18435 18436 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 18437 const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; 18438 18439 const materialProperties = properties.get( material ); 18440 const lights = currentRenderState.state.lights; 18441 18442 if ( _clippingEnabled === true ) { 18443 18444 if ( _localClippingEnabled === true || camera !== _currentCamera ) { 18445 18446 const useCache = 18447 camera === _currentCamera && 18448 material.id === _currentMaterialId; 18449 18450 // we might want to call this function with some ClippingGroup 18451 // object instead of the material, once it becomes feasible 18452 // (#8465, #8379) 18453 clipping.setState( material, camera, useCache ); 18454 18455 } 18456 18457 } 18458 18459 // 18460 18461 let needsProgramChange = false; 18462 18463 if ( material.version === materialProperties.__version ) { 18464 18465 if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { 18466 18467 needsProgramChange = true; 18468 18469 } else if ( materialProperties.outputColorSpace !== colorSpace ) { 18470 18471 needsProgramChange = true; 18472 18473 } else if ( object.isBatchedMesh && materialProperties.batching === false ) { 18474 18475 needsProgramChange = true; 18476 18477 } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) { 18478 18479 needsProgramChange = true; 18480 18481 } else if ( object.isBatchedMesh && materialProperties.batchingColor === true && object._colorsTexture === null ) { 18482 18483 needsProgramChange = true; 18484 18485 } else if ( object.isBatchedMesh && materialProperties.batchingColor === false && object._colorsTexture !== null ) { 18486 18487 needsProgramChange = true; 18488 18489 } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { 18490 18491 needsProgramChange = true; 18492 18493 } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { 18494 18495 needsProgramChange = true; 18496 18497 } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { 18498 18499 needsProgramChange = true; 18500 18501 } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { 18502 18503 needsProgramChange = true; 18504 18505 } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) { 18506 18507 needsProgramChange = true; 18508 18509 } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) { 18510 18511 needsProgramChange = true; 18512 18513 } else if ( object.isInstancedMesh && materialProperties.instancingMorph === true && object.morphTexture === null ) { 18514 18515 needsProgramChange = true; 18516 18517 } else if ( object.isInstancedMesh && materialProperties.instancingMorph === false && object.morphTexture !== null ) { 18518 18519 needsProgramChange = true; 18520 18521 } else if ( materialProperties.envMap !== envMap ) { 18522 18523 needsProgramChange = true; 18524 18525 } else if ( material.fog === true && materialProperties.fog !== fog ) { 18526 18527 needsProgramChange = true; 18528 18529 } else if ( materialProperties.numClippingPlanes !== undefined && 18530 ( materialProperties.numClippingPlanes !== clipping.numPlanes || 18531 materialProperties.numIntersection !== clipping.numIntersection ) ) { 18532 18533 needsProgramChange = true; 18534 18535 } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { 18536 18537 needsProgramChange = true; 18538 18539 } else if ( materialProperties.vertexTangents !== vertexTangents ) { 18540 18541 needsProgramChange = true; 18542 18543 } else if ( materialProperties.morphTargets !== morphTargets ) { 18544 18545 needsProgramChange = true; 18546 18547 } else if ( materialProperties.morphNormals !== morphNormals ) { 18548 18549 needsProgramChange = true; 18550 18551 } else if ( materialProperties.morphColors !== morphColors ) { 18552 18553 needsProgramChange = true; 18554 18555 } else if ( materialProperties.toneMapping !== toneMapping ) { 18556 18557 needsProgramChange = true; 18558 18559 } else if ( materialProperties.morphTargetsCount !== morphTargetsCount ) { 18560 18561 needsProgramChange = true; 18562 18563 } else if ( !! materialProperties.lightProbeGrid !== ( currentRenderState.state.lightProbeGridArray.length > 0 ) ) { 18564 18565 needsProgramChange = true; 18566 18567 } 18568 18569 } else { 18570 18571 needsProgramChange = true; 18572 materialProperties.__version = material.version; 18573 18574 } 18575 18576 // 18577 18578 let program = materialProperties.currentProgram; 18579 18580 if ( needsProgramChange === true ) { 18581 18582 program = getProgram( material, scene, object ); 18583 18584 // notify the node builder that the program has changed so uniforms and update nodes can 18585 // be cached and triggered. 18586 if ( _nodesHandler && material.isNodeMaterial ) { 18587 18588 _nodesHandler.onUpdateProgram( material, program, materialProperties ); 18589 18590 } 18591 18592 } 18593 18594 let refreshProgram = false; 18595 let refreshMaterial = false; 18596 let refreshLights = false; 18597 18598 const p_uniforms = program.getUniforms(), 18599 m_uniforms = materialProperties.uniforms; 18600 18601 if ( state.useProgram( program.program ) ) { 18602 18603 refreshProgram = true; 18604 refreshMaterial = true; 18605 refreshLights = true; 18606 18607 } 18608 18609 if ( material.id !== _currentMaterialId ) { 18610 18611 _currentMaterialId = material.id; 18612 18613 refreshMaterial = true; 18614 18615 } 18616 18617 if ( materialProperties.needsLights ) { 18618 18619 const objectVolume = findLightProbeGrid( currentRenderState.state.lightProbeGridArray, object ); 18620 18621 if ( materialProperties.lightProbeGrid !== objectVolume ) { 18622 18623 materialProperties.lightProbeGrid = objectVolume; 18624 refreshMaterial = true; 18625 18626 } 18627 18628 } 18629 18630 if ( refreshProgram || _currentCamera !== camera ) { 18631 18632 // common camera uniforms 18633 18634 const reversedDepthBuffer = state.buffers.depth.getReversed(); 18635 18636 if ( reversedDepthBuffer && camera.reversedDepth !== true ) { 18637 18638 camera._reversedDepth = true; 18639 camera.updateProjectionMatrix(); 18640 18641 } 18642 18643 p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); 18644 18645 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); 18646 18647 const uCamPos = p_uniforms.map.cameraPosition; 18648 18649 if ( uCamPos !== undefined ) { 18650 18651 uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) ); 18652 18653 } 18654 18655 if ( capabilities.logarithmicDepthBuffer ) { 18656 18657 p_uniforms.setValue( _gl, 'logDepthBufFC', 18658 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); 18659 18660 } 18661 18662 // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067 18663 18664 if ( material.isMeshPhongMaterial || 18665 material.isMeshToonMaterial || 18666 material.isMeshLambertMaterial || 18667 material.isMeshBasicMaterial || 18668 material.isMeshStandardMaterial || 18669 material.isShaderMaterial ) { 18670 18671 p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); 18672 18673 } 18674 18675 if ( _currentCamera !== camera ) { 18676 18677 _currentCamera = camera; 18678 18679 // lighting uniforms depend on the camera so enforce an update 18680 // now, in case this material supports lights - or later, when 18681 // the next material that does gets activated: 18682 18683 refreshMaterial = true; // set to true on material change 18684 refreshLights = true; // remains set until update done 18685 18686 } 18687 18688 } 18689 18690 // Pre-allocate texture units for shadow samplers before setting data textures 18691 if ( materialProperties.needsLights ) { 18692 18693 // Set shadow map uniforms first to ensure they get the first texture units 18694 if ( lights.state.sunShadowMap.length > 0 ) { 18695 18696 p_uniforms.setValue( _gl, 'sunShadowMap', lights.state.sunShadowMap, textures ); 18697 18698 } 18699 18700 if ( lights.state.directionalShadowMap.length > 0 ) { 18701 18702 p_uniforms.setValue( _gl, 'directionalShadowMap', lights.state.directionalShadowMap, textures ); 18703 18704 } 18705 18706 if ( lights.state.spotShadowMap.length > 0 ) { 18707 18708 p_uniforms.setValue( _gl, 'spotShadowMap', lights.state.spotShadowMap, textures ); 18709 18710 } 18711 18712 if ( lights.state.pointShadowMap.length > 0 ) { 18713 18714 p_uniforms.setValue( _gl, 'pointShadowMap', lights.state.pointShadowMap, textures ); 18715 18716 } 18717 18718 } 18719 18720 // skinning and morph target uniforms must be set even if material didn't change 18721 // auto-setting of texture unit for bone and morph texture must go before other textures 18722 // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures 18723 18724 if ( object.isSkinnedMesh ) { 18725 18726 p_uniforms.setOptional( _gl, object, 'bindMatrix' ); 18727 p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); 18728 18729 const skeleton = object.skeleton; 18730 18731 if ( skeleton ) { 18732 18733 if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); 18734 18735 p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); 18736 18737 } 18738 18739 } 18740 18741 if ( object.isBatchedMesh ) { 18742 18743 p_uniforms.setOptional( _gl, object, 'batchingTexture' ); 18744 p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures ); 18745 18746 p_uniforms.setOptional( _gl, object, 'batchingIdTexture' ); 18747 p_uniforms.setValue( _gl, 'batchingIdTexture', object._indirectTexture, textures ); 18748 18749 p_uniforms.setOptional( _gl, object, 'batchingColorTexture' ); 18750 if ( object._colorsTexture !== null ) { 18751 18752 p_uniforms.setValue( _gl, 'batchingColorTexture', object._colorsTexture, textures ); 18753 18754 } 18755 18756 } 18757 18758 const morphAttributes = geometry.morphAttributes; 18759 18760 if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined ) ) { 18761 18762 morphtargets.update( object, geometry, program ); 18763 18764 } 18765 18766 if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { 18767 18768 materialProperties.receiveShadow = object.receiveShadow; 18769 p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); 18770 18771 } 18772 18773 if ( ( material.isMeshStandardMaterial || material.isMeshLambertMaterial || material.isMeshPhongMaterial ) && material.envMap === null && scene.environment !== null ) { 18774 18775 m_uniforms.envMapIntensity.value = scene.environmentIntensity; 18776 18777 } 18778 18779 // Set DFG LUT for physically-based materials 18780 if ( m_uniforms.dfgLUT !== undefined ) { 18781 18782 m_uniforms.dfgLUT.value = getDFGLUT(); 18783 18784 } 18785 18786 if ( refreshMaterial ) { 18787 18788 p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); 18789 18790 if ( materialProperties.needsLights ) { 18791 18792 // the current material requires lighting info 18793 18794 // note: all lighting uniforms are always set correctly 18795 // they simply reference the renderer's state for their 18796 // values 18797 // 18798 // use the current material's .needsUpdate flags to set 18799 // the GL state when required 18800 18801 markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); 18802 18803 } 18804 18805 // refresh uniforms common to several materials 18806 18807 if ( fog && material.fog === true ) { 18808 18809 materials.refreshFogUniforms( m_uniforms, fog ); 18810 18811 } 18812 18813 materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, currentRenderState.state.transmissionRenderTarget[ camera.id ] ); 18814 18815 // light probe volume 18816 18817 if ( materialProperties.needsLights && materialProperties.lightProbeGrid ) { 18818 18819 const volume = materialProperties.lightProbeGrid; 18820 18821 m_uniforms.probesSH.value = volume.texture; 18822 m_uniforms.probesMin.value.copy( volume.boundingBox.min ); 18823 m_uniforms.probesMax.value.copy( volume.boundingBox.max ); 18824 m_uniforms.probesResolution.value.copy( volume.resolution ); 18825 18826 } 18827 18828 WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); 18829 18830 } 18831 18832 if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { 18833 18834 WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); 18835 material.uniformsNeedUpdate = false; 18836 18837 } 18838 18839 if ( material.isSpriteMaterial ) { 18840 18841 p_uniforms.setValue( _gl, 'center', object.center ); 18842 18843 } 18844 18845 // common matrices 18846 18847 p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); 18848 p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); 18849 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); 18850 18851 // UBOs 18852 18853 if ( material.uniformsGroups !== undefined ) { 18854 18855 const groups = material.uniformsGroups; 18856 18857 for ( let i = 0, l = groups.length; i < l; i ++ ) { 18858 18859 const group = groups[ i ]; 18860 18861 uniformsGroups.update( group, program ); 18862 uniformsGroups.bind( group, program ); 18863 18864 } 18865 18866 } 18867 18868 return program; 18869 18870 } 18871 18872 // If uniforms are marked as clean, they don't need to be loaded to the GPU. 18873 18874 function markUniformsLightsNeedsUpdate( uniforms, value ) { 18875 18876 uniforms.ambientLightColor.needsUpdate = value; 18877 uniforms.lightProbe.needsUpdate = value; 18878 18879 uniforms.sunLights.needsUpdate = value; 18880 uniforms.sunLightShadows.needsUpdate = value; 18881 uniforms.directionalLights.needsUpdate = value; 18882 uniforms.directionalLightShadows.needsUpdate = value; 18883 uniforms.pointLights.needsUpdate = value; 18884 uniforms.pointLightShadows.needsUpdate = value; 18885 uniforms.spotLights.needsUpdate = value; 18886 uniforms.spotLightShadows.needsUpdate = value; 18887 uniforms.rectAreaLights.needsUpdate = value; 18888 uniforms.hemisphereLights.needsUpdate = value; 18889 18890 } 18891 18892 function materialNeedsLights( material ) { 18893 18894 return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || 18895 material.isMeshStandardMaterial || material.isShadowMaterial || 18896 ( material.isShaderMaterial && material.lights === true ); 18897 18898 } 18899 18900 /** 18901 * Returns the active cube face. 18902 * 18903 * @return {number} The active cube face. 18904 */ 18905 this.getActiveCubeFace = function () { 18906 18907 return _currentActiveCubeFace; 18908 18909 }; 18910 18911 /** 18912 * Returns the active mipmap level. 18913 * 18914 * @return {number} The active mipmap level. 18915 */ 18916 this.getActiveMipmapLevel = function () { 18917 18918 return _currentActiveMipmapLevel; 18919 18920 }; 18921 18922 /** 18923 * Returns the active render target. 18924 * 18925 * @return {?WebGLRenderTarget} The active render target. Returns `null` if no render target 18926 * is currently set. 18927 */ 18928 this.getRenderTarget = function () { 18929 18930 return _currentRenderTarget; 18931 18932 }; 18933 18934 this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { 18935 18936 const renderTargetProperties = properties.get( renderTarget ); 18937 18938 renderTargetProperties.__autoAllocateDepthBuffer = renderTarget.resolveDepthBuffer === false; 18939 if ( renderTargetProperties.__autoAllocateDepthBuffer === false ) { 18940 18941 // The multisample_render_to_texture extension doesn't work properly if there 18942 // are midframe flushes and an external depth buffer. Disable use of the extension. 18943 renderTargetProperties.__useRenderToTexture = false; 18944 18945 } 18946 18947 properties.get( renderTarget.texture ).__webglTexture = colorTexture; 18948 properties.get( renderTarget.depthTexture ).__webglTexture = renderTargetProperties.__autoAllocateDepthBuffer ? undefined : depthTexture; 18949 18950 renderTargetProperties.__hasExternalTextures = true; 18951 18952 }; 18953 18954 this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { 18955 18956 const renderTargetProperties = properties.get( renderTarget ); 18957 renderTargetProperties.__webglFramebuffer = defaultFramebuffer; 18958 renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; 18959 18960 }; 18961 18962 /** 18963 * Sets the active rendertarget. 18964 * 18965 * @param {?WebGLRenderTarget} renderTarget - The render target to set. When `null` is given, 18966 * the canvas is set as the active render target instead. 18967 * @param {number} [activeCubeFace=0] - The active cube face when using a cube render target. 18968 * Indicates the z layer to render in to when using 3D or array render targets. 18969 * @param {number} [activeMipmapLevel=0] - The active mipmap level. 18970 */ 18971 this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { 18972 18973 _currentRenderTarget = renderTarget; 18974 _currentActiveCubeFace = activeCubeFace; 18975 _currentActiveMipmapLevel = activeMipmapLevel; 18976 18977 let framebuffer = null; 18978 let isCube = false; 18979 let isRenderTarget3D = false; 18980 18981 if ( renderTarget ) { 18982 18983 const renderTargetProperties = properties.get( renderTarget ); 18984 18985 if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { 18986 18987 // Externally-managed framebuffer (e.g. XR) 18988 // Bind to the stored framebuffer (may be null for default, or a WebGLFramebuffer) 18989 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 18990 18991 _currentViewport.copy( renderTarget.viewport ); 18992 _currentScissor.copy( renderTarget.scissor ); 18993 _currentScissorTest = renderTarget.scissorTest; 18994 18995 state.viewport( _currentViewport ); 18996 state.scissor( _currentScissor ); 18997 state.setScissorTest( _currentScissorTest ); 18998 18999 _currentMaterialId = -1; 19000 19001 return; 19002 19003 } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { 19004 19005 textures.setupRenderTarget( renderTarget ); 19006 19007 } else if ( renderTargetProperties.__hasExternalTextures ) { 19008 19009 // Color and depth texture must be rebound in order for the swapchain to update. 19010 textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); 19011 19012 } else if ( renderTarget.depthBuffer ) { 19013 19014 // check if the depth texture is already bound to the frame buffer and that it's been initialized 19015 const depthTexture = renderTarget.depthTexture; 19016 if ( renderTargetProperties.__boundDepthTexture !== depthTexture ) { 19017 19018 // check if the depth texture is compatible 19019 if ( 19020 depthTexture !== null && 19021 properties.has( depthTexture ) && 19022 ( renderTarget.width !== depthTexture.image.width || renderTarget.height !== depthTexture.image.height ) 19023 ) { 19024 19025 throw new Error( 'THREE.WebGLRenderer: Attached DepthTexture is initialized to the incorrect size.' ); 19026 19027 } 19028 19029 // Swap the depth buffer to the currently attached one 19030 textures.setupDepthRenderbuffer( renderTarget ); 19031 19032 } 19033 19034 } 19035 19036 const texture = renderTarget.texture; 19037 19038 if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { 19039 19040 isRenderTarget3D = true; 19041 19042 } 19043 19044 const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; 19045 19046 if ( renderTarget.isWebGLCubeRenderTarget ) { 19047 19048 if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) { 19049 19050 framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ]; 19051 19052 } else { 19053 19054 framebuffer = __webglFramebuffer[ activeCubeFace ]; 19055 19056 } 19057 19058 isCube = true; 19059 19060 } else if ( ( renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { 19061 19062 framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; 19063 19064 } else { 19065 19066 if ( Array.isArray( __webglFramebuffer ) ) { 19067 19068 framebuffer = __webglFramebuffer[ activeMipmapLevel ]; 19069 19070 } else { 19071 19072 framebuffer = __webglFramebuffer; 19073 19074 } 19075 19076 } 19077 19078 _currentViewport.copy( renderTarget.viewport ); 19079 _currentScissor.copy( renderTarget.scissor ); 19080 _currentScissorTest = renderTarget.scissorTest; 19081 19082 } else { 19083 19084 _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); 19085 _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); 19086 _currentScissorTest = _scissorTest; 19087 19088 } 19089 19090 // Use a scratch frame buffer if rendering to a mip level to avoid depth buffers 19091 // being bound that are different sizes. 19092 if ( activeMipmapLevel !== 0 ) { 19093 19094 framebuffer = _scratchFramebuffer; 19095 19096 } 19097 19098 const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 19099 19100 if ( framebufferBound ) { 19101 19102 state.drawBuffers( renderTarget, framebuffer ); 19103 19104 } 19105 19106 state.viewport( _currentViewport ); 19107 state.scissor( _currentScissor ); 19108 state.setScissorTest( _currentScissorTest ); 19109 19110 if ( isCube ) { 19111 19112 const textureProperties = properties.get( renderTarget.texture ); 19113 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); 19114 19115 } else if ( isRenderTarget3D ) { 19116 19117 const layer = activeCubeFace; 19118 19119 for ( let i = 0; i < renderTarget.textures.length; i ++ ) { 19120 19121 const textureProperties = properties.get( renderTarget.textures[ i ] ); 19122 19123 _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, textureProperties.__webglTexture, activeMipmapLevel, layer ); 19124 19125 } 19126 19127 } else if ( renderTarget !== null && activeMipmapLevel !== 0 ) { 19128 19129 // Only bind the frame buffer if we are using a scratch frame buffer to render to a mipmap. 19130 // If we rebind the texture when using a multi sample buffer then an error about inconsistent samples will be thrown. 19131 const textureProperties = properties.get( renderTarget.texture ); 19132 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, textureProperties.__webglTexture, activeMipmapLevel ); 19133 19134 } 19135 19136 _currentMaterialId = -1; // reset current material to ensure correct uniform bindings 19137 19138 }; 19139 19140 function getReadableState( texture ) { 19141 19142 const textureProperties = properties.get( texture ); 19143 19144 if ( textureProperties.__readFormat !== texture.format || textureProperties.__readType !== texture.type ) { 19145 19146 textureProperties.__readFormat = texture.format; 19147 textureProperties.__readType = texture.type; 19148 textureProperties.__formatReadable = capabilities.textureFormatReadable( texture.format ); 19149 textureProperties.__typeReadable = capabilities.textureTypeReadable( texture.type ); 19150 19151 } 19152 19153 return textureProperties; 19154 19155 } 19156 19157 /** 19158 * Reads the pixel data from the given render target into the given buffer. 19159 * 19160 * @param {WebGLRenderTarget} renderTarget - The render target to read from. 19161 * @param {number} x - The `x` coordinate of the copy region's origin. 19162 * @param {number} y - The `y` coordinate of the copy region's origin. 19163 * @param {number} width - The width of the copy region. 19164 * @param {number} height - The height of the copy region. 19165 * @param {TypedArray} buffer - The result buffer. 19166 * @param {number} [activeCubeFaceIndex] - The active cube face index. 19167 * @param {number} [textureIndex=0] - The texture index of an MRT render target. 19168 */ 19169 this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex, textureIndex = 0 ) { 19170 19171 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { 19172 19173 error( 'WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); 19174 return; 19175 19176 } 19177 19178 let framebuffer = properties.get( renderTarget ).__webglFramebuffer; 19179 19180 if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { 19181 19182 framebuffer = framebuffer[ activeCubeFaceIndex ]; 19183 19184 } 19185 19186 if ( framebuffer ) { 19187 19188 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 19189 19190 try { 19191 19192 const texture = renderTarget.textures[ textureIndex ]; 19193 const textureFormat = texture.format; 19194 const textureType = texture.type; 19195 19196 // when using MRT, select the correct color buffer for the subsequent read command 19197 19198 if ( renderTarget.textures.length > 1 ) _gl.readBuffer( _gl.COLOR_ATTACHMENT0 + textureIndex ); 19199 19200 const readableState = getReadableState( texture ); 19201 19202 if ( readableState.__formatReadable === false ) { 19203 19204 error( 'WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); 19205 return; 19206 19207 } 19208 19209 if ( readableState.__typeReadable === false ) { 19210 19211 error( 'WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); 19212 return; 19213 19214 } 19215 19216 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) 19217 19218 if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { 19219 19220 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); 19221 19222 } 19223 19224 } finally { 19225 19226 // restore framebuffer of current render target if necessary 19227 19228 const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; 19229 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 19230 19231 } 19232 19233 } 19234 19235 }; 19236 19237 /** 19238 * Asynchronous, non-blocking version of {@link WebGLRenderer#readRenderTargetPixels}. 19239 * 19240 * It is recommended to use this version of `readRenderTargetPixels()` whenever possible. 19241 * 19242 * @async 19243 * @param {WebGLRenderTarget} renderTarget - The render target to read from. 19244 * @param {number} x - The `x` coordinate of the copy region's origin. 19245 * @param {number} y - The `y` coordinate of the copy region's origin. 19246 * @param {number} width - The width of the copy region. 19247 * @param {number} height - The height of the copy region. 19248 * @param {TypedArray} buffer - The result buffer. 19249 * @param {number} [activeCubeFaceIndex] - The active cube face index. 19250 * @param {number} [textureIndex=0] - The texture index of an MRT render target. 19251 * @return {Promise<TypedArray>} A Promise that resolves when the read has been finished. The resolve provides the read data as a typed array. 19252 */ 19253 this.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex, textureIndex = 0 ) { 19254 19255 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { 19256 19257 throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); 19258 19259 } 19260 19261 let framebuffer = properties.get( renderTarget ).__webglFramebuffer; 19262 if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { 19263 19264 framebuffer = framebuffer[ activeCubeFaceIndex ]; 19265 19266 } 19267 19268 if ( framebuffer ) { 19269 19270 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) 19271 if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { 19272 19273 // set the active frame buffer to the one we want to read 19274 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 19275 19276 const texture = renderTarget.textures[ textureIndex ]; 19277 const textureFormat = texture.format; 19278 const textureType = texture.type; 19279 19280 // when using MRT, select the correct color buffer for the subsequent read command 19281 19282 if ( renderTarget.textures.length > 1 ) _gl.readBuffer( _gl.COLOR_ATTACHMENT0 + textureIndex ); 19283 19284 const readableState = getReadableState( texture ); 19285 19286 if ( readableState.__formatReadable === false ) { 19287 19288 throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' ); 19289 19290 } 19291 19292 if ( readableState.__typeReadable === false ) { 19293 19294 throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' ); 19295 19296 } 19297 19298 const glBuffer = _gl.createBuffer(); 19299 _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); 19300 _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ ); 19301 19302 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 ); 19303 _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, null ); 19304 19305 // reset the frame buffer to the currently set buffer before waiting 19306 const currFramebuffer = _currentRenderTarget !== null ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; 19307 state.bindFramebuffer( _gl.FRAMEBUFFER, currFramebuffer ); 19308 19309 // check if the commands have finished every 8 ms 19310 const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 ); 19311 19312 _gl.flush(); 19313 19314 await probeAsync( _gl, sync, 4 ); 19315 19316 // read the data and delete the buffer 19317 _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer ); 19318 _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer ); 19319 _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, null ); 19320 _gl.deleteBuffer( glBuffer ); 19321 _gl.deleteSync( sync ); 19322 19323 return buffer; 19324 19325 } else { 19326 19327 throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.' ); 19328 19329 } 19330 19331 } 19332 19333 }; 19334 19335 /** 19336 * Copies pixels from the current bound framebuffer into the given texture. 19337 * 19338 * @param {FramebufferTexture} texture - The texture. 19339 * @param {?Vector2} [position=null] - The start position of the copy operation. 19340 * @param {number} [level=0] - The mip level. The default represents the base mip. 19341 */ 19342 this.copyFramebufferToTexture = function ( texture, position = null, level = 0 ) { 19343 19344 const levelScale = Math.pow( 2, - level ); 19345 const width = Math.floor( texture.image.width * levelScale ); 19346 const height = Math.floor( texture.image.height * levelScale ); 19347 19348 const x = position !== null ? position.x : 0; 19349 const y = position !== null ? position.y : 0; 19350 19351 textures.setTexture2D( texture, 0 ); 19352 19353 _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, x, y, width, height ); 19354 19355 state.unbindTexture(); 19356 19357 }; 19358 19359 19360 /** 19361 * Copies data of the given source texture into a destination texture. 19362 * 19363 * When using render target textures as `srcTexture` and `dstTexture`, you must make sure both render targets are initialized 19364 * {@link WebGLRenderer#initRenderTarget}. 19365 * 19366 * @param {Texture} srcTexture - The source texture. 19367 * @param {Texture} dstTexture - The destination texture. 19368 * @param {?(Box2|Box3)} [srcRegion=null] - A bounding box which describes the source region. Can be two or three-dimensional. 19369 * @param {?(Vector2|Vector3)} [dstPosition=null] - A vector that represents the origin of the destination region. Can be two or three-dimensional. 19370 * @param {number} [srcLevel=0] - The source mipmap level to copy. 19371 * @param {?number} [dstLevel=0] - The destination mipmap level. 19372 */ 19373 this.copyTextureToTexture = function ( srcTexture, dstTexture, srcRegion = null, dstPosition = null, srcLevel = 0, dstLevel = 0 ) { 19374 19375 // gather the necessary dimensions to copy 19376 let width, height, depth, minX, minY, minZ; 19377 let dstX, dstY, dstZ; 19378 const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ dstLevel ] : srcTexture.image; 19379 if ( srcRegion !== null ) { 19380 19381 width = srcRegion.max.x - srcRegion.min.x; 19382 height = srcRegion.max.y - srcRegion.min.y; 19383 depth = srcRegion.isBox3 ? srcRegion.max.z - srcRegion.min.z : 1; 19384 minX = srcRegion.min.x; 19385 minY = srcRegion.min.y; 19386 minZ = srcRegion.isBox3 ? srcRegion.min.z : 0; 19387 19388 } else { 19389 19390 const levelScale = Math.pow( 2, - srcLevel ); 19391 width = Math.floor( image.width * levelScale ); 19392 height = Math.floor( image.height * levelScale ); 19393 if ( srcTexture.isDataArrayTexture ) { 19394 19395 depth = image.depth; 19396 19397 } else if ( srcTexture.isData3DTexture ) { 19398 19399 depth = Math.floor( image.depth * levelScale ); 19400 19401 } else { 19402 19403 depth = 1; 19404 19405 } 19406 19407 minX = 0; 19408 minY = 0; 19409 minZ = 0; 19410 19411 } 19412 19413 if ( dstPosition !== null ) { 19414 19415 dstX = dstPosition.x; 19416 dstY = dstPosition.y; 19417 dstZ = dstPosition.z; 19418 19419 } else { 19420 19421 dstX = 0; 19422 dstY = 0; 19423 dstZ = 0; 19424 19425 } 19426 19427 // Set up the destination target 19428 const glFormat = utils.convert( dstTexture.format ); 19429 const glType = utils.convert( dstTexture.type ); 19430 let glTarget; 19431 19432 if ( dstTexture.isData3DTexture ) { 19433 19434 textures.setTexture3D( dstTexture, 0 ); 19435 glTarget = _gl.TEXTURE_3D; 19436 19437 } else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) { 19438 19439 textures.setTexture2DArray( dstTexture, 0 ); 19440 glTarget = _gl.TEXTURE_2D_ARRAY; 19441 19442 } else { 19443 19444 textures.setTexture2D( dstTexture, 0 ); 19445 glTarget = _gl.TEXTURE_2D; 19446 19447 } 19448 19449 state.activeTexture( _gl.TEXTURE0 ); // see #33153 19450 19451 state.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); 19452 state.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); 19453 state.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); 19454 19455 // used for copying data from cpu 19456 const currentUnpackRowLen = state.getParameter( _gl.UNPACK_ROW_LENGTH ); 19457 const currentUnpackImageHeight = state.getParameter( _gl.UNPACK_IMAGE_HEIGHT ); 19458 const currentUnpackSkipPixels = state.getParameter( _gl.UNPACK_SKIP_PIXELS ); 19459 const currentUnpackSkipRows = state.getParameter( _gl.UNPACK_SKIP_ROWS ); 19460 const currentUnpackSkipImages = state.getParameter( _gl.UNPACK_SKIP_IMAGES ); 19461 19462 state.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width ); 19463 state.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height ); 19464 state.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX ); 19465 state.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY ); 19466 state.pixelStorei( _gl.UNPACK_SKIP_IMAGES, minZ ); 19467 19468 // set up the src texture 19469 const isSrc3D = srcTexture.isDataArrayTexture || srcTexture.isData3DTexture; 19470 const isDst3D = dstTexture.isDataArrayTexture || dstTexture.isData3DTexture; 19471 if ( srcTexture.isDepthTexture ) { 19472 19473 const srcTextureProperties = properties.get( srcTexture ); 19474 const dstTextureProperties = properties.get( dstTexture ); 19475 const srcRenderTargetProperties = properties.get( srcTextureProperties.__renderTarget ); 19476 const dstRenderTargetProperties = properties.get( dstTextureProperties.__renderTarget ); 19477 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, srcRenderTargetProperties.__webglFramebuffer ); 19478 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, dstRenderTargetProperties.__webglFramebuffer ); 19479 19480 for ( let i = 0; i < depth; i ++ ) { 19481 19482 // if the source or destination are a 3d target then a layer needs to be bound 19483 if ( isSrc3D ) { 19484 19485 _gl.framebufferTextureLayer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, properties.get( srcTexture ).__webglTexture, srcLevel, minZ + i ); 19486 _gl.framebufferTextureLayer( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, properties.get( dstTexture ).__webglTexture, dstLevel, dstZ + i ); 19487 19488 } 19489 19490 _gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, _gl.DEPTH_BUFFER_BIT, _gl.NEAREST ); 19491 19492 } 19493 19494 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null ); 19495 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null ); 19496 19497 } else if ( srcLevel !== 0 || srcTexture.isRenderTargetTexture || properties.has( srcTexture ) ) { 19498 19499 // get the appropriate frame buffers 19500 const srcTextureProperties = properties.get( srcTexture ); 19501 const dstTextureProperties = properties.get( dstTexture ); 19502 19503 // bind the frame buffer targets 19504 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, _srcFramebuffer ); 19505 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, _dstFramebuffer ); 19506 19507 for ( let i = 0; i < depth; i ++ ) { 19508 19509 // assign the correct layers and mip maps to the frame buffers 19510 if ( isSrc3D ) { 19511 19512 _gl.framebufferTextureLayer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, srcTextureProperties.__webglTexture, srcLevel, minZ + i ); 19513 19514 } else { 19515 19516 _gl.framebufferTexture2D( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, srcTextureProperties.__webglTexture, srcLevel ); 19517 19518 } 19519 19520 if ( isDst3D ) { 19521 19522 _gl.framebufferTextureLayer( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, dstTextureProperties.__webglTexture, dstLevel, dstZ + i ); 19523 19524 } else { 19525 19526 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, dstTextureProperties.__webglTexture, dstLevel ); 19527 19528 } 19529 19530 // copy the data using the fastest function that can achieve the copy 19531 if ( srcLevel !== 0 ) { 19532 19533 _gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, _gl.COLOR_BUFFER_BIT, _gl.NEAREST ); 19534 19535 } else if ( isDst3D ) { 19536 19537 _gl.copyTexSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ + i, minX, minY, width, height ); 19538 19539 } else { 19540 19541 _gl.copyTexSubImage2D( glTarget, dstLevel, dstX, dstY, minX, minY, width, height ); 19542 19543 } 19544 19545 } 19546 19547 // unbind read, draw buffers 19548 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null ); 19549 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null ); 19550 19551 } else { 19552 19553 if ( isDst3D ) { 19554 19555 // copy data into the 3d texture 19556 if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { 19557 19558 _gl.texSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image.data ); 19559 19560 } else if ( dstTexture.isCompressedArrayTexture ) { 19561 19562 _gl.compressedTexSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, image.data ); 19563 19564 } else { 19565 19566 _gl.texSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image ); 19567 19568 } 19569 19570 } else { 19571 19572 // copy data into the 2d texture 19573 if ( srcTexture.isDataTexture ) { 19574 19575 _gl.texSubImage2D( _gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image.data ); 19576 19577 } else if ( srcTexture.isCompressedTexture ) { 19578 19579 _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, dstLevel, dstX, dstY, image.width, image.height, glFormat, image.data ); 19580 19581 } else { 19582 19583 _gl.texSubImage2D( _gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image ); 19584 19585 } 19586 19587 } 19588 19589 } 19590 19591 // reset values 19592 state.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen ); 19593 state.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight ); 19594 state.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels ); 19595 state.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows ); 19596 state.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages ); 19597 19598 // Generate mipmaps only when copying level 0 19599 if ( dstLevel === 0 && dstTexture.generateMipmaps ) { 19600 19601 _gl.generateMipmap( glTarget ); 19602 19603 } 19604 19605 state.unbindTexture(); 19606 19607 }; 19608 19609 /** 19610 * Initializes the given WebGLRenderTarget memory. Useful for initializing a render target so data 19611 * can be copied into it using {@link WebGLRenderer#copyTextureToTexture} before it has been 19612 * rendered to. 19613 * 19614 * @param {WebGLRenderTarget} target - The render target. 19615 */ 19616 this.initRenderTarget = function ( target ) { 19617 19618 if ( properties.get( target ).__webglFramebuffer === undefined ) { 19619 19620 textures.setupRenderTarget( target ); 19621 19622 } 19623 19624 }; 19625 19626 /** 19627 * Initializes the given texture. Useful for preloading a texture rather than waiting until first 19628 * render (which can cause noticeable lags due to decode and GPU upload overhead). 19629 * 19630 * @param {Texture} texture - The texture. 19631 */ 19632 this.initTexture = function ( texture ) { 19633 19634 if ( texture.isCubeTexture ) { 19635 19636 textures.setTextureCube( texture, 0 ); 19637 19638 } else if ( texture.isData3DTexture ) { 19639 19640 textures.setTexture3D( texture, 0 ); 19641 19642 } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { 19643 19644 textures.setTexture2DArray( texture, 0 ); 19645 19646 } else { 19647 19648 textures.setTexture2D( texture, 0 ); 19649 19650 } 19651 19652 state.unbindTexture(); 19653 19654 }; 19655 19656 /** 19657 * Can be used to reset the internal WebGL state. This method is mostly 19658 * relevant for applications which share a single WebGL context across 19659 * multiple WebGL libraries. 19660 */ 19661 this.resetState = function () { 19662 19663 _currentActiveCubeFace = 0; 19664 _currentActiveMipmapLevel = 0; 19665 _currentRenderTarget = null; 19666 19667 state.reset(); 19668 bindingStates.reset(); 19669 19670 }; 19671 19672 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { 19673 19674 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); 19675 19676 } 19677 19678 } 19679 19680 /** 19681 * Defines the coordinate system of the renderer. 19682 * 19683 * In `WebGLRenderer`, the value is always `WebGLCoordinateSystem`. 19684 * 19685 * @type {WebGLCoordinateSystem|WebGPUCoordinateSystem} 19686 * @default WebGLCoordinateSystem 19687 * @readonly 19688 */ 19689 get coordinateSystem() { 19690 19691 return WebGLCoordinateSystem; 19692 19693 } 19694 19695 /** 19696 * Defines the output color space of the renderer. 19697 * 19698 * @type {SRGBColorSpace|LinearSRGBColorSpace} 19699 * @default SRGBColorSpace 19700 */ 19701 get outputColorSpace() { 19702 19703 return this._outputColorSpace; 19704 19705 } 19706 19707 set outputColorSpace( colorSpace ) { 19708 19709 this._outputColorSpace = colorSpace; 19710 19711 const gl = this.getContext(); 19712 gl.drawingBufferColorSpace = ColorManagement._getDrawingBufferColorSpace( colorSpace ); 19713 gl.unpackColorSpace = ColorManagement._getUnpackColorSpace(); 19714 19715 } 19716 19717} 19718 19719export { ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, ArrayCamera, BackSide, BoxGeometry, BufferAttribute, BufferGeometry, ByteType, CineonToneMapping, ClampToEdgeWrapping, Color, ColorManagement, ConstantAlphaFactor, ConstantColorFactor, CubeCamera, CubeDepthTexture, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeUVReflectionMapping, CullFaceBack, CullFaceFront, CullFaceNone, CustomBlending, CustomToneMapping, Data3DTexture, DataArrayTexture, DataTexture, DepthFormat, DepthStencilFormat, DepthTexture, DoubleSide, DstAlphaFactor, DstColorFactor, EqualCompare, EqualDepth, EquirectangularReflectionMapping, EquirectangularRefractionMapping, EventDispatcher, ExternalTexture, Float32BufferAttribute, FloatType, FrontSide, Frustum, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, HalfFloatType, IntType, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NoBlending, NoColorSpace, NoToneMapping, NormalBlending, NotEqualCompare, NotEqualDepth, ObjectSpaceNormalMap, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OrthographicCamera, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PerspectiveCamera, Plane, PlaneGeometry, R11_EAC_Format, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RG11_EAC_Format, 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, 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, RGFormat, RGIntegerFormat, RawShaderMaterial, RedFormat, RedIntegerFormat, ReinhardToneMapping, RepeatWrapping, ReverseSubtractEquation, SIGNED_R11_EAC_Format, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SIGNED_RG11_EAC_Format, SRGBColorSpace, SRGBTransfer, ShaderChunk, ShaderLib, ShaderMaterial, ShortType, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, SubtractEquation, SubtractiveBlending, TangentSpaceNormalMap, Texture, Uint16BufferAttribute, Uint32BufferAttribute, UniformsLib, UniformsUtils, UnsignedByteType, UnsignedInt101111Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLRenderTarget, WebGLRenderer, WebGLUtils, WebXRController, ZeroFactor, createCanvasElement, error, log, warn, warnOnce };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.