PageSourceSearch

https://starwarsdatabase.com/gallery/assets/vendor/three.module.js

js starwarsdatabase.com collected 2026-10-07 19:30:11 UTC 662,772 bytes, 19,719 lines download raw bytes

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.